Android: Broadcast Receiver and Service issues - android

I have written a simple activity to test out services and broacast receivers and a service to go along with it. In order to know whether or not it's working I've set up a Toast within the main activity to be showed once the OnReceive() method is called. But for the life of me I can't get this to work.
These are the codes:
public class ServicesAndBroadcastIntentActivity extends Activity {
private Toast test;
private Intent intent;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intent = new Intent(this,serviceD.class);
test = Toast.makeText(this,"Test",Toast.LENGTH_LONG);
test.setGravity(Gravity.CENTER,0,0);
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
test.setText((intent.getStringExtra("EXTRA_MSG")));
test.show();
}
};
#Override
public void onResume(){
super.onResume();
startService(intent);
registerReceiver(broadcastReceiver, new IntentFilter(serviceD.BROADCAST_ACTION));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
stopService(intent);
}
}
public class serviceD extends Service{
private Intent intent;
static final String BROADCAST_ACTION = "com.mejg.ServicesAndBroadcastIntent";
public void onCreate() {
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
}
public void onStart(){
intent.putExtra("EXTRA_MSG","hola");
sendBroadcast(intent);
stopSelf();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}

You are calling startService() before registerReceiver(). Both are asynchronous operations, but they will still likely occur in sequence. Hence, onStart() of your service will be called before registerReceiver() does its work, which means your broadcast goes out before your receiver is set up.
For this sort of experimentation, I recommend setting up a basic UI (e.g., one really big button) and doing the startService() call when the button is pressed.
Also, since the service calls stopSelf(), you do not need to call stopService() from the activity.
Also also, you might consider using LocalBroadcastManager for this -- same basic syntax with better performance and security, since it all stays within your process.
UPDATE
Also also also, onStart() has been deprecated for two-plus years, and your method signature for it is wrong, anyway. Please use onStartCommand(), with the right parameters.
Also also also also, use #Override when overriding methods, to help you catch these sorts of problems.

Related

service does not listen to certain broadcasts

My service:
#Override
public void onCreate() {
if (debug_mode) {Log.i(TAG,"onCreate");}
super.onCreate();
// set receivers
m_filter.addAction("PREPARE_AUDIO");
m_receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (debug_mode) {Log.i(TAG,"broadcast received: " + intent.getAction());}
if (intent.getAction().equals("PREPARE_AUDIO")) {
set_up_audio();
}
}
};
registerReceiver(m_receiver, m_filter);
}
and my activity:
#Override
protected void onStart() {
super.onCreate(savedInstanceState);
if (debug_mode) Log.i(TAG, "onCreate");
setContentView(R.layout.activity_guide);
// start service
startService(new Intent(this, PlayerService.class));
}
#Override
protected void onStart() {
if (debug_mode) {Log.i(TAG,"onStart");}
super.onStart();
// prepare audio
Intent intent = new Intent();
intent.setAction("PREPARE_AUDIO");
sendBroadcast(intent);
}
This won't trigger the BroadcastReceiver in my service. It won't trigger it either if I put the code on onCreate or onResume. It will trigger it, however, if put e.g. on some Listener associated with a Button, or in the activity's onStop callback. Why is that?
Rather than try to send a broadcast right away, just have the service do its setup work in its onCreate() or onStartCommand() method.
Note that using system broadcasts for this is a fairly bad idea, unless your service is in a separate process from your UI. Even then, you need to think through the security, as any app can tell your service what to do, by sending it broadcasts.
If your service and UI will be in the same process, use an in-process event bus (e.g., LocalBroadcastManager, greenrobot's EventBus), not only for improved security, but for better performance.

Broadcast receiver not working in some cases

So i have this receiver in my Fragment.class
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WeekplanHepler.ACTION_SERVICE_BINDED) && getUpdateService() != null) {
getCounts();
}
if (intent.getAction().equals(Helper.UpdateCounts)) {
HashMap<String, Integer> counts = (HashMap<String, Integer>) intent.getSerializableExtra(Helper.PARAM_LIST_COUNTS);
// Updating counts
}
}
};
For registering/uregistering this receiver i'm using this code:
#Override
public void onStart() {
super.onStart();
getCounts(true);
getActivity().registerReceiver(receiver, getIntentFilter());
}
#Override
public void onStop() {
super.onStop();
getActivity().unregisterReceiver(receiver);
}
getCounts() is a RetrofitRequest puted in UpdateService, which is getUpdateService() here
So, when retrofit request has been finished, it returns counts through Intent and then, as you see, i'm updating them. But if i go to next Activity and then returns, request will work fine, and it will send intent, but receiver wont get it. I think this can be caused by method service is binded in first place. So i have BaseFragment, which binds service for all Fragments needed
public abstract class BaseFragment<T> extends CustomListFragment<T> {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().getApplicationContext().bindService(new Intent(getActivity().getApplicationContext(),
WeekplanUpdateService.class), connection, Context.BIND_AUTO_CREATE);
}
}
When i go to next activity, it fragment will bind service, and my previous fragment will call request again, and will have counts. Maybe receiver has some limitations for how much he can get same intents, but i don't think so. Please help
Oh, i forgot to mention how i'm sending intent
sendBroadcast(new Intent(Helper.UpdateCounts).putExtra(Helper.PARAM_LIST_COUNTS, counts));
So, when i've started to use
sendStickyBroadcast(new Intent(Helper.UpdateCounts)
.putExtra(Helper.PARAM_LIST_COUNTS, counts));
instead of
sendBroadcast(new Intent(Helper.UpdateCounts)
.putExtra(Helper.PARAM_LIST_COUNTS, counts));
it worked.

