Diffutils block UI when updating 10 to 15 items in recyclerview - android

final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
final DiffUtil.DiffResult diffResult =
DiffUtil.calculateDiff(new DiffCb(oldItems, newItems));
handler.post(new Runnable() {
#Override
public void run() {
applyDiffResult(newItems, diffResult);
}
});
}
}).start();
}
this is how I am doing calculation and updaing my list. But when I am updating 2,3 items, it works perfect. But when I am updaing item like 20, it block the UI for alomst 10 seconds.

This is because as per Handler's doc, the task runs on whatever thread the Handler is created on. In this case, it is your UI thread.
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it
You need to use HandlerThread where you assign the Handler it's own worker thread for the operation.
Do this instead when initializing your Handler :
HandlerThread thread = new HandlerThread("newthread");
thread.start();
Handler handler = new Handler(thread.getLooper());
Also, check this link for more information and best practices on using HandlerThread.

Related

Executing operations on UI thread after delay

I want to implement some operations on UI thread after a delay of a few seconds and have tried this approach -
final Handler handler1 = new Handler();
final Runnable r = new Runnable() {
public void run() {
// operations to do
}
};
runOnUiThread(new Runnable() {
#Override
public void run() {
handler1.postDelayed(r, 1000);
}
});
Here I have two runnable objects, so my question is that are the operations I'm performing here being executed in UI thread or another thread because I don't directly execute the operations in Runnable object of the UI thread. Also if this is not the right approach to execute operations in UI thread after a delay, please suggest any modifications required.
When you post a Runnable with a Handler, the Handler executes it on whatever Thread created that Handler.
Handler's default constructor new Handler() is a synonym of new Handler(Looper.myLooper()). That might mean that the Handler will execute Runnables on the main thread, but only if the instantiation happened on the main Thread.
Either way, what you're doing is redundant. The runOnUiThread() is useless. Just change the Handler's constructor:
final Handler handler1 = new Handler(Looper.getMainLooper());
handler1.postDelayed(r, 1000);

Looper Handler Example

I was trying to understand the looper and handler in android, but got stuck with the example written.
What I am trying to do is, add a looper to the thread, to make thread running continuously in run() method. Then post messages or runnables to the hanlder thread.
public class HLClass extends Thread {
Handler mHandler;
#Override
public void run() {
super.run();
Looper.prepare();
mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HLClass","In Handler, Msg = "+msg.arg1);
}
};
Looper.loop();
}
}
This is how I am trying to call handler:
HLClass hlc = new HLClass();
hlc.start();
Message m = hlc.mHandler.obtainMessage();
m.arg1 = 10;
hlc.mHandler.sendMessage(m);
Error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Message android.os.Handler.obtainMessage()' on a null object reference
Here, what really I am trying to understand that, how I can attach a handler to thread and then post message from any other thread
How can I safely post Message or Runnable to handler without error.
You can try following code for sending message.
final HLClass hlc = new HLClass();
hlc.start();
new Handler().postDelayed(new Runnable() {
public void run() {
Message m = hlc.mHandler.obtainMessage();
m.arg1 = 10;
hlc.mHandler.sendMessage(m);
}
}, 300);
A Handler is a component that can be attached to a thread and then made to perform some action on that thread via simple messages or Runnable tasks. It works in conjunction with another component, Looper, which is in charge of message processing in a particular thread.
When a Handler is created, it can get a Looper object in the constructor, which indicates which thread the handler is attached to. If you want to use a handler attached to the main thread, you need to use the looper associated with the main thread by calling Looper.getMainLooper().
In this case, to update the UI from a background thread, you can create a handler attached to the UI thread, and then post an action as a Runnable:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
// update the ui from here
}
});
This approach is a lot better than the first one, but there is an even simpler way to do this…

How can I run a specific type of task off the UI thread?

