How to refresh ListView When service has done its job? - android

I am working on an application in which I have a background task executing via service. I have a list showing some data elements in it. My Scenario is:
1- User set something to execute in bg and does not close the app and leaves it in this state.
2- Background process starts working, it completes its work and finishes. But list is still showing the task user entered. It should have been removed from the list.
This is the very functionality I want to achieve. How can I achieve that?
Remember if user performs some action like navigate to other screen etc, I have coded it to get new list for view. But if user leaves it idle after scheduling something, view does not refresh. Please help me out of this. Any help is appreciated.

call notifyDataSetChanged() on your list adapter.
notifyDataSetChanged() Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
Android. How does notifyDataSetChanged() method and ListViews work?. The accepted answer is the link has a good explanation.

I think you have to use Service with BroadcastReceiver to resolve your issue.
// Register Broadcast Receiver
IntentFilter filter = new IntentFilter(MyService.MYOWNACTIONFILTER);
registerReceiver(myReceiver, filter);
In Service you need to send
Intent intent = new Intent();
// Bundle the counter value with Intent
intent.putExtra("key", data);
sendBroadcast(intent); // finally broadcast
after your background operation done.
And finally
in your service calling Activity
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
// do your operation and refresh the list
}
}
Hope this will work.

Related

Android update Activity from a Service

I'm so lost with all that workflow of notifications and services in Android. My sceneario is this:
I have an Android application that communicate to a MySQL database through a web-service using JSON-RPC. The data retrieved from the service will be displayed in the application.
The data will get updated over time, so the application needs to listen for changes of this and, if a change occur, show a notification and update the data displayed in the app.
To listen for changes I will need to run an "infinite"(until the app is destroyed or maybe until the app destroys it) thread that from time to time will call a method on th web-service which will return the changes since the last check.
UPDATE: Ok, I have been trying using Service and IntentService, but non of them fits my needs: a Service execute in the Main Thread, so If I perform an infinite loop there my app will freeze, IntentService has it's own worker thread but there is no comunication with the App, and I need it, or at least I need a way to know if the app is in foreground (in this case the notification will not popup but the data will be passed and updated) or in background (int this case the notification will pop up and on click it will direct the user to the app with the updated data)
#1 You can fire a broadcast message from your Service and define a Broadcast receiver in your Activity to receive this broadcast.
SEND BROADCAST-from Service
Intent i = new Intent("ALERT_CHANGE");
i.putExtra("DATA","News");
sendBroadcast(i);
RECEIVE BROADCAST-in Activity
registerReceiver(uiUpdated, new IntentFilter("ALERT_CHANGE"));
private BroadcastReceiver uiUpdated= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent)
{
String DATA = i.getStringExtra("Data");
txt.settext(DATA);
}
};
Ok, after a lot of testing and thanks to the info given here I finally found a way to handle with the issue, so I will share it here:
On the IntentService I have a public static AtomicBoolean to control the end of the loop and be able to stop the service.
Then to determine if the Activity is in foreground or not I use the method suggested here https://stackoverflow.com/a/5504711/3107765
With the difference that I use the static modifier there, so I can check it from the service.
if the activity is in foreground I send a broadcast as it was suggested here by Eu. Dr. otherwise I use a notification that once clicked will let the user to the activity.

Downloading data using IntentService - Lifecycle changes

