Android - IntentService - sendBroadcast from custom method - android

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!

Related

Broadcast Receiver from service Listener

I created a Broadcast Receiver (BR) in a service that will react to incoming SMS with specific number and body. I only need it to receive for a few seconds/minutes after user action, that's why I didn't registered it in manifest or activity (user may close it). BR has two parts, automatic (which works fine) and manual which should launch MainActivity and start a Dialog. I know that Dialog can't be started from BR and thats why I created a Listener, but my problem is that it is always null after service starts. It has value in onCreate of my MainActivity, but when service starts it changes to null, and I understand why (serivce re-initalize the Listener listener). I even tryed to put initialised listener value to SharedPrefs and restore it after, but when I try to store it with json it only stores null again. So how do I make my listener != null??? These are the relevant parts of my code:
MainActivity
onCreate {
SMSService smsReceiver = new SMSService();
smsReceiver.setListener(new SMSService.Listener() { //here listener from service is != null
#Override
public void onTextReceived(String s) {
dialogS(s); // totaly different dialog
}
});
...
mDialogBuilder = new AlertDialog.Builder(this);
...
.setPositiveButton(new OnClick...
Intent servisIntent = new Intent(MainActivity.this, SMSService.class);
startService(servisIntent);
...
}
SMSService
private Listener listener; // and here it get null which is the problem
public int onStartCommand(Intent intent, int flags, int startId) {
...
SMSReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MainActivity.class);
context.startActivity(i);
if (listener != null) {
listener.onTextReceived("4333");
}
}
void setListener(Listener listener) {
this.listener = listener; }
interface Listener {
void onTextReceived(String text);
}
Btw I also tried to put smsReceiver.setListener block of code in my Dialog .setPossitive onClickListener after calling startService hoping it would initiate after service but nothing
Installing a listener mechanism with setter method in service is bad practice. You can use ResultReceiver to receive callback results from service. It is Parcelable, so it can be passed in an intent before service started

IntentService - Wakelock release issue

I have an alarm application.
Flow looks like this :
WakefulBroadcastReceiver(Acquires wakelock) --->> Intent service -->> startActivity
public class AlarmService extends IntentService {
protected void onHandleIntent(Intent intent) {
Intent activityIntent = new Intent(this, TriggeredActivity.class);
activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(activityIntent);
Basically WakefulBroadcaseReceiver starts an intent service using startWakefulService(). Inside intent service's onHandleIntent(), only work I am doing is further starting a new activity using startActivity(). That new activity is where I am using mediaPlayer in a loop, which sounds the alarm. That activity has a dismiss button, which waits for user click to stop the media player & activity finishes.
Now the problem I am facing is that after calling startactivity() inside intent service, I can not wait for TriggeredActivity to finish(no equivalent to startActivityForResult in Service) and then complete wakeful intent. Related link
startActivity(activityIntent);
WakefulBCastReceiver.completeWakefulIntent(intent); /* can't do here */
So I am not explicitly releasing wakelock here.
My question is will the wakelock be released automatically(link-to-death), when the process that is holding it is killed.
If yes, then in my particular scenario, I need not call WakefulBCastReceiver.completeWakefulIntent().
Yes, you need to use completeWakefulIntent.
You need to put your TriggeredActivity intent into EXTRAs.
#Override
public void onReceive(Context context, Intent intent) {
Intent intentService = new Intent(context, NotificationsIntentService.class);
// Inserting data inside the Intent
intentService.putExtra(NotificationsIntentService.EXTRA_NOTIF, new Intent(context, TriggeredActivity.class));
startWakefulService(context, intentService);
}
NotificationsIntentService.class
public class NotificationsIntentService extends IntentService {
private static final String TAG = "DebugNotifIntent";
public static final String EXTRA_NOTIF = "extra_notif";
public NotificationsIntentService(){
super(NotificationsIntentService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent: ");
Intent extraIntent = intent.getParcelableExtra(EXTRA_NOTIF);
extraIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(extraIntent);
NotificationWakefulBroadcastReceiver.completeWakefulIntent(intent);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
}
I have managed to find a solution for my problem. I am now using a Messenger for message based cross process communication between intent service & triggered activity.
I am passing a handler - alarmServiceHandler, from intent service to activity through a messenger.
Handler alarmServiceHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
if(msg.arg1 == 1) {
completedTriggeredActivity = true;
}
}
};
Inside onHandleIntent(), I am passing handler through Messenger object in intent's extra data.
Messenger alarmServiceMessenger = new Messenger(alarmServiceHandler);
Intent activityIntent = new Intent(this, TriggeredActivity.class);
activityIntent.putExtra("AlarmServiceMessenger", alarmServiceMessenger);
activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(activityIntent);
while(!completedTriggeredActivity){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
WakefulBCastReceiver.completeWakefulIntent(intent);
In TriggeredActivity, I am retrieving messenger in Dismiss button's OnClickListener, just before calling finish() on the activity. And sending back a message to AlarmService with arg = 1, implying end of processing in triggered activity.
buttonDismiss.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Messenger alarmServiceMessenger = getIntent().getParcelableExtra("AlarmServiceMessenger");
Message alarmServiceMessage = Message.obtain();
alarmServiceMessage.arg1 = 1;
try {
alarmServiceMessenger.send(alarmServiceMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
finish();
}
After starting triggered activity, I am putting AlarmService in sleep mode till boolean variable completedTriggeredActivity has not been set to true in handleMessage(). Once true, it means triggered activity has finished & now I can proceed with releasing wake lock.
I would be glad to receive comments about my approach & any suggestions towards a better solution to my problem, than the one I have deviced.

creating an Async task inside a service

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)

LocalBroadcastManager.sendBroadcast not triggering BroadcastReceiver onReceive

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

onReceive called many times

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

Categories

Resources