CalledFromWrongThreadException sending message Using Handler to other thread when inside Onclick method - android

getting CalledFromWrongThreadException, Only the original thread that created a view hierarchy can touch its views.
on the line, handler2.sendMessage(msg); which is for sending a short text message from the UI thread to MulitThreaderSendback class below.
calling the sendMessage(msg) works perfectly when calling it from inside of the onCreate method, however when i put it inside of the onClick listener it is causing this exception crash.
how can I avoid this crash and be able to call it from an onclick listener so I can use a button press to send the message?
FROM LOGCAT:
E/AndroidRuntime(14366): FATAL EXCEPTION: Thread-1433
E/AndroidRuntime(14366): android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
E/AndroidRuntime(14366): android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5432)
E/AndroidRuntime(14366): android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:970)
Code is:
public class MainActivity extends Activity implements Runnable {
TextView textViewOne;
TextView textViewTwo;
TextView textViewThree;
TextView textViewFour;
TextView textViewFive;
RelativeLayout relativeLayoutOne;
Handler handler;
Handler handler2;
Message msg;
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
relativeLayoutOne = (RelativeLayout) findViewById(R.id.relativeLayout1);
textViewOne = (TextView) findViewById(R.id.textView1);
textViewTwo = (TextView) findViewById(R.id.textView2);
textViewThree = (TextView) findViewById(R.id.textView3);
textViewFour = (TextView) findViewById(R.id.textView4);
textViewFour = (TextView) findViewById(R.id.textView5);
handler = new Handler();
// starting this class that implements Runnable
this.run();
// starting class that extends Thread
MultiThreader multiThreader = new MultiThreader(handler);
multiThreader.start();
// starting class that implements Runnable
MultiThreader2 multiThreader2 = new MultiThreader2(handler);
Thread thread = new Thread(multiThreader2);
thread.start();
MulitThreaderSendback multiSendBack = new MulitThreaderSendback();
Thread thread2 = new Thread(multiSendBack);
thread2.start();
synchronized (multiSendBack) {
while (handler2 == null) {
try {
multiSendBack.wait();
} catch (InterruptedException e) {
//Ignore and try again.
}
}
}
Bundle bundle = new Bundle();
String messageToSend = "message from UI class";
bundle.putString("message", messageToSend);
Random random = new Random();
int messageText = random.nextInt(30);
String putIt = String.valueOf(messageText);
bundle.putString("message", putIt);
msg = Message.obtain();
msg.setData(bundle);
// handler2.sendMessage(msg); // <-- WORKS OK HERE, NO CRASH
relativeLayoutOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
handler2.sendMessage(msg); // <-- FATAL ERROR: CalledFromWrongThreadException
}
});
} // end oncreate
public void setTextViewThree(String textToSet) {
textViewFour.setText(textToSet);
}
public void setTextViewFour(String textToSet) {
textViewFive.setText(textToSet);
}
// local class runnable
#Override
public void run() {
textViewOne.setText("message from local class runnable");
}
// multiThreader inner class
class MultiThreader extends Thread {
Handler handler;
public MultiThreader(Handler handler) {
this.handler = handler;
}
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
textViewTwo.setText("message from multithreader class");
} // end inner run
});
} // end outer run
} // end MultiThreader inner class
// external multiThreader2 inner class
class MultiThreader2 implements Runnable {
Handler handler;
public MultiThreader2(Handler handler) {
this.handler = handler;
}
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
textViewThree.setText("message from MultiThreader2 class");
} // end inner run
});
} // end outer run
} // end MultiThreader2 inner class
class MulitThreaderSendback implements Runnable {
int x = 0;
#Override
public void run() {
// TODO Auto-generated method stub
Looper.prepare();
synchronized(this) {
handler2 = new Handler() {
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
String receivedString = bundle.getString("message");
setTextViewThree("string received from UI thread: " + receivedString);
}
};
notifyAll();
}
Looper.loop();
} // end run method
} // end MultiThreaderSendback inner class
} // end outer class mainactivity

You can embed the line handler2.sendMessage(msg); in this method
runOnUiThread(new Runnable() {
public void run() {
}
});
Try this

Related

Not updating TextView value with thread,Why?

