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"));}
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 am trying to develop a android chat application using asmack api and server is openfire.
I am at the stage of handling incoming messages from users and representing them corresponding user chat screen (i.e. activity).
So for that, I developed 2 activities i.e.
public class ResultActivity extends Activity
public class UserActivity extends Activity
resultactivity is the one which maintains roster presence information like online , away etc. so this would be only one instance.
useractivity is the one which maintain chat list with the corresponding user. This activity starts with onclick event on list in ResultActivity. so this can be more than one based on no of users on Result activity..
So to listen to incoming packets (i.e. incoming messages) I added a listener in the ResultActivity which adds messages into global arraylist.
In Result Activity:
PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
MainActivity.connection.addPacketListener(receive_message, filter);
PacketListener receive_message = new PacketListener() {
public void processPacket(Packet packet) {
message = (Message) packet;
String sender=null,body=null,sender_final=null;
if (message.getBody() !=null) {
Log.d("UA", "message from "+StringUtils.parseBareAddress(message.getFrom()));
Log.d("UA", "message is "+message.getBody());
sender = StringUtils.parseBareAddress(message.getFrom());
sender_final=sender.substring(0, sender.indexOf('#'));
body = message.getBody();
Log.d("UA", "Sender : "+sender_final+" body : "+body);
userMessage = new UserMessage("In", sender_final, body);
userMessage_list.add(userMessage);
userMessage_list.add(userMessage);
}
}
};
After adding the message in the global message list (i.e. userMessage_list) I need to update the user activity with incoming message. userMessage_list is the array list used as array in the getview method of base adapter extended class.
So Now I need the update the userActivity list with notifydatasetchanged method.
In UserActivity :
private class UserActivityThread extends Thread {
#Override
public void run() {
UserActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
userAdapter.notifyDataSetChanged();
}
});
}
}
So how to call the notifydatasetchanged method in the another activity.
I am curious to know how this scenario is handled in whatsapp or any chat applications.
I have solved this problem in my chat app by using a ContentProvider class and a CursorLoaderwhich will be automatically notified everytime certain URI has new records.
In your case I would recommend you launching a broadcast message. Your class which has a ListView with the messages will have registered a BroadcastReceiver and it will be listening to possible updates. Everytime your BroadcastReceiver.onReceive is triggered in your activity, refresh your adapter.
Hope it helps :)
EDIT
How to achieve this:
Create a BroadcastReceiver object in your activity.
BroadcastReceiver mReceiver;
Code your broadcast receiver (on your onCreate for example)
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//extract our message from intent
String extra= intent.getStringExtra("extra");
Log.i("msg received: ", extra);
}
};
Add IntentFilter (in your onResume could be valid)
IntentFilter intentFilter = new IntentFilter("com.myproject.myintentfilter");
4.1 register your receiver
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
registerReceiver(mReceiver,intentFilter);
}
4.2 Unregister your receiver
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
this.unregisterReceiver(mReceiver);
}
Make sure your receiver will receive the message, cheking that your sendBroadcast matches the IntentFilter.
Finally:
Intent i = new Intent("com.myproject.myintentfilter").putExtra("extra", "This is a new value");
this.sendBroadcast(i);
EDIT 2
In the case of receiving a message during your activity rotation (receiver is not registered) I have found 2 solutions which I am not very satisfied with, but they work.
Reload your listview after orientation change, as the activity destroys itself, you can just reload the information of your listview, your new message should appear anyway.
Put a static field in your activity, everytime you receive a message, put such variable to TRUE. If your broadcastReceiver triggers, put that variable to false, and when your onResume / onCreate method is called after a change of orientation, check your static variable and do your reload if the variable was true (put it to false after reloading the ListView).
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!
1) I have an Activity. This Activity starts a service, which in turn creates and registers a BroadcastReceiver.
2) I have an Activity. This Activity creates and registers a BroadcastReceiver.
When does BroadcastReceiver's life end in each of the above cases? In other words - when it gets destroyed and won't listen to broadcasts anymore?
Declare broadcast receiver in manifest to achieve independent life cycle for it.
http://developer.android.com/reference/android/content/BroadcastReceiver.html
Only onReceive() method is called in BroadcastReciver's life cycle.
A BroadcastReciever life cycle ends (ie stop receiving broadcast) when you unregister it. usually you would do this in the onPause/onStop method. but it's up to you technically.
Example:
#Override
public void onResume() {
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));
}
// 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();
}
I have an android service that I need to stop and restart. In the service's onDestroy(), I have some clean up code that may take a while to execute.
Is there away to notify the application that's using the service that it's finish executing onDestroy()? Or something the application can do to check if onDestroy() has finish its execution?
Yes, use broadcast in onDestroy() method!
Intent intent = new Intent( "Service_destroyed" );
// You can also include some extra data.
intent.putExtra("message", "Service is destroyed!");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
That will notify the other activities. Be sure to register the broadcast first in the activities and unregister when not needed anymore.
Register:
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceDestroyedReceiver, new IntentFilter( "Service_destroyed" ));
Here is the method to catch the broadcast:
private BroadcastReceiver mServiceDestroyedReceiver= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String message = intent.getStringExtra("message");
Log.d(TAG, "Service is destroyed message: " + message);
}
};
Unregister broadcast receiver:
LocalBroadcastManager.getInstance(this).unregisterReceiver( mServiceDestroyedReceiver);