I want to run a function whenever a recyclerview binds a view. It's a really long operation, so I have to keep it off the UI thread. I know how to create a thread, but how can I use the same thread to always run the content of the onBindViewHolder method on the second thread without creating a new one every time the specific function gets executed ?
#Override
public void onBindViewHolder (final Adapter adapter, RecyclerView.ViewHolder holder, final int position) {
new Thread(new Runnable() {
#Override
public void run () {
theMethod(adapter, holder, position);
}
}).start();
}
Consider using a HandlerThread, then scheduling work against that thread with a Handler created with the HandlerThread's Looper. You will have to remember the shut down the thread at the end of the activity, of course, or it will stick around indefinitely and maybe leak objects.
For example:
HandlerThread thread = new HandlerThread("Give Me a Name");
thread.start();
Looper looper = thread.getLooper();
Handler handler = new Handler(mServiceLooper);
// use handler to post work to the thread
These lines of code are cribbed directly from IntentService, which does exactly the same thing you want, except in a service. Maybe that's even what you actually want to use!
Create new thread which can do jobs with a queue.
class YourThread extends Thread {
public List<Job> queue = new ArrayList<>();
#Override
public void run(){
while(queue.size() == 0)
wait(); // nothing to do, wait...
Job job = queue.get(queue.size() - 1); // pop queue
queue.remove(queue.size() - 1);
dosomething(job);
}
public void addJob(....){
...
queue.add(job, 0);
}
}
and onBindViewHolder
YourThread thread = new ...
thread.start()
#Override
public void onBindViewHolder (final Adapter adapter, RecyclerView.ViewHolder holder, final int position) {
thread.addJob(...);
// remember that after the job finished, the item may be recycled
}
You can achieve it by using Looper. The main purpose of Looper is this only, to keep the thread alive and waiting for new messages(Runnables).
Here's a sample code from the official documentation :
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Now, you can post new runnables (messages) to the thread using the handler. Something like this :
handler.post(new Runnable()
{
public void run() {
//This will be executed on thread using Looper.
}
});
Edit :
The method provided above is more of 'do-it-yourself'. There's a special class in android that can do this automatically for you, i.e. HandlerThread. Sample code :
HandlerThread thread = new HandlerThread("name");
thread.start();
Looper looper = thread.getLooper();
Handler handler = new Handler(looper);
Now you can post runnables to this handler.

How to use Handler / runnable?

I would like my code runs all the one minut..
Can anyone explain me how to do it?
private Handler myHandler;
private Runnable myRunnable = new Runnable() {
#Override
public void run() {
//DO WORK
Toast.makeText(getApplicationContext(), " Hello",Toast.LENGTH_SHORT).show();
myHandler.postDelayed(this,60000);
}
};
#Override
public void onCreate() {
super.onCreate();
//call function
myHandler = new Handler();
//
myHandler.postDelayed(myRunnable,60000);
Log.d(this.getClass().getName(), "onCreate");
}
watch this http://goo.gl/DRdaUi
BTW 60 second is a very long time for thread to run! If you have something that runs this long consider using android service instead of thread.
Also do you need to use handler? think again, most of the time there is no need for that. AsyncTask is android first option for multithreading and its a lot simpler. unless AsyncTask can not handle what you have in your mind don't use any other method.
A Timer is a valid solution but it will not execute on the UI thread. And your code tells me this is what you want.
The simplest way to do that would be via a handler and a repeating task:
final Handler handler = new Handler(); // ui thread handler
handler.postDelayed(new MyRunnable(handler), INETRVAL);
Where:
class MyRunnable implements Runnable {
#Override
public void run() {
// do periodical action here
// and.. repeat your task <------------
handler.postDelayed(new MyRunnable(handler), INETRVAL);
}
}

Handler-Looper implementation in Android

I have Activity with Handler (UI thread)
I start new Thread and make handler.post(new MyRunnable()) - (new work thread)
Android documentation said about post method: "Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached."
Handler attached to UI thread.
How android can run runnable in the same UI thread without new thread creation?
Is new thread will be created using Runnable from handler.post()?
Or it's only run() method will be called from Runnable subclass?
Here's a rough pseudroidcode example of how to use handlers - I hope it helps :)
class MyActivity extends Activity {
private Handler mHandler = new Handler();
private Runnable updateUI = new Runnable() {
public void run() {
//Do UI changes (or anything that requires UI thread) here
}
};
Button doSomeWorkButton = findSomeView();
public void onCreate() {
doSomeWorkButton.addClickListener(new ClickListener() {
//Someone just clicked the work button!
//This is too much work for the UI thread, so we'll start a new thread.
Thread doSomeWork = new Thread( new Runnable() {
public void run() {
//Work goes here. Werk, werk.
//...
//...
//Job done! Time to update UI...but I'm not the UI thread! :(
//So, let's alert the UI thread:
mHandler.post(updateUI);
//UI thread will eventually call the run() method of the "updateUI" object.
}
});
doSomeWork.start();
});
}
}
Handler attached to UI thread.
Correct.
How android can run runnable in the same UI thread without new thread creation?
Any thread, including the main application ("UI") thread, can call post() on Handler (or on any View, for that matter).

Categories

Resources