how interrupta thread that use blocking call in a looper - android

hi mate i have a thread that use looper. in the looper when he receive message , he call a blocking method (style read socket). How can can write method StopThread to stop this thread to terminate him ? have i to call quit on Handler or interrupt to thread ?
this is the code:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
try{
blocking call read
}catch(Interrupet Exception e) { }
}
};
Looper.loop();
}
public void stopThread(){ ??? }
}

Call
thread.interrupt()
to interrupt the thread.
Edit: You will have to post a runnable on the thread.
looperthread.handler.postrunnable(new Runnable(){
run(){
Looper.myLooper().quit();
}
});

Related

What is the role of the child thread creation handler?

1.I have a problem about creating a handler in a child thread
like
public class Main4Activity extends Activity {
private TextView mTextView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text_view);
new Thread() {
#Override
public void run() {
Looper.prepare();
#SuppressLint("HandlerLeak") Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Toast.makeText(Main4Activity.this, "handler msg", Toast.LENGTH_SHORT).show();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
mTextView.setText("100");
}
};
handler.sendEmptyMessage(1);
Looper.loop();
}
}.start();
}
}
The above code will crash.
Process: com.example.hellokai.kotlindemo, PID: 27485
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6986)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1074)
at android.view.View.requestLayout(View.java:19889)
at android.view.View.requestLayout(View.java:19889)
at android.view.View.requestLayout(View.java:19889)
at android.view.View.requestLayout(View.java:19889)
at android.support.constraint.ConstraintLayout.requestLayout(ConstraintLayout.java:1959)
at android.view.View.requestLayout(View.java:19889)
at android.widget.TextView.checkForRelayout(TextView.java:7369)
at android.widget.TextView.setText(TextView.java:4480)
at android.widget.TextView.setText(TextView.java:4337)
at android.widget.TextView.setText(TextView.java:4312)
at com.example.hellokai.kotlindemo.Main4Activity$1$1.handleMessage(Main4Activity.java:40)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at com.example.hellokai.kotlindemo.Main4Activity$1.run(Main4Activity.java:45)
2.I know to update ui in the main thread,handler creation in the main thread to create, and then send a message in the child thread to the handler can update Ui.
3.My question is what is the role of the handler created in the child thread? When do we need to do that? What is the use of the scene?
Hope someone can solve my confusion!
I have a problem about creating a handler in a child thread.
Your are updating ui from the background thread.
For Example you could send a message from a thread and update ui like
private Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
Toast.makeText(Main4Activity.this.getApplicationContext(), "handler msg", Toast.LENGTH_SHORT).show();
mTextView.setText((String)msg.obj);
}
};
and then
new Thread() {
#Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = Message.obtain(); // Creates an new Message instance
msg.obj = "Hello";
handler.sendMessage(msg);
}
}.start();
Or If you just want a delay there is not need for a thread, looper and sleep as already noted in comments by pskink https://developer.android.com/reference/android/os/Handler.html
I know to update ui in the main thread,handler creation in the main thread to create, and then send a message in the child thread to the
handler can update Ui.
Yes your are right you can create the handler on the ui thread you can send message from the thread and update your ui
My question is what is the role of the handler created in the child thread?
Handler is associated with a thread's looper. If you have a handler in ui thread its associated with it. In your case you have it inside a thread and hence handler is associated with that threads looper.
When do we need to do that? What is the use of the scene?
When you want to communicate from a backgroud thread to ui thread or from ui thread to background thread.
Your code
new Thread() {
#Override
public void run() {
Looper.prepare();
#SuppressLint("HandlerLeak") Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Toast.makeText(Main4Activity.this, "handler msg", Toast.LENGTH_SHORT).show();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
mTextView.setText("100");
}
};
handler.sendEmptyMessage(1);
Looper.loop();
}
}.start();
Can be rewrote to use Android apis:
new Handler(getMainLooper()).postDelayed(
new Runnable() {
#Override
public void run() {
Toast.makeText(Main4Activity.this, "handler msg", Toast.LENGTH_SHORT).show();
mTextView.setText("100");
}
}
}, 200);
Note also that your main problem is that you create the Handler inside the Runnable that already is in a worker-thread, you can also create it early in the onCreate.

Why does Handler.Post Block the main Thread

