send message not reaching the handler in activity - android

I am having the service and activity. inside service i am sending the message.
I am trying to catch it inside the main activity. But message is not reaching the handler in activity.
Please see the code below.
Service:
Handler handler = new Handler(Looper.getMainLooper());
handler.sendEmptyMessage(112345);
MainActivity:
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this, "handled message successfully", Toast.LENGTH_SHORT).show();
if ( msg.what == 1234 ) {
Toast.makeText(MainActivity.this, "handled message successfully", Toast.LENGTH_SHORT).show();
}
}
};
Can anyone tell me why it is not reaching the handler in the activity.
As far as i know

All messages you are sending using Handler.sendMessageXXX will be handled by the same Handler object. So you have to pass the Handler from Activity to Service. It can be done using Messenger class.
Activity:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Toast.makeText(MyActivity.this, "handleMessage " + msg.what, Toast.LENGTH_SHORT).show();
}
};
final Intent intent = new Intent(this, MyService.class);
final Messenger messenger = new Messenger(handler);
intent.putExtra("messenger", messenger);
startService(intent);
}
}
Service:
public class MyService extends IntentService {
public MyService() {
super("");
}
#Override
protected void onHandleIntent(Intent intent) {
final Messenger messenger = (Messenger) intent.getParcelableExtra("messenger");
final Message message = Message.obtain(null, 1234);
try {
messenger.send(message);
} catch (RemoteException exception) {
exception.printStackTrace();
}
}
}

Related

Passing data between long running threads (LocalBroadcastManager deprecated)

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();
}
};
}

Show AlertDialog in IntentService

How to show AlertDialog in IntentService? Error looks like:
Unable to add window -- token null is not for an application.
So this is problem with context, but I don't know how to fix it. Any solutions?
Below there is my code:
public class GcmMessageHandler extends IntentService {
private GoogleCloudMessaging gcm;
private static AlertDialog alert;
String mes;
private Handler handler;
public GcmMessageHandler() {
super("GcmMessageHandler");
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
handler = new Handler();
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
mes = extras.getString("message");
MApp.wakeupSync();
showToast();
Log.i("GCM", "Received : (" + messageType + ") " + extras.getString("message"));
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
#Override
public void onDestroy() {
try {
gcm.unregister();
} catch (IOException e) {
e.printStackTrace();
}
}
public void showToast(){
handler.post(new Runnable() {
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext());
builder.setMessage("TEST")
.setCancelable(false)
.setNegativeButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
alert = builder.create();
alert.show();
}
});
}
}
You can only show AlertDialog using Activity context.
Here you use getApplicationContext() to create builder, but
neither Application context nor Service context will work.
You have to send broadcast/intent to some Activity and as a response to this message show an AlertDialog inside this Activity using Activity context.
Read this for more details:
https://possiblemobile.com/2013/06/context/
Define a handler in your Activity
/**
* Response handler
*/
private Handler handlerResponse = new Handler() {
#Override
public void handleMessage(Message msg) {
//Show your alert here
}
};
Start service along with Messenger
Intent intent = new Intent(getActivity(), CommunicationService.class);
intent.setAction(Constants.ACTION_ONE);
intent.putExtra(Constants.EXTRA_MESSENGER, new Messenger(handlerResponse));
startService(intent);
In your service return the message after completing the functionality
protected void onHandleIntent(Intent intent) {
if (intent != null) {
sendResult(intent, result);
}
}
private void sendResult(Intent intent, String result) {
Bundle extras = intent.getExtras();
if (extras != null) {
Messenger messenger = (Messenger) extras.get(Constants.EXTRA_MESSENGER);
Message msg = Message.obtain();
msg.obj = result;
try {
messenger.send(msg);
} catch (Exception e1) {
Log.e(getClass().getName(), "Exception sending message", e1);
}
}
}
Constants
public static final String EXTRA_MESSENGER = "EXTRA_MESSENGER";
public static final String ACTION_ONE = "INIT_SOCKET";

Send Data from Service To Activity Android

