I searched for a way to update UI from another thread, and found that the available approach is to use Handler.post(Runnable) as shown in the code snippet below:
public class MyClass extends Activity {
private final Handler myHandler = new Handler();
final Runnable updateRunnable = new Runnable() {
public void run() {
// Update UI
}
};
private OnClickListener buttonListener = new OnClickListener() {
public void onClick(View v) {
new Thread(new Runnable() {
myHandler.post(updateRunnable);
}).start();
}
};
}
Instead can't we use Handler.sendMessage and do the UI updates from main UI thread in handleMessage():
public class MyClass extends Activity {
private final Handler myHandler = new Handler();
private Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what) {
// Do logic here
}
}
};
private OnClickListener buttonListener = new OnClickListener() {
public void onClick(View v) {
new Thread(new Runnable() {
myHandler.sendEmptyMessage(0);
}).start();
}
};
}
I'm sorry if this is a very basic question, however I'm quite confused with the above two approaches.
You need to use runOnUiThread. You can post a runnable which does the UI operation to main thread as follows,
public class Utils {
public static void runOnUiThread(Runnable runnable){
final Handler UIHandler = new Handler(Looper.getMainLooper());
UIHandler .post(runnable);
}
}
Utils.runOnUiThread(new Runnable() {
#Override
public void run() {
// UI updation related code.
}
});
Read more at:
android: update UI from another thread in another class
Updating UI / runOnUiThread / final variables: How to write lean code that does UI updating when called from another Thread
https://developer.android.com/training/multiple-threads/communicate-ui.html
Related
I'm trying to understand how Handler works in a pair with Looper, but i have some problem. I need to do some long operation in a back thread and then to send some result in a textView.
I get the following error after pressing a button:
Only the original thread that created a view hierarchy can touch its views.
public class MainActivity extends AppCompatActivity {
Button mButton;
TextView mTextView;
ConsumeThread mConsumeThread;
class ConsumeThread extends Thread{
public Handler mHandler;
#Override
public void run() {
Looper.prepare();
mHandler = new Handler(){
#Override
public void handleMessage(Message msg){
int arg = msg.what;
someLongOperation(arg);
}
};
Looper.loop();
}
private void someLongOperation(int arg){
// do some long operation
arg += 1000;
mTextView.setText("Operation's code is " +arg); // fatal exception
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.txt_view);
mButton = (Button) findViewById(R.id.button);
mConsumeThread = new ConsumeThread();
mConsumeThread.start();
mButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
if(mConsumeThread.mHandler != null){
Message msg = mConsumeThread.mHandler.obtainMessage(10);
mConsumeThread.mHandler.sendMessage(msg);
}
}
});
}
To get Main Thread Handler You have get Handler as follows .
Because:-
Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it
So you need to get Handler which is associated with MainThread. For that you can use one of the following:-
With Context
Handler mainHandler = new Handler(getMainLooper()){
#Override
public void handleMessage(Message msg) {
}
};
Or Directly with Looper even when do not have Context
Handler mainHandler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg) {
}
};
I assume that you are doing some long running task . So its better if you go with AsyncTask.
private void someLongOperation(int arg){
// do some long operation
arg =+ 1000;
mTextView.setText("Operation's code is " +arg); // fatal exception
}
//see here, you are in worker thread, so you can't excess UI toolkit or else exception, so if you want to do something ui related task in worker thread, use runOnUi, see here
runOnUiThread(new Runnable() {
#Override
public void run() {
textview.setText("");
}
})
You can't update the UI from another thread. You have to move the code that updates the UI to the UIThread.
Try Using:
runOnUiThread(new Runnable() {
#Override
public void run() {
//TextView Update Code
}
});
Tip: Try to reduce the number of lines of code you put inside this, as then there would be no purpose of using another thread.
Only the original thread that created a view hierarchy can touch its views
You have to do ui related work on the main thread...
So you can do it like this...
private void someLongOperation(int arg){
// do some long operation
arg =+ 1000;
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mTextView.setText("Operation's code is " +arg); // fatal exception
}
});
}
this is a simple code to understand the runnable .I tried but not working . can you guys help me pls this is my code
public class Autostart extends activity implements Runnable {
#override
public void run (){
System.out.println ("message");
}
}
}
this not printing any statements
If you are using an Activity, you need to write your code inside Activity lifecycle methods. onCreate() is called when the Activity is created. So starting your Runnable here would be the correct way to do it.
#Override
public void onCreate(Bundle savedInstanceState) {
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
System.out.println ("message");
}
};
handler.postDelayed(r, 1000);
}
You have to create a Thread object and call start() using that object.
Thread t = new Thread(this);
t.start();
Or Just use Handler
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Do Something here
}
}, 5000);
You can use below code to print a value after regular interval of time
public void callAsynchronousTask() {
final Handler handler = new Handler();
timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
Log.e("on print timee", your value);
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 1000); // will execute after 1 sec
}
Hope this will help you
I found a similar solution to Swayam (android implements runnable not working?), however another handler.postDelayed reference within run() was required;
public void onCreate(
...
final Handler handler = new Handler();
final Runnable r = new Runnable()
{
public void run()
{
Log.i(TAG, "message");
handler.postDelayed(this, 1000);
...
}
};
handler.postDelayed(r, 1000);
Try following code
Handler mainThreadhandler = new Handler(getMainLooper());
mainThreadhandler.post(new Runnable(){
public void run(){
// UI work
}
});
public class Autostart extends activity implements Runnable {
Thread = thread;
#override
public void onCreate() {
thread = new Thread(this);
thread.start();
}
#override
public void run (){
System.out.println ("message");
}
}
I have a looper and handler:
private Handler handler;
public class LooperThread extends Thread
{
#Override
public void run()
{
Looper.prepare();
handler = new Handler()
{
#Override
public void handleMessage(Message message)
{
updateUI(message.obj);
}
};
Looper.loop();
}
}
In my MainActivity I then call:
new LooperThread().start();
new Thread(new WorkerTask()).start();
Where WorkerTask implements Runnable.
Can't create handler inside thread that has not called Looper.prepare().
Inside my workerTask it is throwing the error on the second line:
locationManager = (LocationManager) activity.getSystemService(activity.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
If this is in Activity or fragment you can simply use runOnUiThread to update ui.
You need to use this:
activity.runOnUiThread(new Runnable() {
public void run() {
updateUI(message.obj);
}
});
Or to use it with your existing code:
private Handler handler;
public class LooperThread extends Thread
{
#Override
public void run()
{
Looper.prepare();
handler = new Handler()
{
#Override
public void handleMessage(Message message)
{
activity.runOnUiThread(new Runnable() {
public void run() {
updateUI(message.obj);
}
});
}
};
Looper.loop();
}
}
I have the below singleton handler class
public class MyHandler
{
private static Handler handler;
private static boolean isRunning;
public static Handler getHandler(Runnable myRunnable)
{
if (handler == null)
{
initHandler(myRunnable);
}
return handler;
}
private static void initHandler(Runnable myRunnable)
{
handler = new Handler();
isRunning = true;
handler.postDelayed(myRunnable, 5000);
}
public static void reRunHandler(Runnable myRunnable)
{
isRunning = true;
handler.postDelayed(myRunnable, 45000);
}
public static void stopMyHandler()
{
isRunning = false;
handler.removeCallbacksAndMessages(null);
}
}
However, how can I update my UI from here ? As the runnables are inside my activity. Apparently I cannot use getHandleMessage to communicate with it.
If you need more code, how am I using this, I can share.
It's very simple:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//do whatever you want on the UI thread
}
});
Handle has functions for this purposes:
private final Handler handler = new Handler() {
public void handleMessage(Message msg) {
// here you can get data from Message and update your UI. runs in UI thread
}
};
If you will send message with data to your Handler use next code:
Message m = new Message();
Bundle b = new Bundle();
b.putInt("myNumber", 5); // for example
m.setData(b);
myHandler.sendMessage(m);
i am trying to make facebook asynchronous non blocking thread in android. due to which our UI is run separate thread but i am unable to do that can any one tell me how to do that.
and If possible pleade give me one example.
Thanks.........
I don't know much about the Facebook but to access to the ui component from the other thread-
public class Dictionary extends Activity{
Handler mhandler;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Handler mhandler = new Handler();
SearchThread thread = new SearchThread();
thread.setParent(this);
thread.setHandler(mhandler);
}
public void notifyItemChanged(ArrayList<ListItem> lItems){
//write code relating to ui here
}
private class SearchThread extends Thread{
private Handler handler;
Dictionary parent;
public void setParent(Dictionary parent) {
this.parent = parent;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
#Override
public void run() {
final Runnable mUpdateResults = new Runnable() {
public void run() {
parent.notifyItemChanged(listItems);
}
};
handler.post(mUpdateResults);
}
}