Android ListView notifyDataSetChanged() from Service - android

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;
}

Don't mix business logic. It looks so complicated that is hard to read.
In your service, broadcast an intent with information about update.
In Activity where ListView is, create and register BroadcastReceiver with IntentFilter for your update events.
In onReceive method of your BroadcastReceiver handle update events, for example update list.

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.

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.

Instead use
notifyDataSetChanged on onDestroy of service.
the list view will get refreshed

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

Related

Can push notification execute code in parallel with UI thread or not?

AsFirebaseMessagingService does not use the Main Thread, I am just wondering as all my code in all of my activities or fragments run in UI thread(Main Thread). Now suppose my activity's onCreate method is executing and then I receive the push notification. Will these two blocks of code run in parallel, or will the push notification code wait in the queue until onCreate() method OR Activity's last life cycle method gets executed?
Edit- As you are saying code will run parallelly then suppose I have a variable in App.java
public class App extends Application {
int ctr = 100;
}
StatusActivity.java
public class StatusActivity extends BaseActivity {
public void onCreate() {
fun();
}
public void fun() {
int d = App.ctr - 1;//Step 1 Here d = 99
int m = App.ctr - 1; // Step 3 Here m = 98
}
}
FcmListener.java
public class FcmListener extends FirebaseMessagingService {
Override
public void onMessageReceived(RemoteMessage mssg) {
App.ctr = App.ctr - 1;//STEP 2 // Now App.ctr = 99
}
}
Now as you can see in the above code there will be problems if push notif code executes in parallel with fun(). I want push_notif and fun() to run serially, where order doesn't matter but not in parallel.
As already pointed out in a parallel answer, the overriden methods of FirebaseMessagingService run in a background thread, so you should use synchronization strategies in order to access/use mutable object from different thread.
But the question I want to answer is a bit different. Let's for a moment assume, that overriden methods run on a main thread. So is there a possibility, that the order of execution will be STEP 1 then STEP 2 and then STEP 3?
Android works with a technique called MessageQueue, basically there are Messages posted on that queue, on which Looper loops and "parses/executes" them.
Now if we assume, that you are currently located on STEP 1, it means, that there was a particular Message which is currently being executed (hypothetically, let's assume that action is - perform onCreate() of this activity).
Until this message is fully executed there cannot exist another Message which might get have a chance to be executed. So if we assume, that Firebase dispatches an event on background thread but the actual overriden method is being run on main thread, then this overriden method would have chance to be executed only after current Message (activity's onCreate()) has finished. In other words, there would be posted another Message on the MessageQueue, which would perform onMessageReceived() when the Looper will give chance for this message to be executed.
So, theoretically, there is no chance that the ordering would be STEP 1 -> STEP 2 -> STEP 3.
If STEP 1 is already executed, then it will continue with STEP 3 and the STEP 2 (at some point in future, because you can't know what other Messages are already posted on MessageQueue).
See this article for more details about MessageQueue and related classes.
How about it?
class Sample {
private String message = null;
private final Object lock = new Object();
public void newMessage(String x) {
synchronized (lock) {
message = x;
}
}
public String getMessage() {
synchronized (lock) {
String temp = message;
message = null;
return temp;
}
}
}
Here is my 2 cents. You say,
Suppose my activity's onCreate method is executing and then I receive the push notification. Will these two blocks of code run parallelly or will the push notification code wait in the queue until onCreate method OR Activity's last life cycle method gets executed?
From the official documentation of FirebaseMessagingService:
Extending this class is required to be able to handle downstream messages. It also provides functionality to automatically display notifications, and has methods that are invoked to give the status of upstream messages. Override base class methods to handle any events required by the application. Methods are invoked on a background thread.
So its possible both methods execute at the same time. If you want to do the operations on a shared variable in your Application class, you can do thread safe operations using synchronize. See How to synchronize or lock upon variables in Java?. That will make sure only one thread is making changes at a time on that variable. If a new thread comes in, it waits for the lock to get free and then makes the changes on that variable. However this doesn't guarantee the order. It just means that one thread operates on it at time and is in FIFO order.
I suggest you a different approach, because using those global variables can lead to unexpected behavior.
If your ctr var is related to your activity, then keep it inside. If you need it on other activities consider passing it via the Intent as an extra.
Use LocalBroadcastManager to inform your activity that you received the push message
public class FcmListener extends FirebaseMessagingService {
public static final String ACTION_MESSAGE_RECEIVED = "ACTION_MESSAGE_RECEIVED"
#Override
public void onMessageReceived(RemoteMessage mssg) {
Intent intent = new Intent(ACTION_MESSAGE_RECEIVED) // put extra vars as needed
boolean delivered = LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// 'delivered' is true if there is at least someone listening to the broadcast, eg. your activity
// If your activity is not running, then 'delivered' is false so you can act accordingly
}
}
Then inside your activity
public class StatusActivity extends BaseActivity {
private BroadcastReceiver messageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(FcmListener.ACTION_MESSAGE_RECEIVED, action)) {
// do stuff with 'ctr'
}
}
};
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(FcmListener.ACTION_MESSAGE_RECEIVED);
LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, filter);
}
#Override
protected void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReceiver);
}
}