Tl;dr How to know when an IntentService has finished downloading upon returning to the Activity which listens to its result using a BroadcastReceiver?
I'm moving to implementing data downloading to IntentServices, and notifying when the task has finished using BroadcastReceivers.
I generally start the service in my Activity:
IntentFilter intentFilter = DownloadDataService.startDownloadData(this);
getLocalBroadcastManager().registerReceiver(mBroadcastReceiver, intentFilter);
The part that starts the Service:
/**
* Starts the service and returns an IntentFilter to subscribe a BroadcastReceiver on.
* When the task has finished, a broadcast for returned IntentFilter is sent,
* containing downloaded data.
*/
public static IntentFilter startDownloadData(final Context context) {
Intent intent = new Intent(context, DownloadDataService.class);
intent.setAction(ACTION_DOWNLOAD_DATA);
context.startService(intent);
return new IntentFilter(ACTION_DOWNLOAD_DATA);
}
And of course, onHandleIntent(Intent) (simplified):
#Override
protected void onHandleIntent(final Intent intent){
Data data = downloadData();
Intent intent = new Intent(ACTION_DOWNLOAD_DATA);
intent.putExtra(DATA, data);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
This all works well, and I can keep states in my Activity to know for example after an orientation change whether I was waiting for a download data result:
#Override
public void onResume(){
super.onResume();
if (mState == State.DOWNLOADING) {
Log.v(TAG, "Registering receiver for existing download data");
IntentFilter intentFilter = DownloadDataService.getIntentFilter();
getLocalBroadcastManager().registerReceiver(mBroadcastReceiver, intentFilter);
}
}
Great, now I can also handle orientation changes. Only one problem left:
Activity starts the DownloadDataService
User moves away from the Activity
DownloadDataService broadcasts its done message (which is not received by the Activity due to unregisterReceiver in onStop())
User moves back into the Activity
Activity still thinks it's waiting for the DownloadDataService, and does nothing.
How can I compensate for this?
Note that I do not have any persistence like databases for storing the downloaded data. The Activity retrieves the data from the broadcasted Intent.
Note #2: There is this answer to the question of how to know whether a Service is running. Although this might work, it is explicitly stated that that method is for debugging or implementing service management type user interfaces.
use sendStickyBroadcast to send a sticky broadcast. This broadcast is held by the system.
I wasn't really convinced by using SharedPreferences, static variables and other 'hacky' solutions.
I did find however that you can supply a ResultReceiver - which is parcelable - which you can use to notify your task is finished. It receives a Handler to specify the thread the result is handled on.
The advantage of this, is that you can save the ResultReceiver during onSaveInstanceState. Using some clever tricks you can certainly make this work. I have created an experimental library which facilitates this tactic: https://github.com/nhaarman/Ergo

Refreshing activity on receiving gcm push notification

Update: GCM is deprecated, use FCM
How to refresh activity on receiving gcm push notification if my app is open. I have an activity which contains listview filled with data from the server. I want to refresh my activity (here adding one more item to listview) , if I receive gcm push notification(which also contains some data).
One alternative is to add timer that periodically do server requests and update the list adapter data but I don't want these because it will take much resources.
Do I need to add broadcast receiver which will trigger on receiving gcm push which further request for newer server data and update my activity UI?
Dear commentors, please read the question carefully, I only need to refresh the list (if app is open and that particular activity is open) else no need for same.
Took me a few hours to figure it out. Posting here in case anyone anyone else has the same problem.
The idea is that you have to register your activity as a broadcast receiver. The easiest way to do this is like so:
//register your activity onResume()
#Override
public void onResume() {
super.onResume();
context.registerReceiver(mMessageReceiver, new IntentFilter("unique_name"));
}
//Must unregister onPause()
#Override
protected void onPause() {
super.onPause();
context.unregisterReceiver(mMessageReceiver);
}
//This is the handler that will manager to process the broadcast intent
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
//do other stuff here
}
};
The above code goes in the activity that you want to 'listen' for events.
Now, how do we send data to this 'listener'? Go to your push notification handler(or from where you want to update your activity) and when you receive a notification call this function:
// This function will create an intent. This intent must take as parameter the "unique_name" that you registered your activity with
static void updateMyActivity(Context context, String message) {
Intent intent = new Intent("unique_name");
//put whatever data you want to send, if any
intent.putExtra("message", message);
//send broadcast
context.sendBroadcast(intent);
}
When you call the above function, your activity should receive it.
Note: Your activity must be running/open to receive the broadcast intent
Note2: I switched to a library called 'otto'. It does actually the same thing but easier, 'broadcasts events' thoughout the app. Here's a link http://square.github.io/otto/
I'm assuming your GCMBroadcastReceiver is in it's own .java file?
As far as refreshing an activity, I would also like to know the answer to that question.
But for knowing if a particular activity is active or not, meaning on screen just add a boolean (call it something like "active") and set it to true in your activity's onResume() event, and to false in the onPause() event:
protected void onResume()
{
super.onResume();
active = true;;
}
protected void onPause()
{
super.onPause();
active = false;
}
Your active variable would be a boolean which is global or static. This way you know if a particular activity is in "front".
Hope that helps a bit.
The accept answer is indeed correct for the "Refreshing activity on receiving gcm push notification" (I've upvoted it too). But if you only want to update a ListView that's being displayed you don't need a broadcast receiver.
Your GCM listener service can update the database using a ContentProvider rather than inserting a direct sql query.
Then you can rely on the notifyChange method on the ContentResolver to do the trick.
Notify registered observers that a row was updated. To register, call
registerContentObserver(). By default, CursorAdapter objects will get
this notification. If syncToNetwork is true, this will attempt to
schedule a local sync using the sync adapter that's registered for the
authority of the provided uri. No account will be passed to the sync
adapter, so all matching accounts will be synchronized.
If your app is already running then try to override the onNewIntent method
Seems there is an easier way. In the OnMessageReceived method of the GCM Listener, you can just do the update from there instead of sending the notification. You can use the same code you would have used if processing the notification. If you're doing StartActivity from the listener, you have to use the ActivityFlags.NewTask flag.
To sum it up in single sentence:
If you want to refresh activity, broadcast your custom event when notification arrives and register your activity as broadcast receiver of that event
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

How can Android service update the UI of the activity that started it?

I'm new to Android programming, so I'm facing some general problems about choosing the best way to design my app.
What I want to do is basically a media player. I want the media player to run on a service because I want it to play also when the activity is not displayed.
My question is, how can I update the UI on my activity depending on the service working flow (for example, the song changes and I want its name to be displayed)?
I guess I could use a Local Broadcast Manager in order to send intents from my service to my activity and invoke UI updates (does it seem right?)
BUT... I will want my service to do some stuff while playing music (like querying/updating the DB).
For this reason I was thinking on running the service on a different process (or thread?).
SO.. I guess, running service on a different process, I won't be able to use local broadcast manager (is this right?).
I hope I explained what are my doubts... anyone can help?
thanks a lot!
Use an async task in your service to handle the work you need done in the background. When you need to update the UI use the progressUpdate method of async task to send a broadcast back to any interested activities.
Pseudo example.
Activity
onCreate -> startService and create new broadcastReceiver. Make sure to override the onReceive method and test for the specific intent.
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(yourActionType)) {
//do work here
}
}
};
onResume -> register as a broadcast receiver
IntentFilter filter = new IntentFilter();
filter.addAction(yourActionType);
mLocalBroadcastManager.registerReceiver(broadcastReceiver, filter);
Service
onCreate -> create broadcast manager.
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
onStartCommand -> create and execute a new async task if necessary. (onStart could be called multiple times)
Async Task
doInBackground -> Start whatever background task you need. In this case playing music.
Make periodic calls to publishProgress
onProgressUpdate -> sendBroadcast indicating updated status
Intent broadcastIntent = new Intent(yourActionType);
broadcastIntent.putExtra(whateverExtraData you need to pass back);
mLocalBroadcastManager.sendBroadcast(broadcastIntent);
onPostExecute -> sendBroadcast indicating task ended

How can my service change values of variables and UI textfields of my activities?

I have an application that get/send data from/to a remote DB on internet.
I need to get my application working in background mode, then i supose that i have to put all the send/get remote data in a service.....
but.... How can this service change values of variables and UI textfields of my activities?
i can't find any information about this, all the tutorials i am finding are of simple services that doesn't do something like that
can someone explain me how to do it please?
Use a BroadcastReceiver
In your Activity place the following code:
private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
#Override
public void onReceive(Context ctxt, Intent i) {
// do stuff to the UI
}
};
Register the receiver in your onResume():
registerReceiver(onBroadcast, new IntentFilter("mymessage"));
Be sure to unregister in onPause():
unregisterReceiver(onBroadcast);
In your Service, you can post the message to the Application, which will be heard by your Activity:
getApplicationContext().sendBroadcast(new Intent("mymessage"));
If you need to, you can add data to the Intent's bundle to pass to your Activity as well.
my suggestion to you is, create a handler for the UI part which updates the text field or UI components.
Secondly, have notifications from the service to the activity by way of interface class.

Categories

Resources