How should I implement this secondary thread to avoid errors? (Android)

I am implementing in my Android app a splash screen which:
dowloads a sqlite database from a server
loads urls to get JSONs
creates a sqlite database in the device and execute several queries
I am using AsyncTask to do everything, my problem will occur if the user close the app in the middle of the process or turn off the device because the app:
could be creating a database or executing crucial queries in the device
could be downloading the sqlite db from a server
could be running several important process
etc
Definitely, the entire process (3-5 seconds) is important.
So... How could I avoid this? should I use handlers, loaders, on-(pause, stop, destroy) methods in order to get my objective? Can you give me an example?
As mentioned in the comment above, you should use a service as their lifecycle is separate to that of the activity.
Create the service like so:
public class MyService extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Do everything you need to here, then call stop:
Log.d("DEBUG", "Started...");
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
Intent intent = new Intent("com.example.androidexample.SERVICE_STOPPING");
sendBroadcast(intent);
super.onDestroy();
}
}
Then in the activity:
public class MainActivity extends Activity {
private ServiceCompleteReceiver receiver;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter;
receiver = new ServiceCompleteReceiver();
filter = new IntentFilter("com.example.androidexample.SERVICE_STOPPING");
startService(new Intent(this, MyService.class));
registerReceiver(receiver, filter);
}
public class ServiceCompleteReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Do whatever needs to be done here
unregisterReceiver(receiver);
}
}
}
EDIT :
Don't forget to add it to your manifest as well
<service
android:name="com.example.androidexample.MyService"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
</service>

How to make a started service continue after the last bound services un-binds