using handler for every single task(method) in android

Hello i am new to android and android thread so want to know that
How could we use more number of thread in order to perform every single task or method so that while user click on any UI component it does effect the performance ,having little knowledge of how the handler thread and asynctask work.But how can we run every method inside the asynctask so to do the operation and mean while user can do the other operation also.
In the application
i have voice recording from mic.
next showing progress bar.
next showing gallery with some image and with that setting effect to the picture.
The recommended way is to use AsyncTasks for long running tasks. So, not everything needs to be run with AsyncTasks, as you can get a performance hit due to the context switching.
As for how AsyncTasks work, read the documentation.
Use an AsyncTask and make sure to implement these as needed. You mention the idea of doing something in the background while a user is doing something so I'm guessing you'll want to alter the UI.
Take a look at these links for an more details from Android. They cover Runnable, AsyncTask and Handler
Overview of them all http://developer.android.com/guide/components/processes-and-threads.html
AsyncTask example http://developer.android.com/reference/android/os/AsyncTask.html
Old but relevant, Painless Threading http://android-developers.blogspot.com/2009/05/painless-threading.html
Another, more complex example http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
I don't generally paste full examples in here but I had a lot of trouble finding an example I was happy with for a long time and to help you and others, here is my preferred method. I generally use an AsyncTask with a callback to the Activity that started the task.
In this example, I'm pretending that a user has triggered onClick(...) such as with a button, but could be anything that triggers a call into the Activity.
// Within your Activity, call a custom AsyncTask such as MyTask
public class MyActivity extends Activity implements View.OnClickListener, MyTask.OnTaskComplete {
//...
public void onClick(View v) {
// For example, thet user clicked a button
// get data via your task
// using `this` will tell the MyTask object to use this Activty
// for the listener
MyTask task = new MyTask(this);
task.execute(); // data returned in callback below
}
public void onTaskComplete(MyObject obj) {
// After the AsyncTask completes, it calls this callback.
// use your data here
mTextBox.setText(obj.getName);
}
}
Getting the data out of a task can be done many ways, but I prefer an interface such as OnTaskComplete that is implemented above and triggered below.
The main idea here is that I often want to keep away from inner classes as they become more complex. Mostly a personal preference, but it allows me to separate reusable tasks outside of one class.
public class MyTask extends AsyncTask<Void, Void, MyObject> {
public static interface OnTaskComplete {
public abstract void onTaskComplete(MyObject obj);
}
static final String TAG = "MyTask";
private OnTaskComplete mListener;
public MyTask(OnTaskComplete listener) {
Log.d(TAG, "new MyTask");
if (listener == null)
throw new NullPointerException("Listener may not be null");
this.mListener = listener;
}
#Override
protected MyObject doInBackground(Void... unused) {
Log.d(TAG, "doInBackground");
// do background tasks
MyObbject obj = new MyObject();
// Do long running tasks here to not block the UI
obj.populateData();
return
}
#Override
protected void onPostExecute(MyObject obj) {
Log.d(TAG, "onPostExecute");
this.mListener.onTaskComplete(obj);
}
}

Android Service communcation