This is a class which extends Thread and implements the run() function:
public class TestThread extends Thread{
public Handler handler;
public TestThread(){
handler = new Handler(){
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
}
};
}
public Looper getLooper(){
return Looper.myLooper();
}
#Override
public void run() {
// TODO Auto-generated method stub
Looper.prepare();
Looper.loop();
}
}
Now in a button in the main activity I have this code:
TestThread t=new TestThread();
t.start();
Handler h=new Handler(t.getLooper());
h.post(new Runnable(){
#Override
public void run() {
// TODO Auto-generated method stub
while (true);
}
});
As far as I know this is supposed to put the runnable in the target Thread's message queue and the thread (not UI thread) will run it when possible.
But this code blocks the UI. why does this happen? As you see I sent the target thread's looper to the Handler constructor and the handler should use that looper not the main thread's looper.
Looper.myLooper() returns the current thread looper which is the calling UI thread's looper for you. Then you make a handler with it and post a blocking runnable there.
To make this "work", move the myLooper() call under the thread run() method.

Android Looper and Thread doesn't seem to work

Hi I am trying to use a thread with a handler and a looper in Android.
Thread class:
public void run() {
Looper.prepare();
handler = new AndroidHandler(context);
Looper.loop();
while (!stopMe) {
someMethod();
}
((Handler) handler).getLooper().quit();
}
public void someMethod(){
Log.i("New System", "Handling ");
order ++;
Message m=handler.obtainMessage();
m.arg1=order;
handler.sendMessage(m);
}
in a separate class:
public class AndroidHandler extends Handler{
public AndroidHandle(Context){
super();
}
public void dispatchMessage(Message m) {
super.dispatchMessage(m);
}
#Override
public void handleMessage(Message msg) {
Log.i("New System", "handling Message "+msg.arg1);
}
}
It doens't work!!! messages aren't being sent and nothing is getting printed in the console and I don't know how to fix it.... What is the problem here any ideas? thanks
ps: I don't want to use the ui thread I want to do this in a separate thread.
That's because you are doing your infinite while loop in the same thread as the looper! So this thread is kept busy and cannot receive messages...
You need to let the Looper's thread on its own.
Let's say you setup your looper thread like this:
class LooperThread extends Thread {
public Handler handler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
Log.i("New System", "handling Message "+msg.arg1);
}
};
Looper.loop();
}
}
LooperThread looper = new LooperThread();
looper.start();
Then you can send messages from any OTHER thread (the UI thread or any other one) just the same way as you did:
Handler handler = looper.handler;
Message m = handler.obtainMessage();
m.arg1 = order;
handler.sendMessage(m);
But don't do this from the same thread as the looper or it doesn't make any sense.

How to use an handler(created before the looper) in a looper inside thread

hi mate in all tutorial or example the handler used in a looper is created inside the looper example:
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();
}
}
but if a create the handler before the thread, at example
public Handler mHandler=new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
is possible associate him at the thread in run() method in a looper or i must create him only in run method inside the looper ?
The constructor in Handler basically looks like this:
public Handler() {
....
mLooper = Looper.myLooper();
if (mLooper == null) {
// throws an exception
}
....
}
The field, mLooper is a package-private final field - and, of course, there's no setter available for you to change it later on.
In short, the Handler() constructor will associate itself with Looper.myLooper(), there are other constructors that allow you to pass the Looper - but these would also require you to create the Looper prior to creating your Handler.

How do you display a Toast from a background thread on Android?