TextView output;
int i;
Random random=new Random();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
output=findViewById(R.id.textView);
new Thread(new mythread()).start();
}
class mythread implements Runnable{
#Override
public void run() {
try {
while(true) {
i = random.nextInt(100);
output.setText(i + "");
Thread.sleep(500);
}
}catch (Exception e){}
}
}
}
it just showing one number in text view
but requirement is ,it should generate random number and keep updating textview after 500ms
Thank You!
The main problem, in your code, is that you can update UI only in the main thread and you are using a custom thread.
The second problem is that you are using Thread.sleep that is a very bad practise.
I suggest you to use Handler
Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
Log.d("Handler", "Running Handler");
handler.postDelayed(this, 500);
}
}
handler.postDelayed(runnable, 0);
and here the kotlin version
var handler = Handler()
var runnable = object : Runnable {
override fun run() {
Log.d("Handler", "Running Handler");
handler.postDelayed(this, 500)
}
}
handler.postDelayed(runnable, 500)
Try this, I think it will solved your problem.
public class MainActivity extends AppCompatActivity {
private Random random;
private Handler handler;
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_number);
displayRandomNumber();
}
/**
* Display random number in text view
*/
private void displayRandomNumber()
{
random = new Random();
handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
int value = random.nextInt();
textView.setText(String.valueOf(value));
handler.postDelayed(this,2000);
}
}, 2000);
}
}

The application leaves at the location where the secondary thread handler is created

Wrote an application to an Android to understand the control of view items from the child thread. Took the main looper from named Mainactivity and passed it through the constructor to a class that implements a child thread and that just changes the contents of TextView through callback.
public class MainActivity extends AppCompatActivity {
private TextView textView = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("create", Thread.currentThread().toString());
textView = (TextView) findViewById(R.id.textView);
HandlerTextView handlerTextView = new HandlerTextView(getApplicationContext().getMainLooper());
handlerTextView.registerMessage(new Message() {
#Override
public void handleMessage(String msg) {
textView.setText(msg);
}
});
HandlerThread handlerThread = new HandlerThread("two", HandlerThread.NORM_PRIORITY);
if(handlerThread != null){
Handler a = new Handler(handlerThread.getLooper());
if(a != null) {
a.post(handlerTextView);
}
}
}
}
public class HandlerTextView implements Runnable {
private Looper mainLooper = null;
private TextView textView = null;
private Socket socket = null;
private Message message = null;
public HandlerTextView(Looper looper) {
this.mainLooper = looper;
}
public void registerMessage(Message m) {
this.message = m;
}
private void setText(final String str) {
Handler handler = new Handler(mainLooper);
handler.post(new Runnable() {
#Override
public void run() {
message.handleMessage(str);
}
});
}
#Override
public void run() {
setText("dfsdfsdfsdf");
}
}
Created a new Handlerthread thread handler object, took it looper
and passed it to the constructor of the new handler handler and it
The error: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity
ComponentInfo{elaneturn.com.myapplication/elaneturn.com.myapplication.MainActiv Caused by: java.lang.NullPointerException
Call handlerThread.start() before creating Handler:
handlerThread.start();
Handler a = new Handler(handlerThread.getLooper());

Handler and TextView updating Issue

I don't understand how an handler can be used to update a TextView during the flow of a program. I'm testing it on a simple code like this
public class MainActivity extends AppCompatActivity {
TextView text;
boolean isReady; //boolean to check a new Message
String update; //String to send to TextView
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.textView);
Handler handler = new MyHandler(); //defined down
MyHandlerThread thr = new MyHandlerThread(handler); //defined in other .class file
thr.start();
for(int i=0;i<100;i++){ //a simple for
if(i%2==0)
thr.setMessage(i + ": Divisible for 2");
else
thr.setMessage(i+": Not Divisible for 2");
}
}
private class MyHandler extends Handler { //inner class
#Override
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
if(bundle.containsKey("refresh")) {
String value = bundle.getString("refresh");
text.setText(value);
}
}
}}
and this is the thread code
public class MyHandlerThread extends Thread {
private Handler handler;
private boolean isSent;
String text;
public MyHandlerThread(Handler handler) {
this.handler = handler;
isSent=false;
text="";
}
public void run() {
try {
while(true) {
if(isSent){
notifyMessage(text);
Thread.sleep(1000);
isSent=false;
}
}
}catch(InterruptedException ex) {}
}
public void setMessage(String str){
text=str;
isSent=true;
}
private void notifyMessage(String str) {
Message msg = handler.obtainMessage();
Bundle b = new Bundle();
b.putString("refresh", ""+str);
msg.setData(b);
handler.sendMessage(msg);
}}
this code just print the last expected string "99: not divible for 2"
You are just calling 100 times your thread setMessage, so texts will overwrite each other before your thread loop has any chance to print them.
You should implement a queue in your setMessage, then the thread loop should pop the next element from the queue, print it (sending a message via the Handler) then sleep. If no more elements are in the queue, just loop until one becomes available.

Issue related to handler desing pattern

