Reputation: 2401
I just wrote a code which adds several views, each using a handler. These are added using a for-loop. These add just correctly. Then I tried to add a button AFTER the for loop without using handler. This time the button was shown on the top of the layout i.e BEFORE the items added in for loop. This does not happen if I add the button using handler.
So, if I use the following code with a handler after the loop then the button is added on the bottom of the layout:
private void fillFeedWithData(final List<ParseObject> feedObjectList) {
LayoutInflater inflaterOfFeedItem = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = 0; i < feedObjectList.size(); i++) {
final String jokeTitle = feedObjectList.get(i).getString("content");
final View cvFeedItem = inflaterOfFeedItem.inflate(R.layout.feed_item_theme_card, null);
final TextView tvJoke = (TextView) cvFeedItem.findViewById(R.id.tvFeedJoke);
Handler h2 = new Handler();
Runnable update2 = new Runnable() {
public void run() {
tvJoke.setText(jokeTitle);
llFragmentFeedParent.addView(cvFeedItem);
// llFragmentFeedParent is acquired in OnCreate() method
}
};
h2.post(update2);
}
final Button bNext = new Button(this);
bNext.setText("Next >");
bNext.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
Handler h3 = new Handler();
Runnable update3 = new Runnable() {
public void run() {
llFragmentFeedParent.addView(bNext);
}
};
h3.post(update3);
}
If I used the following code after the loop then the button is added on the top of the layout:
Button bNext = new Button(this);
bNext.setText("Next >");
bNext.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
llFragmentFeedParent.addView(bNext);
So now my app is working as intended with the handler but I am concerned as to why this was happening. I think the handlers are mixing up the timings/sequence of execution? If I keep using the logic, is it possible that the button might, in a slow mobile phone, appear on top or even in between the items added in the loop?
Upvotes: 0
Views: 70
Reputation: 36045
I'm not sure why you'd want to do it this way, but to answer your question. Handlers post Runnables in a queue that run in order (assuming you don't use postDelayed
). They run eventually meaning that when they execute depends entirely on how many other Runnables are posted and how long it takes for those Runnables to execute.
Handlers actually share a Looper
thread that they are created on (in this case the Main UI Looper thread), so no matter how many Handler references you make, they will post in the same thread. Likewise, you can pass in a Looper
object of another thread so the Runnables will run on that thread.
In this case, when you add a button without the Handler, you're adding it to the view now before your other Handler executes. When you post in another Handler, which is also created on the UI thread, it will post the Runnable in a queue after the first one you posted. So then they effectively run sequentially.
EDIT:
Also in this case, I would ditch the Handler
mechanism entirely and just put all Views you want to add in a List
, then add them in a collection. You're posting a new Runnable every pass, which will add a new view to the layout, which will trigger a layout pass, which will trigger a draw pass. It's way better to just add them all in one go.
Upvotes: 2