How can I display Toast messages from a thread?
You can do it by calling an Activity's runOnUiThread method from your thread:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
I like to have a method in my activity called showToast which I can call from anywhere...
public void showToast(final String toast)
{
runOnUiThread(() -> Toast.makeText(MyActivity.this, toast, Toast.LENGTH_SHORT).show());
}
I then most frequently call it from within MyActivity on any thread like this...
showToast(getString(R.string.MyMessage));
This is similar to other answers, however updated for new available apis and much cleaner. Also, does not assume you're in an Activity Context.
public class MyService extends AnyContextSubclass {
public void postToastMessage(final String message) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
}
});
}
}
One approach that works from pretty much anywhere, including from places where you don't have an Activity or View, is to grab a Handler to the main thread and show the toast:
public void toast(final Context context, final String text) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
Toast.makeText(context, text, Toast.LENGTH_LONG).show();
}
});
}
The advantage of this approach is that it works with any Context, including Service and Application.
Like this or this, with a Runnable that shows the Toast.
Namely,
Activity activity = // reference to an Activity
// or
View view = // reference to a View
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
showToast(activity);
}
});
// or
view.post(new Runnable() {
#Override
public void run() {
showToast(view.getContext());
}
});
private void showToast(Context ctx) {
Toast.makeText(ctx, "Hi!", Toast.LENGTH_SHORT).show();
}
Sometimes, you have to send message from another Thread to UI thread. This type of scenario occurs when you can't execute Network/IO operations on UI thread.
Below example handles that scenario.
You have UI Thread
You have to start IO operation and hence you can't run Runnable on UI thread. So post your Runnable to handler on HandlerThread
Get the result from Runnable and send it back to UI thread and show a Toast message.
Solution:
Create a HandlerThread and start it
Create a Handler with Looper from HandlerThread:requestHandler
Create a Handler with Looper from Main Thread: responseHandler and override handleMessage method
post a Runnable task on requestHandler
Inside Runnable task, call sendMessage on responseHandler
This sendMessage result invocation of handleMessage in responseHandler.
Get attributes from the Message and process it, update UI
Sample code:
/* Handler thread */
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());
final Handler responseHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
//txtView.setText((String) msg.obj);
Toast.makeText(MainActivity.this,
"Runnable on HandlerThread is completed and got result:"+(String)msg.obj,
Toast.LENGTH_LONG)
.show();
}
};
for ( int i=0; i<5; i++) {
Runnable myRunnable = new Runnable() {
#Override
public void run() {
try {
/* Add your business logic here and construct the
Messgae which should be handled in UI thread. For
example sake, just sending a simple Text here*/
String text = "" + (++rId);
Message msg = new Message();
msg.obj = text.toString();
responseHandler.sendMessage(msg);
System.out.println(text.toString());
} catch (Exception err) {
err.printStackTrace();
}
}
};
requestHandler.post(myRunnable);
}
Useful articles:
handlerthreads-and-why-you-should-be-using-them-in-your-android-apps
android-looper-handler-handlerthread-i
Get UI Thread Handler instance and use handler.sendMessage();
Call post() method handler.post();
runOnUiThread()
view.post()
You can use Looper to send Toast message. Go through this link for more details.
public void showToastInThread(final Context context,final String str){
Looper.prepare();
MessageQueue queue = Looper.myQueue();
queue.addIdleHandler(new IdleHandler() {
int mReqCount = 0;
#Override
public boolean queueIdle() {
if (++mReqCount == 2) {
Looper.myLooper().quit();
return false;
} else
return true;
}
});
Toast.makeText(context, str,Toast.LENGTH_LONG).show();
Looper.loop();
}
and it is called in your thread. Context may be Activity.getContext() getting from the Activity you have to show the toast.
I made this approach based on mjaggard answer:
public static void toastAnywhere(final String text) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
Toast.makeText(SuperApplication.getInstance().getApplicationContext(), text,
Toast.LENGTH_LONG).show();
}
});
}
Worked well for me.
Kotlin Code with runOnUiThread
runOnUiThread(
object : Runnable {
override fun run() {
Toast.makeText(applicationContext, "Calling from runOnUiThread()", Toast.LENGTH_SHORT)
}
}
)
I encountered the same problem:
E/AndroidRuntime: FATAL EXCEPTION: Thread-4
Process: com.example.languoguang.welcomeapp, PID: 4724
java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
at android.widget.Toast$TN.<init>(Toast.java:393)
at android.widget.Toast.<init>(Toast.java:117)
at android.widget.Toast.makeText(Toast.java:280)
at android.widget.Toast.makeText(Toast.java:270)
at com.example.languoguang.welcomeapp.MainActivity$1.run(MainActivity.java:51)
at java.lang.Thread.run(Thread.java:764)
I/Process: Sending signal. PID: 4724 SIG: 9
Application terminated.
Before: onCreate function
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
}
});
thread.start();
After: onCreate function
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
}
});
it worked.
java 11:
var handler = new Handler(Looper.getMainLooper);
handler.post(() -> Toast.makeText(your_context, "Hi!", Toast.LENGTH_SHORT).show());
Lambdas are available in java 8 though. var is introduced in java 11.
Contrary to almost every answer here, Toast#makeText and Toast#show do NOT have to run on the UI thread. The only requirement is that it runs on a thread that has called Looper#prepare.
The reasons for this is because toasts are handled and rendered by the OS, not the application. Internally, Toast#show makes a call to a system service to enqueue the toast.
This means the following code is valid
private static class MyThread extends Thread {
public Handler handler;
#Override
public void run() {
Looper.prepare();
handler = new Handler(Looper.myLooper()) {
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop()
}
}
final private MyThread t = new MyThread();
// start and wait for t to start looping
private void onClick() {
t.handler.post(() -> Toast.makeText(this, "this works", Toast.LENGTH_SHORT).show());
}
Method in onCreate :
private void toastPublic(final String message){
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
Toast.makeText(getBaseContext(),""+message,
4 /*Toast.LENGTH_SHORT*/).show();
}});
}
Next : use in inside Thread

Categories

Resources