I have one class in which a listener is implemented and depending on the methods call in listener, I am to update the data in corresponding activities. For this, i am interested in using the different-different handlers for each activity.
Since, my handler class in each activity is static and hence, handler object is non-static in activity.
So, problem is how to use those activity's handlers to send Message to them.? Help?
This is one of my class in which I am to update the data from another class: How to do?
public class HandlerActivity extends Activity {
TextView tv;
int counter;
Handler handler = new HandlerExtension(this);
//handler static class
private static class HandlerExtension extends Handler {
private final WeakReference<HandlerActivity> targetActivity;
//constructor
HandlerExtension(HandlerActivity activity){
this.targetActivity = new WeakReference<HandlerActivity>(activity);
}
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
HandlerActivity activity = targetActivity.get();
if(activity != null){
final String data = msg.getData().getString("counter");//gettting msg data
activity.tv.setText(data);
}
}
}//HandlerExtension
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.handler_activity);
Button startB = (Button) findViewById(R.id.button1);
tv = (TextView) findViewById(R.id.textView1);
final Runnable runnable = new Runnable() {//object to be executed in the thread
#Override
public void run() {
counter+=10;
String result = String.valueOf(counter);
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("counter", result);
msg.setData(bundle);
handler.sendMessage(msg);//Now, updating the view from background thread via handler
SystemClock.sleep(1000);
}
};
//starting the background thread on button click
startB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(runnable).start();
}
});
}//onCreate
}//HandlerActivity

Android Refresh TextView from Thread

I know there are already quite a number of discussions about this, but none of what I found could clear my confusion.
I'm using the Android SDK for the first time and my Java Skills are rather average.
I have the following Problem:
From my MainActivity - OnCreate() fct. I start a thread (Receiver), receiving data from a SocketStream. This thread shall refresh a TextView-Element on the GUI when new data was read from the stream.
What is a simple but proper way to do so? I read something about ASyncTask, but did not understand how to implement it.
public class MainActivity extends Activity
{
ExecutorService myExecutor;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println("this is a test"); System.out.flush();
try
{
myExecutor = Executors.newCachedThreadPool();
myExecutor.execute(Receiver.getInstance());
}
catch (IOException e)
{
e.printStackTrace();
}
}
...
public class Receiver implements Runnable
{
[...]
public void run()
{
while (true)
{
//blocking system-io-call to read data from socket..
//extract information
// *** update textView *** ??
}
}
}
You can implement handler in GUI thread to change GUI (in MainActivity in your case):
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//refresh textview
}
};
and than call it from another threads
activity.handler.sendEmptyMessage(what);
You can write your own constructor for Receiver:
public class Receiver implements Runnable
{
[...]
MainActivity activity;
public Receiver(MainActivity activity){
this.activity = activity;
}
public void run()
{
while (true)
{
//blocking system-io-call to read data from socket..
//extract information
// *** update textView *** ??
activity.handler.sendEmptyMessage(0);
}
}
}
You can use runOnUiThread
public class Receiver implements Runnable
{
[...]
public void run()
{
while (true)
{
//blocking system-io-call to read data from socket..
//extract information
runOnUiThread(new Runnable() {
public void run() {
// *** update textView *** ??
}
});
}
}
}
this is a example:
create Counter class :
public class Counter implements Runnable
{
private ICounterEvents listener;
public static Thread OBJ_THREAD = null;
public Counter()
{
OBJ_THREAD = new Thread(this);
}
public void setCountListener(ICounterEvents listener)
{
this.listener = listener;
}
public void start()
{
OBJ_THREAD.start();
}
#Override
public void run()
{
for(int i = 0; i < 100; i++)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
Message msg = Message.obtain();
msg.obj = i;
this.handler.sendMessage(msg);
}
}
private Handler handler =
new Handler()
{
#Override
public void handleMessage(Message msg)
{
if(Counter.this.listener != null)
{
int value = (Integer)msg.obj;
Counter.this.listener.countChanged(value);
}
}
};
}
and create a interface class:
public interface ICounterEvents
{
public void countChanged(int value);
}
and than in your main layout create a textview and a button,
and use this code in onCreate method in MainActivity:
public class MainActivity extends Activity implements ICounterEvents, OnClickListener
{
private TextView txtCounter;
private Button btnStart;
private Counter counter;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.setupViews();
}
private void setupViews()
{
this.counter = new Counter();
this.counter.setCountListener(this);
this.txtCounter = (TextView)findViewById(R.id.txtCount);
this.btnStart = (Button)findViewById(R.id.btnStart);
this.btnStart.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
this.counter.start();
}
public void countChanged(int value)
{
try
{
this.txtCounter.setText(value + "");
}
catch (Exception e)
{
}
}
}

Categories

Resources