i ahve a problem with a thread handler receiving a message. all other thread i implemnted this pattern works fine. here my code:
Start thread
InternalScoresThread t = new InternalScoresThread(
this.game.getApplicationContext(),
this.map.fileName, this.map.getCurrentTime(),
new Handler() {
#Override
public void handleMessage(Message msg) {
Log.d("DEBUG", "message received");
if (msg.getData().getBoolean("record")) {
Player.this.showtRecordMessage();
} else {
Player.this.showtFinishMessage();
}
Player.this.showTimeMessage();
Player.this.showRestartMessage();
}
});
t.start();
Thread class
public class InternalScoresThread extends Thread {
private Handler handler;
private String map;
private float time;
private Context context;
public InternalScoresThread(Context context, String map, float time, Handler handler) {
this.context = context;
this.handler = handler;
this.map = map;
this.time = time;
}
#Override
public void run() {
Log.d("DEBUG", "thread started");
Database db = Database.getInstance(this.context);
float bestTime = db.getBestTime(this.map);
db.addRace(this.map, this.time);
Log.d("DEBUG", "race added");
Message msg = new Message();
Bundle b = new Bundle();
b.putBoolean("record", this.time < bestTime || bestTime == 0);
msg.setData(b);
this.handler.sendMessage(msg);
Log.d("DEBUG", "message sent");
}
}
The "thread started, "race added" and "message sent" logs appear in logcat, but not the "message received" in the handler.
well, I dunno why, but dispatchMessage() instead of sendMessage() solved the problem...
I know this is an old question, but Google.
The problem is that you created the Handler in the UI thread. It then receives messages on that thread. You need to create the Handler in the new thread:
public void run() {
Log.d("DEBUG", "creating Handler in thread " + Thread.currentThread().getId());
Looper.prepare();
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.d("DEBUG", "message received");
}
};
Looper.loop();
Related
I have the following scenario: a foreground service spawns 2 HandlerThreads (A and B). From time to time A must send some data to B, B performs a certain action on this data and sends back to A the result of the operation. I do not know how to effectivelly pass data between these 2 threads. Originally I was posting messages to the MainService thread (via handlers), which in turn posted it to the appropriate thread. But it seems like a bit overkill:
(thread A) post message to main thread handler
(main thread) receive the message and post it to the thread B handler
(thread B) do something and post the result back to the main thread handler
(main thread) receive the message and post it to the thread A handler
(thread A) do something
I thought that I could use LocalBroadcastManager, but it seems to be deprecated now. Do you have any suggestion on that?
EDIT 1
Simplified version of the program. I am afraid that the showed code will get too much complex after adding more signals between threads.
MainService.java
public class MainService extends Service {
private static final String TAG = "MainService";
public static final Integer START_A = 0;
public static final Integer DO_STH_IN_B = 1;
public static final Integer RESPOND_FROM_B_TO_A = 2;
private Handler mServiceHandler = new Handler(Looper.getMainLooper()) {
// this is a dispatcher for messages between threads
#Override
public void handleMessage(#NonNull Message msg) {
super.handleMessage(msg);
Message msg_s;
if (msg.what == DO_STH_IN_B)
msg_s = Message.obtain(myThreadB.getHandler());
else if (msg.what == RESPOND_FROM_B_TO_A)
msg_s = Message.obtain(myThreadA.getHandler());
else return;
msg_s.what = msg.what;
msg_s.sendToTarget();
}
};
private MyThreadA myThreadA = new MyThreadA(mServiceHandler);
private MyThreadB myThreadB = new MyThreadB(mServiceHandler);
#Override
public void onCreate() {
super.onCreate();
myThreadA.start();
myThreadB.start();
SystemClock.sleep(100);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification =
new NotificationCompat.Builder(this, "M_ID")
.setContentTitle("Notification Title")
.setContentText("Notification Text")
.setSmallIcon(R.drawable.ic_android)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
Message msg = Message.obtain(myThreadA.getHandler());
msg.what = START_A;
msg.sendToTarget();
//stopSelf();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
myThreadA.quit();
myThreadB.quit();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
MyThreadA.java
public class MyThreadA extends HandlerThread {
private static final String TAG = "MyThreadA";
private Handler mHandler;
private Handler mMainServiceHandler;
public MyThreadA(Handler handler) {
super(TAG, Process.THREAD_PRIORITY_BACKGROUND);
mMainServiceHandler = handler;
}
#SuppressLint("HandlerLeak")
#Override
protected void onLooperPrepared() {
mHandler = new Handler() {
#Override
public void handleMessage(#NonNull Message msg) {
if (msg.what == MainService.START_A) {
mHandler.post(myRoutine);
} else if (msg.what == MainService.RESPOND_FROM_B_TO_A) {
mHandler.post(myRoutineRespond);
}
}
};
}
public Handler getHandler() { return mHandler; }
private Runnable myRoutine = new Runnable() {
#Override
public void run() {
Log.d(TAG, "run: [thread A] myRoutine");
// do something here (may be blocking)
SystemClock.sleep(1000);
// send message to Thread B (by passing it through the main service)
Message msg = Message.obtain(mMainServiceHandler);
msg.what = MainService.DO_STH_IN_B;
msg.sendToTarget();
// repeat the routine
mHandler.post(myRoutine);
}
};
private Runnable myRoutineRespond = new Runnable() {
#Override
public void run() {
Log.d(TAG, "run: [thread A] respond handler");
// do something here with the respond from B
SystemClock.sleep(2000);
}
};
}
MyThreadB.java
public class MyThreadB extends HandlerThread {
private static final String TAG = "MyThreadB";
private Handler mHandler;
private Handler mMainServiceHandler;
public MyThreadB(Handler handler) {
super(TAG, Process.THREAD_PRIORITY_BACKGROUND);
mMainServiceHandler = handler;
}
#SuppressLint("HandlerLeak")
#Override
protected void onLooperPrepared() {
mHandler = new Handler() {
#Override
public void handleMessage(#NonNull Message msg) {
if (msg.what == MainService.DO_STH_IN_B) {
mHandler.post(myRoutine);
}
}
};
}
public Handler getHandler() { return mHandler; }
private Runnable myRoutine = new Runnable() {
#Override
public void run() {
Log.d(TAG, "run: [thread B] do something and respond");
// do something here (may be blocking)
SystemClock.sleep(2000);
// send respond back to Thread A
Message msg = Message.obtain(mMainServiceHandler);
msg.what = MainService.RESPOND_FROM_B_TO_A;
msg.sendToTarget();
}
};
}
I wrote the below code to better understand the Handler and the Looper. I would liek to know how can I quit the Looper on occurence of a specific condition
for example, when a counter reaches a specific limit.
In the below code, I want to call .quit() on the looper of the Thread T when "what" is equal to 10.
According to the code i wrote below, even when the contents of "what" exceeds 10, the "handleMessage" method is getting called...i expected that when .quit()
is called, the "handleMessage" will no longer be called.
please let me know how can I properly quit a Looper.
app.gradle
public class ActMain extends AppCompatActivity {
private static final String TAG = ActMain.class.getSimpleName();
private Handler mHandler = null;
private Button mBtnValues = null;
private int i = -1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_act_main);
this.mBtnValues = findViewById(R.id.btnValues);
this.mBtnValues.setOnClickListener(x-> {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("what", "" + i++);
Log.d(TAG, "i: " + i);
msg.setData(bundle);
mHandler.sendMessage(msg);
});
new T().start();
}
private class T extends Thread {
private String str = "";
public T() {}
#Override
public void run() {
super.run();
Log.d(TAG, "run method started");
Looper.prepare();
Log.d(TAG, "beginning of the looped section");
final String[] cnt = {""};
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String what= msg.getData().getString("what");
str += what;
Log.d(TAG, "new str: " + str);
}
};
Log.d(TAG, "end of the looped section");
if (i == 10) {
Looper.myLooper().quit();
}
Looper.loop();
}
}
}
I want to create another thread to loop itself and perform something.
May I know any mistake I done? Because it just perform single time and stop.
public class LooperClazz extends Thread {
private MessageQueue messageQueue;
private Context context;
private long counter = 0;
public LooperClazz(Context context){
this.context = context;
}
#Override
public void run() {
Looper.prepare();
long threadId1 = Thread.currentThread().getId(); //new thread
final Handler responseHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
long mainThreadId = Thread.currentThread().getId(); //1
//Here success to Toast something.
}
};
messageQueue = Looper.myQueue();
messageQueue.addIdleHandler(new MessageQueue.IdleHandler() {
#Override
public boolean queueIdle() {
//I'm expecting running this in a loop, but it not, why?
long threadId2 = Thread.currentThread().getId();
//Same as threadId1
counter++;
Message msg = new Message();
msg.obj = counter+ "";
responseHandler.sendMessage(msg);
SystemClock.sleep(3000);
return true;
}
});
Looper.loop();
}
}
In MyApplication, I just start it with
new LooperClazz(context).start();
I believe I'm not understanding how Handler can pass/receive messages.
I have a handler created on a different thread, and then have the main thread send it a message. Here is how I did it
public void startAniHandlerThread(int timer){
final int sleeptime = timer;
int test2;
Thread thread1 = new Thread(){
public void run(){
Looper.prepare();
Log.v("loop","looping");
Handler handler = new Handler(){
#Override
public void handleMessage(Message inputMessage) {
Log.v("Thread handler", "checking");
if(inputMessage.what == 10) {
if (inputMessage.arg1 == 2) {
Log.v("Thread handler", "stop");
} else if (inputMessage.arg1 == 1) {
Log.v("Thread handler", "continue");
} else{
Log.v("nothing", "nothing");
}
}
}
};
Looper.loop();
}
};
thread1.start();
}
Here is how I attempted to send a message to it from the UI thread:
public void stopAniHandlerThread(){
Handler newHandler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
return false;
}
});
Runnable newRunable = new Runnable() {
#Override
public void run() {
Handler handler = new Handler();
Message message = new Message();
message.what = 10;
message.arg1 = 2;
handler.sendMessage(message);
}
};
newHandler.postDelayed(newRunable, 2000);
}
Here is the Log I get(I'm expected this to get called, but it doesn't:
Log.v("Thread handler", "stop");
V/stopAniHandlerThread﹕ posting
V/loop﹕looping
Implementing a Thread by providing a new class that extends Thread and overriding its run() method is new to me. I've tried all day to get it to work. Here's my code:
/*
* see http://developer.android.com/reference/java/lang/Thread.html
*/
class threadClass extends Thread {
private Handler mHandler;
private Message mMsg;
// constructor
public threadClass(Handler handler, Message msg) {
// do something like save the Handler reference
mHandler = handler;
mMsg = msg;
}
#Override
public void run() {
// do some background processing, call the Handler?
mHandler.sendMessage(mMsg);
}
}
public Thread passHandlerToThread(Handler handler) {
handler.sendEmptyMessage(10);
Message msg = Message.obtain();
msg.what = 10;
Thread thread = new threadClass(handler, msg);
return thread;
}
private Handler localHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
int what = msg.what;
if (what == 10) Log.i("localHandler", "what: " + what);
}
};
public void startThread() {
Thread thread = passHandlerToThread(localHandler);
thread.start();
}
I call startThread() in my LocalService onCreate() but nothing happens. What am I doing wrong? I was expecting localHandler() to be called twice: once in passHandlerToThread() and again in run().
Do something like this:
private final Handler handler = new Handler();
// toast runnables
final Runnable updateTwitterNotification = new Runnable() {
#Override
public void run() {
dismissProgressSpinner();
Toast.makeText(getBaseContext(), "Tweet sent!", Toast.LENGTH_LONG).show();
}
};
final Runnable updateCreateError = new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(), "Tweet error!", Toast.LENGTH_LONG).show();
}
};
postMessageInThread();
//implementation:
private void postMessageInThread() {
Thread t = new Thread() {
#Override
public void run() {
try {
connectToTwitterService() // or whatever
handler.post(updateTwitterNotification);
} catch (Exception ex) {
Log.e(TAG, "Error sending msg", ex);
handler.post(updateCreateError);
}
}
};
t.start();
}