I'm writing an application which run a background Service which communicate with a remote server.
when the server sends me a new message, i need to update an object which is represent in the UI and then to update the UI View to represent the new state of the object (for example if the object's background propery is true - set the background of the View to green and if false set the background of the view to red).
I'm using a list view to show all an ArrayList of all those objects throw an ArrayAdapter.
I have an Application object (named app) for static reference and i have there a CurrentActivity property which store the current activity running (or null if the UI is closed).
i'm using this code to update the UI:
in my Service:
onNewMessage(boolean backgruond)
{
if (app.getCurrentActivity != null)
app.getCurrentActivity.onNewMessage(background);
}
in my Activity:
onNewMessage(boolean background)
{
object.setBackground(bacground);
Log.d("Background", String.valueof(background));
runOnUiThread(new Runnable() {
#Override
public void run()
{
arrayAdapter.notifyDataSetChanged();
}
});
}
and although the Log returns the right background state, the view isn't refreshing with the notifyDataSetChanged();
i've tried to send message to Activity throw BroadcastRecevier but it much more complicated because i have lots of messages coming from the server and i will have to register many receivers.
And besides - i don't understand why would the recevier work and this mechanism wont..
example of working method which updates the ListView:
ListViewActivity - inheritance from BaseActivity:
#Override
public void onUnFriend(FacebookUser facebookUser, boolean isYouRemovedClient)
{
super.onUnFriend(facebookUser, isYouRemovedClient);
updateView();
}
BaseActivity (the super class which extends Activity):
public void onUnFriend(FacebookUser facebookUser, boolean isYouRemovedClient)
{
facebookUser.setApplicationFriend(false);
app.getApplicationFriends().remove(facebookUser);
app.getDatabaseManager().deleteApplicationFriend(facebookUser.getId());
if (isYouRemovedClient)
app.showToast(facebookUser.getName() + " has removed from your friends", true);
else
app.showToast(facebookUser.getName() + " has removed you from friends", true);
}
this one works and does change the background color in the ListView.
not working example
ListViewActivity:
#Override
public void onFriendRequestAccepted(FacebookUser facebookUser, boolean showDialog) {
super.onFriendRequestAccepted(facebookUser, showDialog);
updateView();
}
BaseActivity:
public void onFriendRequestAccepted(FacebookUser facebookUser, boolean showDialog)
{
facebookUser.setApplicationFriend(true);
app.getApplicationFriends().add(facebookUser);
app.getDatabaseManager().addApplicationFriend(facebookUser);
if (showDialog)
app.showNewEventActivity(facebookUser, EventDialogManager.EVENT_FRIEND_ACCEPTED);
}
no update is made... i can't really understand why..
i have there a CurrentActivity property which store the current activity running (or null if the UI is closed)
I do not recommend this practice. It relies upon you consistently and reliably updating that Application data member, and it increases the coupling between your service and your UI.
and although the Log returns the right background state, the view isn't refreshing with the notifyDataSetChanged();
It would appear that you did not change the data in the adapter. Certainly, there is no evidence in the code that you have here that you updated the data in the adapter.
BTW, neither of the code snippets you have shown here are likely to compile (first is not valid Java, second has a typo).
i have lots of messages coming from the server and i will have to register many receivers
No, you will have to register one receiver, and in onReceive(), use an if statement (or perhaps a switch, if you prefer) to distinguish one message from another.
In addition to what CommonsWare said, I assume that object in the first line of your onNewMessage is the view. setBackround accepts an int parameter, not a boolean.
Use 0xFF00FF00 for green and 0xFFFF0000 for red.
By the way, it's a very bad practice to keep static references of Context objects and it's derived classes (Application and Activity both derive from Context, and keeping a static reference of them may lead to serious memory leaks. Read more here.)
Use a BroadcastReceiver instead. They are much more simple comparing to how you described them - you only need one.

How to access SQLite database from UI thread if I'm inserting data in AsyncTask thread?

I have a class in my Android app, called Main.java, to validate a user login (user name + password) against the data in my server. At first, I succeeded; I used an AsyncTask thread to do it plus a library which handles the Http connection, call HttpPostAux.java (in fact, I found the library's code here in this forum). In the onPostExecute method of AsyncTask, I was creating and starting a new activity instead of modifying the current one and it worked.
But now I want to do things different. I want to save the validated data (user name + password) into a SQLite table in the AsyncTask thread and then in the UI thread, recover that data and use it to open the mentioned activity. The insertion occurs but when I'm trying to access the database from UI thread: it says that the table is empty. So I looked in the logcat and I found that UI thread executes before AsyncTask thread.
So my question is how to insert data in the AsyncTask thread and then recover it inside UI thread? Can anybody help here? I'm kind of lost!
I will appreciate a code example! Thanks in advance!
Greetings from Venezuela!
UI thread is your applications main thread. When you create an AsyncTask, your long time-taking task will be executed(inside doInBackground function) on a separate thread. When doInBackground completes, onPostExecute() will be called from the UI thread. So you simply need to execute your UI thread task(="recover that data and use it to open the mentioned activity") from inside onPostExecute().
I think the way you did it before is correct. I would recommend to make a sort of SplashScreen activity which checks if the user has been logged in before, i.e. if there is a username/password in the database. If this is the case, use this data to login the user and then proceed to your main activity. If the user hasn't been logged in before, promp them with a login screen, store this data for future use and continue to your main activity.
You can implement a BroadcastReciever in your UIThread that listens to Intents sent from your AsyncTask when the insert to the database is done.
fire from AsyncTask:
Intent intent = new Intent("DATABASE_INSERTION_DONE");
context.sendBroadcast(intent );
register in UiThread:
IntentFilter intentFilter = new IntentFilter("DATABASE_INSERTION_DONE");
registerReceiver(myIntentsReceiver, intentFilter);
class:
class MyIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if ("DATABASE_INSERTION_DONE".equals(intent.getAction())) {
//do something
}
}
}
You have to keep in mind that once you start an AsyncTask, it will run on another thread and your UI thread will keep moving forward. For example:
x="foo";
new SampleAsyncTask().execute();
txtView.setText(x);
Class SampleAsyncTask extends AsyncTask<...>{
.....
public Void doInBackground(...){
//LOTS OF CALCULATIONS
x="bar";
}
}
Your txtView will most definitely show "foo" rather than "bar". To make sure that your AsyncTask is finished there are lots of options. You can call a method to start the rest of your operations in PostExecute of your AsyncTask. You can also use intents and a broadcastreceiver like Jelgh said. But my favorite is using a simple callback:
public class LoginActivity extends Activity implement SampleAsyncTask.asyncCallback{
#Override
protected void onCreate(Bundle savedInstanceState){
x="foo";
new SampleAsyncTask().execute();
Class SampleAsyncTask extends AsyncTask<...>{
asyncCallback mCallback;
public SampleAsyncTask(Context c){
mCallback; = (asyncCallback) c
}
public interface asyncCallback{
void servedMyPurposeYouCanGoOn();
}
public Void doInBackground(...){
//LOTS OF CALCULATIONS
x="bar";
mCallback.servedMyPurposeYouCanGoOn;
//REST OF THE WORK
}
}
}
#Override
public void servedMyPurposeYouCanGoOn(){
runOnUIThread(
//rest of the work
)
}
}

