I am working on using the LocalBroadcastReceiver to send messages from an IntentService to an activity. I have a basic activity all the activities in my project inherit from that contains the activity code below. And a basic IntentService that is initialized by a WakefulBroadcastReceiver that contains the service code below.
In my activity I have:
#Override
protected void onCreate(Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(
mMessageReceiver, new IntentFilter("push-message"));
super.onCreate(savedInstanceState);
}
#Override
protected void onPause(){
LocalBroadcastManager.getInstance(this).unregisterReceiver(
mMessageReceiver);
super.onPause();
}
#Override
protected void onResume(){
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(
mMessageReceiver, new IntentFilter("push-message"));
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
And in my service I have:
public class SimpleMessagerService extends IntentService {
public SimpleMessagerService() {
super("SimpleMessagerService");
}
#Override
protected void onHandleIntent(Intent intent) {
Intent newintent = new Intent("push-message");
// You can also include some extra data.
String message = intent.getExtras().getString("message");
newintent.putExtra("message", message);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
The service onHandleIntent is being triggered, and when I put a break point in it and evaluate the expression: LocalBroadcastManager.getInstance(this); I can see the mMessageReceiver in the mReceivers list; however when I put a breakpoint in mMessageReceiver's onReceive, I find that it is never being triggered.
More info:
It seems my service cannot actively do anything when it is called, but does not throw an exception. I tried saving my current context in the application file and throwing up a toast message from the service. The process seems to succeed, but the toast message never appears. This is what I have in the manifest for the service:
<service
android:name="packagename.services.SimpleMessagerService"
android:exported="false">
</service>
turns out a couple things where wrong. First exported needed to be true in the manifest. Second, because the service is an Intent service it operates in a different thread than the main activities, so in order to send a broadcast to them I have to make it look something like:
Handler mHandler = new Handler(getMainLooper());
mHandler.post(new Runnable() {
#Override
public void run() {
Intent newintent = new Intent("push-message");
newintent.putExtra("message", message);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(newintent);
}
});
So the main thread is hit. I hope this helps someone else with the same problem.
I'd like to credit rubenlop88 in the for posting this solution for a similar problem in the thread,
java.lang.RuntimeException: Handler (android.os.Handler) sending message to a Handler on a dead thread
Related
I am trying to implement an Async task that gets a string from a url inside a service.
I am using a startedService which calls the Async task get the correct string, update a public DB class content and return to the main activity, the problem is that the list adapter which i need to notify of the change in the DB is at the main activity and i don't have access to it from the Service , I am a a noobie so I am not familiar with what better to use , started or bind service for that job, any sugestions ?
thank you
You can use BroadcastReceiver :
In your Activity:
#Override
public void onResume() {
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("mybroadcast"));
}
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
#Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
And to Broadcast from service use:
Intent intent = new Intent();
intent.setAction("mybroadcast");
sendBroadcast(intent)
I have a service that get data from an other application.
When I get date I send message to broadCast in order to refresh the UI.
The onReceive method is called many times and data displayed multiple times.
this is my code:
DataService.java
if(sizeLat == 1) {
sendMessage("Alerte1;");
}
else {
sendMessage("Alerte2;");
}
private void sendMessage(String message) {
Log.w("","==> send message");
Intent intent = new Intent("my-event");
// add data
intent.putExtra("message", message);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
MainActivity.java
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("","Onreceiver");
String message = intent.getStringExtra("message");
if(message.equals("Alerte1")){
parentItems.add(message);
adapter.notifyDataSetChanged();
}}};
#Override
protected void onResume() {
Log.d(TAG, "On Resume");
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));}
How can I resolve the problem ?
Put broadcast register line in onCreate and unregister it in onDestroy() method. The line which you have to move from onResume() to onCreate is:-
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));}
Possibly, you have two instances of the activity living at the same time. Make a breakpoint on the message receiver and check the address of the instance of your activity class and see if they are different each time the onReceive is called.
There are a few reasons why you could have two instances living at the same time, but one of the most common is leaking context within the activity.
More on this topic.
I fixed same problem by unregister BroadcastReceiver in onPause method
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver,new IntentFilter("my-event")));
Register it in OnResume Method
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));}
I have an intent service in my app that is called from the main thread. The intent service is started upon clicking on a button. Once started, the service connects to the server and retrieves information.
I want to send broadcast to the activity once the data is retrieved. If I send it from the onHandleIntent(), the data might not be retrieved yet.
Can't I send the broadcast from the method that retrieves the data? If not, any alternatives?
code sample:
onHandleIntent()
{
myMethod();
//Here where it is expected to send the broadcast
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.example.intent.action.MESSAGE_PROCESSED");
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra("TAG",Message);
getApplicationContext().sendBroadcast(broadcastIntent);
}
MyMethod()
{
//Retrieving data from server, which returns Message.
//Here Where I want to send broadcast (Message is ready)
}
Thank you for your help.
You could also use a handler/runnable combo to act as a timer, so that you check whether the value is null or not before sending the broadcast. See this for how to do that.
edit:
It would look like this:
Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
sendBroadcast();
}
};
onHandleIntent()
{
myMethod();
runnable.run();
}
MyMethod()
{
//Retrieving data from server, which returns Message.
//Here Where I want to send broadcast (Message is ready)
}
sendBroadcast(){
// If your value is still null, run the runnable again
if (Message == null){
handler.postDelayed(runnable, 1000);
}
else{
//Here where it is expected to send the broadcast
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.example.intent.action.MESSAGE_PROCESSED");
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra("TAG",Message);
getApplicationContext().sendBroadcast(broadcastIntent);
}
}
You could do the following in your activity class:
1- Create a BroadcastReceiver
private class MyBroadcastReceiver extends BroadcastReceiver
#Override
public void onReceive(Context context, Intent intent) {
//Get your server response
String server_response = intent.getExtras().getString("TAG");
//Do your work
}
}
2- Create an object in your activity (as a member of the activity)
MyBroadcastReceiver mReceiver= new MyBroadcastReceiver ();
3- Register it in your onResume() method and deregister it in your onPause() method.
#Override
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.intent.action.MESSAGE_PROCESSED");
registerReceiver(mChatReceiver, filter);
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
That should be enough!, Hope it helps!
I need to send some data to my service on app startup. I put data to Intent, cast sendBroadcast(intent) in onCreate method of my activity. So my service doesn't receive any intents.
But if i use Handler.post with custom Runnable in onCreate everything works fine.
Can someone explain me such a strange behavior?
Doesn't work at all:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
broadcastIntent = new Intent(BROADCAST);
broadcastIntent.putStringArrayListExtra("URLs", alURLS);
sendBroadcast(broadcastIntent);
}
Works perfectly:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
broadcastIntent = new Intent(BROADCAST);
broadcastIntent.putStringArrayListExtra("URLs", alURLS);
hDelayedPost = new Handler();
hDelayedPost.post(rHandleDelayedSendBroadcast);
}
private Runnable rHandleDelayedSendBroadcast = new Runnable() {
#Override
public void run() {
sendBroadcast(broadcastIntent);
}
};
So my service doesn't receive any intents
Services do not receive broadcasts. BroadcastReceivers receive broadcasts.
UPDATE: Presumably, your Service is not yet running in onCreate() of your activity, and you are calling startService() sometime between onCreate() and when your delayed sendBroadcast() is called.
I created a Handler in my activity. The handler will be stored in the application object.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.action_activity);
appData = (AttachApplication) getApplication();
Handler updateHandler = new Handler() {
public void handlerMessage(Message msg) {
Log.d( TAG, "handle message " );
}
};
appData.setUpdateHandler( updateHandler );
}
My plan is that this handleMessage will be called when i setEmtpyMessage in my service. The service retrieves the handler from the application object.
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand of attachService");
List<Job> jobList = DBManager.getInstance().getAllOpenJobs();
appData = (AttachApplication) getApplication();
updateHandler = appData.getUpdateHandler();
updateHandler.sendEmptyMessage( 101 );
I checked the logs, but there is no handle message so that it seems that my plan does not work. I want to update a textfield each time my service did its job.
In Your case You shoild use BroadcastReceiver like this:
define receiver in your Activity class:
public class DataUpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(MainService.REFRESH_DATA_INTENT)) {
//do something
}
}
}
on your onCreate or onStart method you must register receiver:
DataUpdateReceiver dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(MainService.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);
on your service add this:
public static final String REFRESH_DATA_INTENT = "done";
and when you done all staff you must send brocast like this:
sendBroadcast(new Intent(MainService.REFRESH_DATA_INTENT));
Your code snippet says public void handlerMessage(Message msg), but I think you mean public void handleMessage(Message msg), without the r. You can avoid these problems by using the #Override tag when you intent to override methods from a superclass; so your snippet would be rendered #Override public void handleMessage(Message msg), whereas #Override public void handlerMessage(Message msg) would be an error.
What are you trying to do? I really don't see the point of instantiating a Handler in an Activity, since all you're doing is getting Messages from the MessageQueue. You certainly don't want to fool around with any of the Messages that Android posts, and there are much better ways of sending messages to the Activity.
Of course, you don't include the code for AttachApplication, so I can only speculate.
You're also trying to access this Handler from a Service. Something is going on, but I'm not sure what.
If you want to update a TextView every time your Service does its job, send a broadcast Intent from the Service to the Activity, and use a broadcast receiver in the Activity. You should also consider using an IntentService instead of a Service.