I am building a music player that uses a service for playback. I have an Activity UI that controls (play, pause, next, ...) the service.
I want to update the UI from my service when the next or previous button is pressed. I thought of passing an integer value. Here is my code:
I have used a messenger for communication. The code in my service looks like:
enum Event {
NextSongChanged, CurrentPlayingSong
};
public synchronized void registerHandler(Messenger m) {
clients.add(m);
}
private void emit(Event e) {
for (Messenger m : clients) {
try {
m.send(Message.obtain(null, e.ordinal()));
} catch (RemoteException exception) {
/* The client must've died */
clients.remove(m);
}
}
}
My method that I am calling on click of next button:
public synchronized void playnext() {
reset();
if(songIndex < (songsList.size() - 1)) {
songIndex += 1;
playSong(songIndex);
} else {
songIndex = 0;
playSong(songIndex);
}
emit(Event.NextSongChanged);
}
As soon as I fire the NextSongChanged event I want to pass the "songIndex" variable into my activity. Any idea on how to achieve this?
My Activity code to handle the event:
private Messenger playerMessenger = new Messenger(new Handler() {
#Override
public void handleMessage(Message msg) {
switch (MyService.Event.values()[msg.what]) {
case NextSongChanged:
//String songTitle = songsList.get(currentSongIndex+1).get("songTitle");
//currentSongIndex += 1;
//songTitleLabel.setText(songTitle);
//updatePlaying();
break;
case CurrentPlayingSong:
break;
}
}
});
Sample code hope will help others
1. Set Handler (to receive message) and Messenger (to communicate) MainActivity.java
Messenger msgService;
boolean isBound;
ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) { isBound = false; }
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
isBound = true;
msgService = new Messenger(service);
}
};
public void sendMessage(View view) {
if (isBound) {
try {
Message message = Message.obtain(null, MessangerService.MESSAGE, 1, 1);
message.replyTo = replyMessenger;
Bundle bundle = new Bundle();
bundle.putString("rec", "Hi, you hear me");
message.setData(bundle);
msgService.send(message); //sending message to service
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
//setting reply messenger and handler
Messenger replyMessenger = new Messenger(new HandlerReplyMsg());
class HandlerReplyMsg extends Handler {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String recdMessage = msg.obj.toString(); //msg received from service
toast(recdMessage);
}
}
2. Setup service class MessengerService.java
Messenger replyMessanger;
final static int MESSAGE = 1;
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE) {
Bundle bundle = msg.getData();
toast(bundle.getString("rec"));//message received
replyMessanger = msg.replyTo; //init reply messenger
doSomething();
}
}
}
private void doSomething() {
// do stuff
if (replyMessanger != null)
try {
Message message = new Message();
message.obj = "Yes loud and clear";
replyMessanger.send(message);//replying / sending msg to activity
} catch (RemoteException e) {
e.printStackTrace();
}
}
Messenger messenger = new Messenger(new IncomingHandler());
#Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
Make sure you declared Service in manifest and binding/unbinding Service in activity.

Android Message in loop

I need to send data from a class to the main UI Activity and i am trying to do this with message passing.
Unfortunately my handler didn't receive the message sent inside a loop. I show you my code so far:
In the UI Activity
private final Handler mIncomingHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
tedit.setText("Received " + msg.arg1);
break;
default:
super.handleMessage(msg);
}
}
};
private final Messenger mMessenger = new Messenger(mIncomingHandler);
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mTransferServiceBound = true;
Message msg = Message.obtain(null, TransferService.MSG_REG_CLIENT);
msg.replyTo = mMessenger;
mTransferService = new Messenger(service);
try {
mTransferService.send(msg);
} catch (RemoteException e) {
Log.e(TAG, "Unable to register client");
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
mTransferService = null;
mTransferServiceBound = false;
}
};
In the service
private class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REG_CLIENT:
Log.d(TAG, "Activity client registered");
mClient = msg.replyTo;
waitCommunication();
break;
case MSG_UNREG_CLIENT:
mClient = null;
stopSelf();
break;
default:
super.handleMessage(msg);
}
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());
private void waitCommunication() {
int i = 0;
while(true) {
try {
mClient.send(Message.obtain(null, MainActivity.Message_READ, i++, -1));
} catch (RemoteException e) {
Log.e(TAG, "Unable to send Message", e);
}
}
}
When i try to send the message without the while(true) it works fine, but like i described above i simply didn't receive any message on the handler.
Can someone help me with this issue ?
I think the service is running on the UI thread. Thus if you have an endless loop running, the Activity will never get any CPU time to respond to the message.
Instead of doing while (true) {...}, allocate a Handler. You can use its various post methods to do things repeatedly at timed intervals, or even as fast as possible, without totally blocking all other activity on the UI thread.

Implement a Thread by providing a new class that extends Thread and overriding its run() method

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();
}

Categories

Resources