Callback to activity from other class

I have Activity class, Controller class (normal java class use to control number of activity) and BusinessEngine class (normal java class use to process data).
When I need to do some calculation from activity, Activity will call Controller and Controller will call BusinessEngine to do the calculation. When BusinessEngine done with the calculation, it will pass the value back to Controller and finally let the activity know the calculation is complete.
The problem is how I callback Activity from Controller class? Or pass any data to Activity and notify it the data has been change?
Any "long" running tasks must be performed in a background thread. I'm not sure if your currently doing this for your task, so just in case your not, there are a couple of ways to do this. The first is to simply use a AsyncTask, the second is to create your own instance of AbstractExecutorService (AsyncTask uses ThreadPoolExecutor) and use that to post Runnable or Callables to. The later way may save you a lot of re factoring depending on your code base.
Assuming you're now running the task in a background thread, it's necessary to perform your UI updates on the UI thread. There are again a couple of ways to do this. One method is to post a runnable to the method Activity#runOnUiThread, the second is to use a Handler which has previously been created on the UI thread (which Activity#runOnUiThread does behind the scenes).
So, assume your Activity has a method #postResults(final Object o), and your controller has the method #doSomething(final Activity activity).
Your activity would look something like this.
public class MyActivity extends Activity {
Controller controller = ....
ExecutorService service = Executors.newFixedThreadPool(10);
private void startTask() {
Runnable r = new Runnable() {
public void run() {
c.doSomething(MyActivity.this);
}
}
service.submit(r);
}
public void postResults(final Object o) {
Runnable r = new Runnable() {
public void run() {
// Update your UI here
}
}
runOnUiThread(r)
}
}
and your controller
public class Controller {
public void doSomething(final Activity activity) {
// Perform some long running task here
activity.postResults(someObject);
}
}
Obviously this example could be tidied up (for example passing a interface to doSomething rather than the Activity), but hopefully it should be enough to understand what you need to do :)
Why are you looking for the controller to call you Activity? Normally, your Activity must call the controller via its methods and directly get results from them:
// Code in your Activity
result = controller.doSomething(args);
try using a android AsyncTask, if your method takes a long time to process. example
Add your classes to an Async task or if you're calling the classes and passing them from one class to the other.I would say to use static class. And provide some code so we can know how you are passing your data.
If not use general methods to call the superclass or the subclass.
My answer is a bit abstract as information is less.

Categories

Resources