How to use goAsync for broadcastReceiver?
You can find short explanation here.
Use goAsync()
if you want to handoff the processing inside of your BroadcastReceiver
's onReceive()
method to another thread. The onReceive()
method can then be finished there. The PendingResult is passed to the new thread and you have to call PendingResult.finish()
to actually inform the system that this receiver can be recycled.
For example:
final PendingResult result = goAsync();
Thread thread = new Thread() {
public void run() {
int i;
// Do processing
result.setResultCode(i);
result.finish();
}
};
thread.start();
BroadcastReceiver goAsync() returns null PendingResult
I wrote a JobIntentService
instead:
package com.example.broadcastreceiverpendingintenttest;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;
import android.util.Log;
public class MyJobIntentService extends JobIntentService {
public static final String ACTION = "and....action!";
static final int JOB_ID = 9001;
@Override
protected void onHandleWork(@NonNull Intent intent) {
// TODO check the intent action is valid, get extras etc
Log.i("tag", "performed my task");
}
}
It's declared in AndroidManifest
as follows:
<service
android:name=".MyJobIntentService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false" />
MyReceiver
then enqueues work for the Service:
package com.example.broadcastreceiverpendingintenttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.util.Log;
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent jobIntent = new Intent();
jobIntent.setAction(MyJobIntentService.ACTION);
MyJobIntentService.enqueueWork(context, MyJobIntentService.class, MyJobIntentService.JOB_ID, jobIntent);
}
}
Bit more overhead than I wanted, but it gets the job done.
android, how to unit test BroadcastReceiver which uses doAsync()
fond a way, there must be better one tho.
BroadcastReceiver.PendingResult pendingResultMock =
mock(BroadcastReceiver.PendingResult.class);
NotificationReceiver receiverSpy = spy(new NotificationReceiver());
doReturn(pendingResultMock).when(receiverSpy).goAsync();
Broadcast receiver goAsync
It changes the thread so you can do computationally heavy work without freezing the UI thread. Read the docs:
" This does not change the expectation of being relatively responsive to the broadcast (finishing it within 10s), but does allow the implementation to move work related to it over to another thread to avoid glitching the main UI thread due to disk IO."
Broadcast receiver goAsync
It changes the thread so you can do computationally heavy work without freezing the UI thread. Read the docs:
" This does not change the expectation of being relatively responsive to the broadcast (finishing it within 10s), but does allow the implementation to move work related to it over to another thread to avoid glitching the main UI thread due to disk IO."
Async Task inside BroadcastReceiver onReceive method not running?
The problem is that since you are executing the Network Request using an Async Task in the onReceive method, the onReceive method returns before the AsyncTask executes since an Async Task is Asynchronous. Therefore the process that is running the onRequest method becomes a low priority since the onReceive method has returned and the operating system will kill it before your Async Task actually executes.
Here are two solutions:
First ensure that the receiver is declared in your Android manifest, then do one of the following.
Instead of calling an Async Task to execute your network request, create a service and use the service to run the network code.
You can call the
goAsync()
method in the onReceive method to tell the system to give the receiver more time to execute its Async Task. The code for this would be something like this:@Override
public void onReceive(final Context context, final Intent intent) {
//create a pending intend that you will pass to the Async task so you can tell the system when the Async Task finished so that it can recycle.
final PendingResult pendingResult = goAsync();
AsyncTask<String, Integer, String> asyncTask = new AsyncTask<String, Integer, String>() {
@Override
protected String doInBackground(String... params) {
//put the network calling code in here
// Must call finish() so the BroadcastReceiver can be recycled.
pendingResult.finish();
return data;
}
};
asyncTask.execute();
}
The second way I believe would be simpler, so I would reccomend using that as it doesnt require you to create a whole new service.
Related Topics
How to Open Navigation Drawer with No Actionbar, Open with Just a Button
Cannot Deserialize Instance of Object Out of Start_Array Token in Spring Webservice
Android:Load Svg File from Web and Show It on Image View
Moving from One Activity to Another Activity in Android
Gradle Flavors for Android with Custom Source Sets - What Should the Gradle Files Look Like
Firebase: When Ondisconnect Event Fire
Textbox Hidden Below Keyboard in Android Webview
How to Send JSON Object to the Server from My Android App
Pass Parameter with Volley Post
How to Apply Plugin to Only One Flavor in Gradle
Android: Google Maps Location with Low Battery Usage
How to Disable Dates Before Today Date in Datepickerdialog Android