Android Activity communication with IntentService - android

I need to have a two way communication between my activity and a running IntentService.
The scenario is like this: the app can schedule alarms which on run, start an IntentService which fetches some data from web and process it. There are three possible situations when IntentService finishes:
The app is in focus, which means that when the IntentService will finish, the app needs to refresh its views with the new data.
The app is closed and when opened after IntentService has finished the work, so the app will have access to processed data
The app is opened while the IntentService is running, in which case I need to have a way from the activity to ask the IntentService if its doing something in the background.
For 1. I have already implemented a BroadcastReceiver in my activity which gets registered with the LocalBroadcastManager. When IntentService finishes the work, sends a broadcast and the activity reacts. This works fine
For 2. There is nothing needed to be done
For 3. I don't know what to do. So far I've tried this:
In Activity:
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_SEND_TO_SERVICE));
In IntentService
private LocalBroadcastManager localBroadcastManager;
private BroadcastReceiver broadcastReceiverService = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BROADCAST_SEND_TO_SERVICE)) {
//does not reach this place
//Send back a broadcast to activity telling that it is working
}
}
};
#Override
protected void onHandleIntent(Intent intent) {
localBroadcastManager = LocalBroadcastManager.getInstance(context);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_SEND_TO_SERVICE);
localBroadcastManager.registerReceiver(broadcastReceiverService, intentFilter);
.... //do things
}
The problem with my implementation is that n the IntentService the BroadcastReceiver does not fire onReceive. Any suggestions or maybe a simpler way for the Activity to ask the IntentService what it is doing?
LE:
Trying to get atomicboolean.
In Service:
public static AtomicBoolean isRunning = new AtomicBoolean(false);
#Override
protected void onHandleIntent(Intent intent) {
isRunning.set(true);
// do work
// Thread.sleep(30000)
isRunning.set(false);
}
In Activity, restarting the app while service is running:
Log(MyIntentService.isRunning.get());
//this returns always false, even if the intent service is running
On AndroidManifest
<service
android:name=".services.MyIntentService"
android:exported="false" />

Related

Slow Intent Broadcasts

I'm working on an application that uses Android's DownloadManager to download files. In my AndroidManifest.xml I register a receiver to listen for downloads completing like this
<receiver android:name=".download.DownloadCompleteBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>
In the broadcast receiver's onReceive method, I launch an IntentService to perform some post-processing on the downloaded file before it's ready for use. Here's what that code looks like:
public class DownloadCompleteBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
final long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1L);
context.startService(
new Intent(context, DownloadService.class)
.putExtra("downloadId", downloadId));
} catch (Throwable t) {
Log.i("Yo", Log.getStackTraceString(t));
}
}
The DownloadService class looks something like this
public class DownloadService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
// Some processing logic
...
// Send processing complete
sendBroadcast(new Intent("com.example.package.DownloadService:PROCESSING_COMPLETE"));
}
}
This service is registered in my AndroidManifest.xml like this
<service android:name=".download.DownloadService" android:process=":Downloads"/>
Finally, I have an activity that listens for that PROCESSING_COMPLETE broadcast. That code looks like this
public class MyActivity extends AppCompatActivity {
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Update some UI
}
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(receiver, new IntentFilter("com.example.package.DownloadService:PROCESSING_COMPLETE"));
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
}
And finally, the issues:
1) I am seeing delays (as much as 20 seconds) between when the download manager completes a download and when my registered BroadcastReceiver receives the download complete notifications. Is this normal? This issue/question is not as big of a concern as the next two.
2) I am seeing delays (as much as 2 minutes) between when my BroadcastReceiver calls startService() and when DownloadService.onCreate() is called. What's going on here? Sometimes my devices will show an ANR dialog asking me to wait for the app or force close it. I know I declared the service to run in a separate process, and there's some lead time to create the process and launch the service, however I'm seeing similar delays in successive runs when the process is already created. Moving DownloadService to the default process doesn't appear to improve the load time, however I believe the best practice is to run such a service in it's own process to keep it from being terminated should the app crash.
3) I am seeing delays (as much as 2 minutes) between when the DownloadService sends the PROCESSING_COMPETE broadcast and when my activity actually receives it. This is without leaving the activity then coming back (an onPause() and onResume()cycle), though my code handles unregistering and re-registering. What's going on here? I'm testing on a Galaxy S7 running 6.0. I hardly have any apps installed/running on this device that I could image would be slowing down broadcasts. Another interesting observation is that if I send multiple broadcasts, they're all delivered at the same time after the long delay.
Thanks for the help in advance!

How to send message from BroadcastReceiver to activity or fragment