I would like to have a service (doing occasional monitoring) be active continuously. I plan to start it by listening to a BOOT_COMPLETE, which I believe makes it a "Started Service". I want a UI application to bound to it, which is working and documented. However, after the binding activity is destroyed, the Service dies because it's "unbound from all clients".
Is there a way to have a started service allow binding and still continue after the last bound services un-binds?
Returning true from onUnbind() wouldn't help, as the service should continue to be active even if no additional binder exist.
In Android, services are started in one of two ways - through the startService(Intent i) method, or the bindService(Intent i). The method used to start the service determines whether it is started or bound. A service can be started, then bound to a client - or bound and then have calls to start sent to it (it doesn't restart if already started).
As you mention listening for BOOT_COMPLETE, I assume this is an action for an Intent, which is sent via a Broadcast object. This means that you can create an IntentFilter object with the BOOT_COMPLETE action added to it via the addAction(String action) method. Then a BroadcastReceiver object can be created, which upon receiving an intent with an action of BOOT_COMPLETE can then call the startService(Intent i) method (this is done by overriding the onReceive(Context context, Intent intent) method).
If you call startService(Intent i) when the Intent is received, then the service will be a started service. This means that it will only stop when a call to stopService(Intent i) is made by the app, or if the service calls the stopSelf() method. It can be bound and unbound from by multiple activities during the time it is running, and it will not stop (as it is started, not bound).
Here is an example of this, using two Activity objects and a Service:
Activity 1 (first activity of your app):
public class ServiceActivity extends Activity {
private IntentFilter filter = new IntentFilter();
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(action.equals(BOOT_COMPLETE) {
startService(new Intent(ServiceActivity.this, MyService.class));
}
}
};
#Override
protected void onStart() {
super.onStart();
filter.addAction(BOOT_COMPLETE);
registerReceiver(receiver, filter);
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(receiver);
}
//Some other code
}
Activity 2 (used at some point after activity 1):
public class AnotherActivity extends Activity {
private MyService service;
private ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
service = ((MyService.MyBinder)service).getService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}
};
#Override
protected void onStart() {
super.onStart();
bindService(new Intent(this, MyService.class), connection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(connection);
}
//Some other code
}
Service:
public class MyService extends Service {
private MyBinder binder = new MyBinder();
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
//Some other code
final class MyBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
Final notes
To be able to use the service as bound, you need to override the onBind(Intent intent) method, and return an instance of binder MyBinder. Not doing so will result in not being able to bind (the binding sets the service variable by using the getService() method defined in MyBinder).
The BroadcastReceiver must alwasy be unregistered when the Activity it's in closes, as it would be leaked otherwise. That is why in the example, I have registered and unregistered in the onStart() and onStop() methods respectively. Using onDestroy() to unregister is not recommended as it is not always called.
The MyService object that is used when binding must also be unbound when it's Activity closes, as it too can be leaked. It is set to null when onServiceDisconnected(ComponentName name) is called for garbage collecting.
Sources for further reading
https://developer.android.com/reference/android/content/BroadcastReceiver.html
https://developer.android.com/reference/android/app/Activity.html
https://developer.android.com/reference/android/app/Service.html
https://developer.android.com/reference/android/content/ServiceConnection.html

Android Best Practice on Updating the UI from BroadcastReceiver to a certain activity

When i have a broadcastReceiver say android.intent.action.MEDIA_BUTTON and i want to update the current activity's UI without creating a new activity, is there any good practice on this one?
What i know (might not be correct)
1) I can put the BroadcastReceiver in the same class as the activity and call the updateUI function after certain activity
2) Create a ContentObserver?
3) Communicate to a service created by the activity, use aidl. (I dont know how to get the current service if its registered from an activity)
4) Create a custom filter on the broadcastReceiver located on the same class as the activity, and use context.sendBroadcast(msg of custom filter) and in the custom filter call updateUI (same as one but more generic?)
The final flow is it would come from a BroadcastReceiver and ends up updating the UI without renewing the activity (unless the activity is dead?)
Kindly provide links/source code on your how you tackle this kind of problem. Thanks a lot in advance :)
The easiest way to provide this functionality is to put the broadcast receiver in you Activity and bind / unbind it using registerReceiver and unregisterreceiver:
public class MyActivity extends Activity {
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MyActivity.this.receivedBroadcast(intent);
}
};
#Override
public void onResume() {
super.onResume();
IntentFilter iff = new IntentFilter();
iff.addAction("android.intent.action.MEDIA_BUTTON");
// Put whatever message you want to receive as the action
this.registerReceiver(this.mBroadcastReceiver,iff);
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(this.mBroadcastReceiver);
}
private void receivedBroadcast(Intent i) {
// Put your receive handling code here
}
}
Depending on the intent you wish to receive, you may need to add the appropriate permissions to your AndroidManifest.xml file.
What I recently had to do to change a Button's text after receiving data from a LocalBroadcastManager is to store the value in a private field and then do the UI stuff in my onResume() method.
public class myClass extends Activity {
private String myString;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// register to receive data
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter("myAction"));
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// get the extra data included in the intent
myString = intent.getStringExtra("myString");
}
};
#Override
public void onResume() {
super.onResume();
System.out.println("onResume");
// do something to the UI
myButton.setText(myString != null ? myString : "Default");
}
}

Categories

Resources