Android: Service is killed and restarted after a while - android

I know that is a well known subject, but I have tried lot of things. I have an simple application, dedicated to a specific user, application has an mainActivity which is displaying some status on screen and it's starting two services, one is making request from a server (at every 5 minutes) and one which is sending sms and replay to server (at every ten minutes).
The application is running on a Samsung pocket 2 with Android 4.4.2, this device is used only for this application. While the device is connected to ADB the services are working just fine, but if I disconnect the phone and let it running normally, the services are killed repeatable and restarted after a while. The messaged are send with very much delay. I would be thankful for any suggestions.
Here is my code:
Main activity:
public class MainActivity extends Activity {
private TextView _internet;
private TextView _signal;
private TextView _server;
private BroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
IntentFilter intentFilter = new IntentFilter(Constants.SS);
receiverWorker();
registerReceiver(receiver, intentFilter);
startService(new Intent(this, RefreshDBService.class));
startService(new Intent(this, SmsService.class));
}
private void receiverWorker() {
receiver = new BroadcastReceiver() {
public void onReceive(Context arg0, Intent arg1) {
checkState();
}};
}
public void refreshButonClicked(View v) {
checkState();
}`
Here is my first service:
public class RefreshDBService extends Service {
private Thread _backgroundWork;
private ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
private DataBaseOperations _dataSource;
#Override
public void onCreate() {
super.onCreate();
_dataSource = new DataBaseOperations(this);
_backgroundWork = new Thread(new Runnable() {
#Override
public void run() {
if(Checks.checkInternetConnection(getApplicationContext())){
if(ServerOperations.isServerAvailable(getApplicationContext())){
String inputData = ServerOperations.makeRequest(Constants.GET_DATA_ROUTE, ServerOperations.getMessagesFromServer(getApplicationContext()));
ArrayList<DataSmsObj> dataFromServer=null;
if(inputData!=null && !inputData.isEmpty()){
dataFromServer = ServerOperations.fromJsonToObjects(inputData);
if(dataFromServer.size()>0){
_dataSource.open();
_dataSource.insertDataFromServer(dataFromServer);
_dataSource.close();
}
}
System.out.println("check server for messages in pending status, received -> "+ dataFromServer.size());
}else{
System.out.println("no server");
sentErrorToUI(Constants.NO_SERVER);
}
}else{
System.out.println("no internet");
sentErrorToUI(Constants.NO_INTERNET);
}
}
});
}
public int onStartCommand(Intent intent, int flags, int startId) {
scheduleTaskExecutor.scheduleWithFixedDelay(_backgroundWork, 0, Constants.NEXT_CYCLE/2, TimeUnit.MINUTES);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
scheduleTaskExecutor.shutdownNow();
}
public IBinder onBind(Intent intent) {
return null;
}
private void sentErrorToUI(String message){
Intent intent = new Intent(Constants.SS);
intent.putExtra(Constants.SS, message);
System.out.println("trimit" +message);
sendBroadcast(intent);
}
}
And this is the second one:
public class SmsService extends Service {
private Thread _backgroundWork;
private ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
private DataBaseOperations _dataSource;
#Override
public void onCreate() {
super.onCreate();
_dataSource = new DataBaseOperations(this);
_backgroundWork = new Thread(new Runnable() {
#Override
public void run() {
sendFeedbackToServer();
List<DataSmsObj> dataToSent = new ArrayList<DataSmsObj>();
_dataSource.open();
dataToSent = _dataSource.getDataToSent();
_dataSource.close();
System.out.println("messages to sent: "+ dataToSent.size());
for (int i = 0; i < dataToSent.size(); i++) {
//here the messages are send, the code is to long to put it here, but if is need i can do it afterwards
}
}
});
}
public int onStartCommand(Intent intent, int flags, int startId) {
scheduleTaskExecutor.scheduleWithFixedDelay(_backgroundWork, 0, Constants.NEXT_CYCLE, TimeUnit.MINUTES);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
scheduleTaskExecutor.shutdownNow();
public IBinder onBind(Intent intent) {
return null;
}

If you are using a background Service with a scheduled task, it could be killed by the system. The only way to prevent the killing is a foreground Service. Quoting the documentation:
A foreground service is a service that the user is actively aware of and is not a candidate for the system to kill when low on memory.
You have to call the method startForeground() inside your Service using a Notification to show it. For further information you can check: https://developer.android.com/guide/components/services.html#Foreground
By the way, I recommend you to use the new JobScheduler api above api 21.
https://developer.android.com/reference/android/app/job/JobScheduler.html

Android kills service based on priority stack.
Android: keeping a background service alive (preventing process death)
What is START_STICKY,START_NOT_STICKY and START_REDELIVER_INTENT Service
Above links might help you.

Your devices will sleeps if it is unplugged from computer . So, the solutions :
Use startForeground method to prevent service to be killed and/or use AlarmManager in order to charge event.
It is possible to use start_stiky flag but it just restarts the process if it killed by system.

Related

What kind of services should I use for accessing sensors data in background?

I successfully used a service to do a certain task in the foreground. Now, to do it in the background, I'd remove the handler.removeCallbacks method in onDestroy().
But this would also prevents me from stopping the service using stopService(intent).
I saw on the official docs that I should maybe use JobScheduler (as I target API 28).
Here is a more precise indication of my code :
public class MainActivity {
private Intent intent;
onCreate() {
if (intent == null) {
intent = new Intent(this, MyService.class);
}
}
startService(intent);
... // Then is some code to stop the service if needed with stopService(intent)
}
--------------------------------------------------------------
public class myService {
private Handler handler = null;
private static Runnable runnable = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
handler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
System.out.println("Running service times " + i);
i++;
handler.postDelayed(runnable, 1000);
}
};
handler.post(runnable);
}
#Override
public void onDestroy() {
handler.removeCallbacks(runnable);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
I would like it to run in the background (even if the device is locked) but still being able to disable the service (or JobScheduler?).
What are your suggestions?
you can use work manager
or job dispatcher
and there is a lot of options like
SyncAdapter, Bound services, Intent Service
you can use one of these options according to your need

Run a service in background continuously

Run a service in background continuously. For example, a service has to be kicked off which will display a toast message 20 seconds once even if the app is closed.
public class AppService extends IntentService {
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public AppService() {
super("AppService");
}
#Override
protected void onHandleIntent(Intent workIntent) {
Toast.makeText(getApplicationContext(), "hai", Toast.LENGTH_SHORT).show();
SystemClock.sleep(20000);
}
}
Below code works for me...
public class AppService extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, " MyService Created ", Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, " MyService Started", Toast.LENGTH_LONG).show();
return START_STICKY;
}
}
Accepted answer will not work on from Android 8.0 (API level 26), see the android's background limitations here
Modification in Accepted Answer:
1: You have to invoke the service's startForeground() method within 5 seconds after starting the service. To do this, you can call startForeground() in onCreate() method of service.
public class AppService extends Service {
....
#Override
public void onCreate() {
startForeground(9999, Notification())
}
....
}
2: You must call startForegroundService() instead of startService() by checking API level from where you want to start the service.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
This code work for me..
public class ServiceClass extends Service {
public static final int notify = 300000; //interval between two services(Here Service run every 5 Minute)
private Handler mHandler = new Handler(); //run on another Thread to avoid crash
private Timer mTimer = null; //timer handling
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
if (mTimer != null) // Cancel if already existed
mTimer.cancel();
else
mTimer = new Timer(); //recreate new
mTimer.scheduleAtFixedRate(new TimeDisplay(), 0, notify); //Schedule task
}
#Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel(); //For Cancel Timer
Log.d("service is ","Destroyed");
}
//class TimeDisplay for handling task
class TimeDisplay extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
Log.d("service is ","running");
}
});
}
}
}
In your manifest, where you declare your service, add:
android:process=":processname"
This lets the service run on a separate process and thus it will not be killed with the app.
You can then chose if you want to use foreground. It will show a persistent notification, but reduces the likelihood if the service being killed.
Further, if you want to create a continuously running service, use Service, NOT IntentService. IntentService stops when it is finished doing its action.

How do I stop my thread and will my service stop too if I do?

I'm currently working on my first android app and I've run into a problem.
My app is supposed to be counting in the background using a Service and I'm creating a new thread to handle that. If I don't stop the thread in my Service's onDestroy() method, my phone gives me the message "Unfortunately, (my app) has stopped." every time I close the app. I need to stop it somehow, and I tried to do it using :
while(!Thread.currentThread().isInterrupted()){
**my code**
}:
And then interrupting it in the onDestroy() method.
It works, but it makes my app count extremely fast, so I would like to know if it can be done any other way that does not change the functionaliy of my code.
Also, since my thread gets stopped in the onDestroy method, I guess my service stops as well. Is there any way to keep my service running even when my app has been closed?
Here's my code:
public class CounterService extends Service {
private Handler handler;
private int time = -1;
private boolean isActive;
private Intent timeBroadcaster;
private Runnable counter;
private Thread serviceCounter;
#Override
public void onCreate(){
super.onCreate();
handler = new Handler();
timeBroadcaster = new Intent();
timeBroadcaster.setAction("EXAMPLE_BROADCAST");
counter = new Runnable() {
#Override
public void run() {
isActive = ((PowerManager) getSystemService(Context.POWER_SERVICE)).isInteractive();
if (isActive) {
handler.postDelayed(this, 1000);
time += 1;
} else {
if (time > 5) {
//log
}
time = 0;
handler.postDelayed(this, 1000);
}
timeBroadcaster.putExtra("counter", time);
sendBroadcast(timeBroadcaster);
}
};
serviceCounter = new Thread(counter);
serviceCounter.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy(){
//serviceCounter.interrupt();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Is there any way to keep my service running even when my app has been closed?
you can use sync adapter which runs in background even app is stoped.
https://developer.android.com/training/sync-adapters/creating-sync-adapter.html

OnDestroy restarts service, how can I destroy my activity without killing or restarting the service?

I'm writting an app that pops up notifications from time to time.
a service is running in the background, and when I kill the app the service is restarted and a notification pops up, but I don't want this to happen.
I want the service to stay there quiet and be executed at the right time.(I'm using a TimerTask)
I don't want to kill or restart the service, I want it to stay there quiet.
when i kill the app the service is restarted and a notification pops up, but i don't want this to happen
In your service's onStartCommand() method, return START_NOT_STICKY.
(and I so wish that this were the default...)
i want the service to stay there quiet and be executed at the right time.(I'm using a TimerTask)
Use AlarmManager to arrange to get executed at the right time; do not use a TimerTask in a running service. Only have a service running when it is actively delivering value to the user. Watching the clock tick is not actively delivering value to the user.
I faced the same issue and resolved after reading the documentation,dozen of stack overflows, and blog posts. I created a background service and made it foreground to prevent it from restarting if the app(process) closed or opened--to prevent the data lose from the service. but again, there was persistent notification produced which was unmovable(I hated it). I wanted to remove this notification along with service started. then started surfing on updating the notification and there I found a question directed me to the documentation of updating notification. I read that and update foreground service notification and vola it worked like charm. I'm giving the complete code here.
Main Activity
public class MainActivity extends AppCompatActivity {
TextView textView;
Context context = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.time);
Intent background = new Intent(context,TimeBroadCast.class);
context.startService(background);
LocalBroadcastManager.getInstance(this).registerReceiver(
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int message = intent.getIntExtra(UpdatTime.timUpdate,0);
textView.setText(String.valueOf(message));
}
}, new IntentFilter(UpdatTime.ACTION_LOCATION_BROADCAST)
);
}
}
Service class
public class TimeBroadCast extends Service {
private boolean isRunning;
private Context context;
UpdatTime updatTime;
Timer timer;
#Override
public void onCreate() {
this.context = this;
this.isRunning = false;
timer = new Timer();
updatTime = new UpdatTime(this);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
StartForground();
Notification notification = new NotificationCompat.Builder(this).build();
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager nMgr = (NotificationManager) getApplicationContext().getSystemService(ns);
nMgr.notify(101,notification);
nMgr.cancel(101);
return START_STICKY;
}
#Override
public void onDestroy() {
StopForgroudn();
super.onDestroy();
}
private void StartForground() {
if(!isRunning) {
isRunning = true;
timer.schedule(updatTime, 0, 1000);
}
Notification notification = new NotificationCompat.Builder(this)
.setOngoing(false)
.setSmallIcon(android.R.color.transparent)
.build();
startForeground(101, notification);
}
private void StopForgroudn()
{
timer.cancel(); // Terminates this timer, discarding any currently scheduled tasks.
timer.purge(); // Removes all cancelled tasks from this timer's task queue.
stopForeground(true);
stopSelf();
}
}
TimerTaks class
public class UpdatTime extends TimerTask {
static String timUpdate = "timecountdown", ACTION_LOCATION_BROADCAST = TimeBroadCast.class.getName() + "TimeBroadCast";
Context myContext;
int i = 0;
public UpdatTime(Context myContext) {
this.myContext = myContext;
}
#Override
public synchronized void run() {
try {
i += 1;
Log.v("Data1", ""+i);
Intent intent = new Intent(ACTION_LOCATION_BROADCAST);
intent.putExtra(timUpdate,i);
LocalBroadcastManager.getInstance(myContext).sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Hops this may helps.
Sorry for the improper format of the code....

Communication between Activity and Service

I am trying to make my own MusicPlayer for android. Where i came to a problem is running some things in background. Main activity manages GUI and up to now all the songs are playing. I wanted to separate GUI and music playing classes. I want to put music managing part in Service and leave other things as they are now.
My problem is that i can't organize communication between Activity and Service as lot of communication is happening between them including moving objects in both directions. I tried many techniques that I searched here on Stack Overflow but every time I had problems. I need Service to be able to send objects to Activity and vice versa. When I add widget i also want it to be able to communicate with Service.
Any tips are appreciated, if you need source code place comment bellow but now in this transition it became chaotic.
Is there any more advanced tutorial on this than calling one method that returns random number from service? :P
EDIT: Possible solution is to use RoboGuice library and move objects with injection
I have implemented communication between Activity and Service using Bind and Callbacks interface.
For sending data to the service I used Binder which retruns the Service instace to the Activity, and then the Activity can access public methods in the Service.
To send data back to the Activity from the Service, I used Callbacks interface like you are using when you want to communicate between Fragment and Activity.
Here is some code samples for each:
The following example shows Activity and Service bidirectional relationship:
The Activity has 2 buttons:
The first button will start and stop the service.
The second button will start a timer which runs in the service.
The service will update the Activity through callback with the timer progress.
My Activity:
//Activity implements the Callbacks interface which defined in the Service
public class MainActivity extends ActionBarActivity implements MyService.Callbacks{
ToggleButton toggleButton;
ToggleButton tbStartTask;
TextView tvServiceState;
TextView tvServiceOutput;
Intent serviceIntent;
MyService myService;
int seconds;
int minutes;
int hours;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serviceIntent = new Intent(MainActivity.this, MyService.class);
setViewsWidgets();
}
private void setViewsWidgets() {
toggleButton = (ToggleButton)findViewById(R.id.toggleButton);
toggleButton.setOnClickListener(btListener);
tbStartTask = (ToggleButton)findViewById(R.id.tbStartServiceTask);
tbStartTask.setOnClickListener(btListener);
tvServiceState = (TextView)findViewById(R.id.tvServiceState);
tvServiceOutput = (TextView)findViewById(R.id.tvServiceOutput);
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
Toast.makeText(MainActivity.this, "onServiceConnected called", Toast.LENGTH_SHORT).show();
// We've binded to LocalService, cast the IBinder and get LocalService instance
MyService.LocalBinder binder = (MyService.LocalBinder) service;
myService = binder.getServiceInstance(); //Get instance of your service!
myService.registerClient(MainActivity.this); //Activity register in the service as client for callabcks!
tvServiceState.setText("Connected to service...");
tbStartTask.setEnabled(true);
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Toast.makeText(MainActivity.this, "onServiceDisconnected called", Toast.LENGTH_SHORT).show();
tvServiceState.setText("Service disconnected");
tbStartTask.setEnabled(false);
}
};
View.OnClickListener btListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if(v == toggleButton){
if(toggleButton.isChecked()){
startService(serviceIntent); //Starting the service
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE); //Binding to the service!
Toast.makeText(MainActivity.this, "Button checked", Toast.LENGTH_SHORT).show();
}else{
unbindService(mConnection);
stopService(serviceIntent);
Toast.makeText(MainActivity.this, "Button unchecked", Toast.LENGTH_SHORT).show();
tvServiceState.setText("Service disconnected");
tbStartTask.setEnabled(false);
}
}
if(v == tbStartTask){
if(tbStartTask.isChecked()){
myService.startCounter();
}else{
myService.stopCounter();
}
}
}
};
#Override
public void updateClient(long millis) {
seconds = (int) (millis / 1000) % 60 ;
minutes = (int) ((millis / (1000*60)) % 60);
hours = (int) ((millis / (1000*60*60)) % 24);
tvServiceOutput.setText((hours>0 ? String.format("%d:", hours) : "") + ((this.minutes<10 && this.hours > 0)? "0" + String.format("%d:", minutes) : String.format("%d:", minutes)) + (this.seconds<10 ? "0" + this.seconds: this.seconds));
}
}
And here is the service:
public class MyService extends Service {
NotificationManager notificationManager;
NotificationCompat.Builder mBuilder;
Callbacks activity;
private long startTime = 0;
private long millis = 0;
private final IBinder mBinder = new LocalBinder();
Handler handler = new Handler();
Runnable serviceRunnable = new Runnable() {
#Override
public void run() {
millis = System.currentTimeMillis() - startTime;
activity.updateClient(millis); //Update Activity (client) by the implementd callback
handler.postDelayed(this, 1000);
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Do what you need in onStartCommand when service has been started
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//returns the instance of the service
public class LocalBinder extends Binder{
public MyService getServiceInstance(){
return MyService.this;
}
}
//Here Activity register to the service as Callbacks client
public void registerClient(Activity activity){
this.activity = (Callbacks)activity;
}
public void startCounter(){
startTime = System.currentTimeMillis();
handler.postDelayed(serviceRunnable, 0);
Toast.makeText(getApplicationContext(), "Counter started", Toast.LENGTH_SHORT).show();
}
public void stopCounter(){
handler.removeCallbacks(serviceRunnable);
}
//callbacks interface for communication with service clients!
public interface Callbacks{
public void updateClient(long data);
}
}
Update: July 10 2016
IMO I think using BroadcastReceiver for custom events is better way
as the Messengers mentioned don't handle activity recreation on device
rotation as well as possible memory leaks.
You may create custom BroadCast Receiver for events in the activity, Then you may also use Messengers.
In your Activity
create a MessageHandler class as
public static class MessageHandler extends Handler {
#Override
public void handleMessage(Message message) {
int state = message.arg1;
switch (state) {
case HIDE:
progressBar.setVisibility(View.GONE);
break;
case SHOW:
progressBar.setVisibility(View.VISIBLE);
break;
}
}
}
Now you can have it's instance as
public static Handler messageHandler = new MessageHandler();
Start your Service with this Handler object as an extra data as
Intent startService = new Intent(context, SERVICE.class)
startService.putExtra("MESSENGER", new Messenger(messageHandler));
context.startService(startService);
In your Service you receive this object from the intent and initialize the Messenger variable in Service as
private Messenger messageHandler;
Bundle extras = intent.getExtras();
messageHandler = (Messenger) extras.get("MESSENGER");
sendMessage(ProgressBarState.SHOW);
And then write a method sendMessage to send messages to activity.
public void sendMessage(ProgressBarState state) {
Message message = Message.obtain();
switch (state) {
case SHOW :
message.arg1 = Home.SHOW;
break;
case HIDE :
message.arg1 = Home.HIDE;
break;
}
try {
messageHandler.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
The sample code above shows and hides a ProgressBar in Activity as messages are received from Service.
Intents are good solution for communication between Activitiy and Service.
A fast solution for receive intents in your service is subclassing IntentService class. It handles asynchronous requests expressed as Intents using a queue and worker thread.
For communication from service to Activity you can broadcast the intent but instead of using normal sendBroadcast() from Context, a more efficent way is to use LocalBroadcastManager from support library.
Example service.
public class MyIntentService extends IntentService {
private static final String ACTION_FOO = "com.myapp.action.FOO";
private static final String EXTRA_PARAM_A = "com.myapp.extra.PARAM_A";
public static final String BROADCAST_ACTION_BAZ = "com.myapp.broadcast_action.FOO";
public static final String EXTRA_PARAM_B = "com.myapp.extra.PARAM_B";
// called by activity to communicate to service
public static void startActionFoo(Context context, String param1) {
Intent intent = new Intent(context, MyIntentService.class);
intent.setAction(ACTION_FOO);
intent.putExtra(EXTRA_PARAM1, param1);
context.startService(intent);
}
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_FOO.equals(action)) {
final String param1 = intent.getStringExtra(EXTRA_PARAM_A);
// do something
}
}
}
// called to send data to Activity
public static void broadcastActionBaz(String param) {
Intent intent = new Intent(BROADCAST_ACTION_BAZ);
intent.putExtra(EXTRA_PARAM_B, param);
LocalBroadcastManager bm = LocalBroadcastManager.getInstance(this);
bm.sendBroadcast(intent);
}
}
Example Activity
public class MainActivity extends ActionBarActivity {
// handler for received data from service
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(MyIntentService.BROADCAST_ACTION_BAZ)) {
final String param = intent.getStringExtra(EXTRA_PARAM_B);
// do something
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter();
filter.addAction(MyIntentService.BROADCAST_ACTION_BAZ);
LocalBroadcastManager bm = LocalBroadcastManager.getInstance(this);
bm.registerReceiver(mBroadcastReceiver, filter);
}
#Override
protected void onDestroy() {
LocalBroadcastManager bm = LocalBroadcastManager.getInstance(this);
bm.unregisterReceiver(mBroadcastReceiver);
super.onDestroy();
}
// send data to MyService
protected void communicateToService(String parameter) {
MyIntentService.startActionFoo(this, parameter);
}
}
I think there is a problem with the correct answer. I have not enough reputation to comment on it.
Right in the answer:
Activity call bindService() to get pointer to Service is ok. Because service context is maintained when connection is maintained.
wrong in the answer:
service pointer to Activity class to call back is bad way. Activity instance maybe not null during Activity context is being Release => exception here.
solution for the wrong in the answer:
service send intent to Activity. and Activity receiver intent via BroadcastReceiver.
Note:
in this case, Service and Activity in the same Process, you should use LocalBroadcastManager to send intent. It make performance and security better
This is a simple example of communication between activity and service
Activity
MyReceiver myReceiver; //my global var receiver
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layourAwesomexD);
registerReceiver();
}
//When the activity resume, the receiver is going to register...
#Override
protected void onResume() {
super.onResume();
checkStatusService(); // verficarStatusServicio(); <- name change
registerReceiver();
}
//when the activity stop, the receiver is going to unregister...
#Override
protected void onStop() {
unregisterReceiver(myReceiver); //unregister my receiver...
super.onStop();
}
//function to register receiver :3
private void registerReceiver(){
//Register BroadcastReceiver
//to receive event from our service
myReceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(MyService.SENDMESAGGE);
registerReceiver(myReceiver, intentFilter);
}
// class of receiver, the magic is here...
private class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
//verify if the extra var exist
System.out.println(arg1.hasExtra("message")); // true or false
//another example...
System.out.println(arg1.getExtras().containsKey("message")); // true or false
//if var exist only print or do some stuff
if (arg1.hasExtra("message")) {
//do what you want to
System.out.println(arg1.getStringExtra("message"));
}
}
}
public void checkStatusService(){
if(MyService.serviceStatus!=null){
if(MyService.serviceStatus == true){
//do something
//textview.text("Service is running");
}else{
//do something
//textview.text("Service is not running");
}
}
}
Service
public class MyService extends Service {
final static String SENDMESAGGE = "passMessage";
public static Boolean serviceStatus = false;
#Override
public void onCreate() {
super.onCreate();
serviceStatus=true;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {return null;}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//you service etc...
passMessageToActivity("hello my friend this an example of send a string...");
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
passMessageToActivity("The service is finished, This is going to be more cooler than the heart of your ex...");
System.out.println("onDestroy");
serviceStatus=false;
}
private void passMessageToActivity(String message){
Intent intent = new Intent();
intent.setAction(SENDMESAGGE);
intent.putExtra("message",message);
sendBroadcast(intent);
}
}
if we don't unregister BroadcastReceiver we will have an error, you need to unregister when the activity go onPause, onStop, onDestroy...
if you don't register BroadcastReceiver when you back to activity, it will not listen anything from the service... the service will send information to BroadcastReceiver but it will not receive anything because it isn't registered.
When you create more than one service, the following services are going to begin in onStartCommand.
You can pass information to service with intent and you get it in onStartCommand
Difference about return in onStartCommand: Difference between START_STICKY and START_REDELIVER_INTENT? and check the official website of google: Services
The best way in this case is to communicate by doing broadcasting from your service for different actions and receiving it in your activity. You can create a custom broadcast and send some codes defining specific events like complete, change, prepare etc...
Most easy and efficient way will be using EventBus from GreenRobot.
Use simple 3 steps:
1 Define events
public static class MessageEvent { /* Additional fields if needed */ }
2 Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle:
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
3 Post events:
EventBus.getDefault().post(new MessageEvent());
Very easy yet powerful way is to use EventBus you can add it to your gradle build and enjoy the easy publisher/subscriber pattern .

Categories

Resources