I have a receiver, it does call details saving task like storing incoming call, outgoing call etc.. all these details goes to sqlite DB. If my activity is not running, then its fine.
Sometime, when my activity is running, i get some incoming call. the receiver runs & stores data to DB. UI wont get refreshed because it never knows about change in DB.
Here i need to manually tell from receiver that, if activity is running refresh screen. How to implement this process in android.
I'm slightly confused in this part
You can use a LocalBroadcastManager to send a local broadcast to your Activity (more efficient and more secure than using a global broadcast):
Intent intent = new Intent(action);
LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(context);
mgr.sendBroadcast(intent);
http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
Your Activity would have to register a BroadcastReceiver in onStart and unregister it in onStop:
private BroadcastReceiver mBroadcastReceiver;
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do your thing
}
};
LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this);
mgr.registerReceiver(mBroadcastReceiver, new IntentFilter(action));
in onStop:
mgr.unregisterReceiver(mBroadcastReceiver)
Now that's the official Android way to do it. I most certainly prefer to use an event/message bus like Otto or EventBus (https://github.com/greenrobot/EventBus). You can use those to broadcast messages/events across different components in your app. The advantage is you don't need access to a Context (like you do when using Broadcasts), it's faster and it forces the developer to object oriented programming (since the events are always objects). Once you start using an event bus you'll never look back to local broadcasts and you'll replace many of the sometimes messy observer / listener patterns used across your app.
You can create a BroadcastReceiver inside an activity. Register it in onResume() and unregister it in onPause(). Whenever your other receiver receives a broadcast, send a broadcast to this receiver too. If the activity is running(i.e. on front), the broadcast will be received. Do whatever you want in its onReceive().
Example:
BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Do stuff
}
};
Also override methods:
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(br);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(br, new IntentFilter("intent_filter"));//Use any string for IntentFilter you like
}
You can update fragments from activiy by creating methods inside fragment and access them from Fragment object inside activity.

android services and activity lifecycle?

I am having problem with my android IntentService. When I first open the application, the service gets started by intent from the profile activity and data is fetched from this service. If I switch to other activity and then back service is still running and that is ok.
However if you press back, so that activity is finished and put in the background, the service is still working as the application is in background but If I get it back to foreground service stops. I do not know why. Bellow is my code, please help.
I have read activity life cycle couple of times and still do not get it why this is happening.
What is weird is that Service receive data one more time before it stops when MainActivity is brought back to running state. Service is not crashing.
Service
public class SomeService extends IntentService
{
public static final String extra = "someData";
public SomeService()
{
super(SomeService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent)
{
Log.e("SomeService", "starting service");
while (true)
{
SomeData data = Api.getNewSocketData();
//Broadcast data when received to update the view
Intent broadcastData = new Intent();
broadcastData.setAction(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
broadcastData.addCategory(Intent.CATEGORY_DEFAULT);
broadcastData.putExtra(extra, " ");
sendBroadcast(broadcastData);
Log.e("SomeService", "received from socket");
}
}
}
Receiver
public class dataBroadcastReceiver extends BroadcastReceiver
{
public final static String ACTION_DATA_RECEIVED = "net.bitstamp.intent.action.ACTION_SOMEDATA_RECEIVED";
#Override
public void onReceive(Context context, Intent intent)
{
Log.e("receiver", "data received");
}
}
Main Activity
#Override
public void onPause()
{
super.onPause();
unregisterReceiver(dataBroadcastReceiver);
}
#Override
public void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
dataBroadcastReceiver = new dataBroadcastReceiver();
registerReceiver(dataBroadcastReceiver, intentFilter);
Intent someService = new Intent(this, SomeService.class);
startService(someService);
}
I really need help on this. Thanks
You don't want to the up the IntentService in an infinite loop. It will block all other incoming requests. From the documentation:
All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
Your Service is likely still happily running along, it just isn't processing your new request because your old one is still being handled in the infinite loop.

Android keep BroadcastReceiver in background

I created a BroadcastReceiver and it runs only when my app shown in recent apps menu. If I remove my app from the recent apps the BroadcastReceiver will stop working.
How can I keep the BroadcastReceiver in background?
I register the BroadcastReceiver from my main activity (in OnCreate()).
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(receiver, intentFilter);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
This is not how you should register a receiver. You receiver stops working, because you construct it in onCreate, which means it will live as long as your app is alive. When the app gets destroyed, you also lose the the receiver.
If you register receiver inside an activity, you should always register it in onResume and deregister onPause, which will make it available while the activity is visible to the user. This is a use case when you want to have an active receiver while user interacts with an activity.
If you want a background receiver, you need to register it inside the AndroidManifest (with intent filter), add an IntentService and start it when you receive a broadcast in the receiver.
Here is a tutorial, you are interested in chapter 3.
If you need to be always on, start a foreground service. There is function in Service that lets you: startForeground. Then register your receiver when service is created and deregister when it's destroyed. Foreground services are quite nasty though.
Use a service with it.
Services can survive when the app dies if they have the right flag example:
public class MyService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY; //this defines this service to stay alive
}
#Override
public void onCreate() {
super.onCreate();
appStatus = APPISUP;
//This is a thread that stays alive for as long as you need
new CheckActivityStatus().execute();
//Not needed but in case you wish to lauch other apps from it
}
private class CheckActivityStatus extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
while(true) {
... //add something that breaks eventually
}
}
}
To lauch the service you have to lauch it from an activity like so:
Intent service = new Intent(getBaseContext(), MyService.class);
startService(service);
With the service the BroadcastReceiver still functions receiving whatever you want.
Note that the service sometimes stops and comes back. I haven't found out why but I'm betting on priorities of other apps that may ask the system to halt the service

Android - Sending data from an activity to a service

I've a local service that is started in my main activity. The service is responsible for network I/O. It also interacts with other activities in my application. Till, now the service was only "providing" data to activity (using callbacks and not Intents.)
Now I need to send data (custom objects) from my activities to the service. I understand one way to do it using Intents. I know it is possible to receive an Intent in the service by overriding the onStartCommand() in my service. But it's not clear to me if the onStartCommand will be invoked every time I broadcast an Intent from my sending activity. Can a Service also be BroadcastReceiver ? If yes - how ?
Thanks.
You can create a BroadcastReceiver object in the service and register it to listen to any broadcast event you want. It's something like this:
BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//handle the broadcast event here
}
};
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mScreenStateReceiver, filter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mScreenStateReceiver);
}
Regards,

Categories

Resources