Notify Activity in Android to refresh when data is updated - android

I have a background Service which updates the database in an Android App.
In the App this data is displayed, but I am having trouble finding a good way to trigger a refresh of the data.
Initially I just refreshed each time a view resumed, but that doesn't work obviously if the data is updated while the view is shown.
On iOS I use notifications, which I register in the view, and is triggered by the update process when completed. Is there a way to do something similar in Android to trigger an update on the UI thread from a background thread?

BroadcastReciever in your Activity is the best way to update Activity from the Service.
Activity:
BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
}
After that, all you need is to register some action for it in Activity:
public final static String BROADCAST_ACTION = "com.example.action";
IntentFilter intFilt = new IntentFilter(BROADCAST_ACTION);
registerReceiver(br, intFilt);
In your service you should build an intent and call sendBroadcast.
Service:
Intent intent = new Intent(MainActivity.BROADCAST_ACTION);
sendBroadcast(intent);

There's no need to use a BroadCastReceiver if you update your database and you're using a ContentProvider to saving your data to the db then whenever data change on the ContentProvider it should notify that data has changed and in your on your activity you use a CursorLoader then the Loader is notified and UI updated, this is very easy to do and has the advantage that a CursorLoader will run the thread on background see more here and here

Related

Android Activity communication with IntentService

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" />

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.

How to let Activity know that cyclic Service has finished its task once?

I have some problems working with Android Services. I already have a Service which downloads a file from a server. (The Service checks cyclic for new data) Aftwerwards it parses the file and adds values to an ArrayList wich will be saved to SharedPreferences.
In my Activity there are two methods. One will display the values from the ArrayList/SharedPreferences in UI and the second method sets a Notification if needed.
But how do I now when my Service completed its task so the two methods can be started?
Register a BroadcastReceiver in your Activity something like:
myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do my stuff
}
};
registerReceiver(myReceiver , new IntentFilter("com.myapp.DOWNLOADCOMPLETE"));
Then in your service send the broadcast:
Intent i = new Intent("com.myapp.DOWNLOADCOMPLETE");
sendBroadcast(i);
You can also putExtras on your intent if you need to pass some values:
Documentation BroadcastReceiver

send broadcast with combination of localbroadcastmanager sendorderedbroadcast

