Asaf Nevo
Asaf Nevo

Reputation: 11678

Android ListView notifyDataSetChanged() from Service

I have a background service which receive messages from a server and with those message it updates inner properties of objects which are shown in a ListView.

I always uses the runOnUiThread method to run the listArrayAdapter.notifyOnDataSetChanged() command.

From some reason sometimes the ListView is refreshed and it does show me the property update and sometimes it doesn't..

For testing i've added a "refresh" Button to my ListView and when it pressed the listArrayAdapter.notifyOnDataSetChanged() is executed.

Every click on the button the view is refreshed perfectly..

I can't really understand why when trying to refresh from the service it doesn't always work but i think i maybe not always runs on the UIThread...

I'm really hopeless and will glad to get help..

My Code

ServerConnectionManager.java - extends Service

//example of a command executed when a specific message received from the server:
//app is the Application variable
    public void unFriend(int userId)
    {
        serverResponseManager.onUnFriend(app.getApplicationFriend(userId),false);
    }

ServerResponseManager.java - a class that handle all application responses to server messages:

    public void onUnFriend(FacebookUser facebookUser, boolean isYouRemovedClient) {                 

         //this is the property which will effect the ListView view when calling the  
         //arrayListAdataper.notifyOnDataSetChanged();
        facebookUser.setApplicationFriend(false);        
        app.getApplicationFriends().remove(facebookUser);
        app.getDatabaseManager().deleteApplicationFriend(facebookUser.getId());         

         //if the application is currently running in the UI (not on the background) it will run a method inside the BaseActivity
        if (app.isApplicationInForeground())
        {           
            app.getCurrentActivity().onUnFriend(facebookUser);
            if (isYouRemovedClient)
                app.showToast(facebookUser.getName() + " has removed from your friends", true);
            else
                app.showToast(facebookUser.getName() + " has removed you from friends", true);
        }
    }

BaseActivity.java - an Activity which set all default configuration for all Activities which extends it

//in this exemple the BaseActivity method does nothing but the ListViewActivity.java method override it
public void onUnFriend(FacebookUser facebookUser)
{                   

}

ListViewActivity.java - extends BaseActivity and have a ListView in it which should reflect the change in the FacebookUser object property which being made in public void onUnFriend(FacebookUser facebookUser, boolean isYouRemovedClient) in ServerResponseManager.

@Override
public void onUnFriend(FacebookUser facebookUser)
{       
    updateView();
}

private void updateView()
{
    runOnUiThread(updateViewRunnable());
}

private Runnable updateViewRunnable()
{
    Runnable run = new Runnable() {

        @Override
        public void run() {             
            listArrayAdapter.notifyDataSetChanged();
        }
    };
    return run;
}

Upvotes: 3

Views: 4900

Answers (5)

Mayank Saini
Mayank Saini

Reputation: 3017

Instead use

notifyDataSetChanged on onDestroy of service.

the list view will get refreshed

Upvotes: 1

Kitesurfer
Kitesurfer

Reputation: 3561

You could use a Cursor in your ListView to display your Data. The Service writes/updates the Data in your ContentProvider. At the End of your Database Transaction you simple use:

getContext().getContentResolver().notifyChange(PROVIDER_URI,null);

and your ListView gets updated automaticly.

Upvotes: 1

Markus Junginger
Markus Junginger

Reputation: 7075

A Service should usually independent from UI concerns. A great way to decouple services and UI related stuff is the event bus pattern. For Android, check out https://github.com/greenrobot/EventBus.

In the ServerConnectionManager, you could post an event:

EventBus.getDefault().post(new UnfriendEvent(userId));

Now register your activity to the event bus, and the event will be delivered to the activity by calling the onEvent method:

public void onEventMainThread(UnfriendEvent event) {...}

Like this, you decouple your components leading to a neat and clean software design, which is very flexible to changes.

Upvotes: 1

anz
anz

Reputation: 1327

You can use this tutorial for proper architecture of your code

developing an app with a background service

It shows how to receive notifications from the service and update the UI.

runOnUiThread is mostly used before AsyncTask calls are made. I think you should use a handler instead (it updates the UI and allows the thread to run). Try using the handler and see what happens

Upvotes: 0

pawelzieba
pawelzieba

Reputation: 16082

Don't mix business logic. It looks so complicated that is hard to read.

  1. In your service, broadcast an intent with information about update.
  2. In Activity where ListView is, create and register BroadcastReceiver with IntentFilter for your update events.
  3. In onReceive method of your BroadcastReceiver handle update events, for example update list.

Upvotes: 9

Related Questions