I'm wanting to implement what CommonsWare describes on this blog post: http://commonsware.com/blog/2010/08/11/activity-notification-ordered-broadcast.html. The post makes sense, and I was able to browse the example source here: https://github.com/commonsguy/cw-advandroid/tree/master/Broadcast.
What I'm curious about is if calling LocalBroadcastManager.getInstance(UnzipService.this).sendBroadcast(broadcast); inside of a service will still be picked up by a broadcast receiver of the type you define in your manifest.
In case what I'm asking isn't clear, what I'm trying to do is use the LocalBroadcastManager because the broadcasts from my service don't necessarily need to be seen system wide and I'd rather keep them private if possible, but I also want to display notifications if the user closes my app and the service is still running. Is there a way to combine both of those capabilities without sending a broadcast twice inside of the service?
(What I don't want to have to do) like:
LocalBroadcastManager.getInstance(UnzipService.this).sendBroadcast(broadcast);
sendOrderedBroadcast(broadcast);
What I'm curious about is if calling LocalBroadcastManager.getInstance(UnzipService.this).sendBroadcast(broadcast); inside of a service will still be picked up by a broadcast receiver of the type you define in your manifest.
No. LocalBroadcastManager only works with receivers registered with the LocalBroadcastManager singleton itself. Moreover, LocalBroadcastManager does not support ordered broadcasts, last I checked.
what I'm trying to do is use the LocalBroadcastManager because the broadcasts from my service don't necessarily need to be seen system wide and I'd rather keep them private if possible
So long as you are not using an <intent-filter> on your BroadcastReceiver in the manifest, and therefore are using an explicit Intent as the broadcast itself, your broadcast will only be seen by yourself and the bit of the OS that manages broadcasts. Other apps will not be able to spy upon it.
If you only have 2 objects that might handle your broadcast (in your case an Activity and a notifications controller), you can achieve the behavior of a ordered broadcast using only the LocalBroadcastManager.
The general idea is:
Set up your Service so that it broadcasts an Intent to your Activity with a particular action when you want to display your result
In your Activity create a BroadcastReceiver that handles your Service result Intent, and register it on the LocalBroadcastManager with an IntentFilter using the action from step 1
In your Service, when the results are available, try to send the result Intent using LocalBroadcastManager.getInstance(Context).sendBroadcast(Intent) this method returns a boolean that indicates if the broadcast has been sent to at least one receiver. If this boolean is false, it means that your Activity didn't handle your broadcast and you should show a notification instead.
In your service:
public UnzipService extends IntentService {
public static final String ACTION_SHOWRESULT = UnzipService.class.getCanonicalName() + ".ACTION_SHOWRESULT";
#Override
protected void onHandleIntent(Intent intent) {
Thread.sleep(500); // Do the hard work
// Then try to notify the Activity about the results
Intent activityIntent = new Intent(this, YourActivity.class);
activityIntent.setAction(ACTION_SHOWRESULT);
activityIntent.putExtra(SOME_KEY, SOME_RESULTVALUE); // Put the result into extras
boolean broadcastEnqueued = LocalBroadcastManager.getInstance(this).sendBroadcast(activityIntent);
if (!broadcastEnqueued) { // Fallback to notification!
PendingIntent pendingIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), activityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE))
.notify(SOME_ID, new NotificationCompat.Builder(this)
.setContentIntent(pendingIntent)
.setTicker("results available")
.setContentText("results")
.build());
}
}
}
In your Activity:
public YourActivity extends Activity {
private BroadcastReceiver resultReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
processResult(intent); // Results Intent received through local broadcast
}
}
private IntentFilter resultFilter = new IntentFilter(UnzipService.ACTION_SHOWRESULT);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate();
Intent intent = getIntent();
if (UnzipService.ACTION_SHOWRESULT.equals(intent.getAction())) {
// The Activity has been launched with a tap on the notification
processResult(intent); // Results Intent contained in the notification PendingIntent
}
}
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this)
.registerReceiver(resultReceiver, resultFilter);
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(resultReceiver);
super.onPause();
}
private void processResult(Intent intent) {
// Show the results from Intent extras
}
}
This should be a complete working example.
I hope this helps who is trying to implement ordered broadcasts with LocalBroadcastManager from support library!
I understand you want to achieve the following:
"I have an event that occurs in the background. I want to update my activity, if the activity is on the screen. Otherwise, I want to raise a Notification." (#TheCommonsBlog)
You can achieve this behaviour by implementing a ResultReceiver.
Examples Restful API service and
http://itekblog.com/background-processing-with-intentservice-class/
What you basically do is instance a ResultReceiver in your Activity and pass it to the Service like a Parcelable parameter through an intent. Then, each time your service whats to update the UI, the service verifies the ResultReceiver object for NULL. If not NULL, you update the Ui via the onReceiveResult interface. Else, you raise a notification. When your activity dismisses, make sure you set the ResultReceiver on the Service to NULL.
Hope it helps.
PS: IMO, broadcasts are too much work and hard to control.
Use LocalBroadcastManager and broadcasts become easy to use.
I am not in favor of updating an Activity if an event occurs in the background. The user might already be doing something else in the Activity. Seems to me that a Notification is sufficient; it's always visible and remains until the user dismisses it. Gmail and Gcal work like this; Gmail doesn't update the current screen if a new mail comes in. If you want to know how to handle the task flow for handling a notification when the user is already in the app, see the Notifications API guide and also the [Notifying The User2 training class.

Android: Refresh Activity

I have a problem !
I have 3 Activities, DB, and WebServer. Let say that every 20 min server clean my DB and fill it up with new Data. Every Activity use data from DB. How to refresh active activity automaticaly when new refresh of DB was done. Thanks.
I'd recommend sending a Broadcast each time the DB is updated and registering broadcastreceivers in each activity that needs to be informed of the update.
EDIT example:
In your DB-class, send this broadcast:
Intent intent = new Intent("my.db.updated");
context.sendBroadcast(intent);
In the Activities where you need to be informed of DB-changes:
public void onCreate(...) {
...
BroadcastReceiver receiver = new BroadcastReciever() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction.equals("my.db.updated") {
// Do something
}
}
};
registerReceiver(receiver, new IntentFilter("my.db.updated"));
}
I don't think you can push the new data. Take a look at timers and divide your activity like this onCreate -> init -> getData
and then put getData(); within a timer
Good luck

Categories

Resources