I am struggling with persistent problem with Android app that has MQTT ServiceConnection running on background. When ever I switch to an other application that has fullscreen surface (game, youtube on fullscreen, etc) the application completely freezes when trying to bring it on front again. It even refuses to relaunch if closed from drawer. The app won't reopen unless completely killed. The weird thing is that if I run the application via debugger it works perfectly. It makes the problem difficult to get handle on. I have put on prints on beginning of each life cycle method, even before call to super class method. None of them get printed when the app hangs, which hints that it hangs some where on the system level.
Now if I call stopService at onStop method, it works fine but defeats the purpose of having persistent service on the background. I have called unbindService also on onStop, but it does not help. With all the other application everything works fine, even you tube as long as it is not used in fullscreen.
The dependency to the MQTT library is
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.0.2'
and this is my onStop() method
#Override
protected void onStop() {
FirebaseUserActions.getInstance().end(getIndexApiAction0());
if(mBoundToService) {
try {
unbindService(serviceConnection);
mBoundToService = false;
}
catch (Exception e)
{
e.printStackTrace();
}
}
super.onStop();
}
And the onStart() method would be this:
#Override
protected void onStart() {
Log.d(TAG, "onStart has been called");
super.onStart();
if(!mBoundToService) {
bindService(mqttIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
FirebaseUserActions.getInstance().start(getIndexApiAction());
}
But this never gets called. From the logs I can see that MQTT service is receiving messages and produces no errors. Messages continue to be received even as the application is hanged so the background service is alive and running.
The inlined Service connection class is like this:
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder)
{
mqttService = ((MQTTService.MyBinder) binder).getService();
mBoundToService = true;
Log.d(TAG,"MQTT service has been bound");
Handler handler = getHandler();
//NOTIFY THE LOGIN ACTIVITY THAT THE DATA HAS BEEN ACQUIRED
Message msg = handler.obtainMessage(Utils.HANDLE_MQTT_SERVICE_CONNECTED);
Bundle bundle = new Bundle();
bundle.putString(Utils.KEY_MQTT_SERVICE_BOUND,"Everything is complete");
msg.setData(bundle);
handler.sendMessage(msg);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBoundToService = false;
Log.d(TAG, "MQTT service has been UNbound");
}
};
The MQTT service is started like this from onCreate():
mqttIntent = new Intent(getApplicationContext(), MQTTService.class);
if(!mBoundToService){
Log.d(TAG,"Starting MQTT Intent");
startService(mqttIntent);
Log.d(TAG,"Binding MQTT Service");
bindService(mqttIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
Am I missing something that I should be doing at the onStop() to be able to resume the application after having fullscreen application on front?
Related
As a Unity3D developer, I've created an application and exported it to Android Studio. My client is asking me to make this app go back to foreground after 10 seconds of user's inactivity (in case the user opens another app). I've tried to create a service that is started on the OnPause function of my UnityPlayerActivity. Then the service would detect the user's inactivity and launch my app again (putting it back to foreground). First I've only tried to use Time.Schedule to launch my app after 10 seconds no matter what, but everytime the application is paused (goes to background), it starts the service and then it crashes. The question is: is there a simple way to do this? I'm not an Android Java Developer (only know the basics) and I'm struggling with this part .
I'm trying to create this Service and then I try to start it from the onPause() function in my activity. When I pause the app on my phone the app crashes. Can anyone tell me if I'm on the right way and, please, help me?
public class ReturnToForeground extends Service {
public ReturnToForeground() {
}
// constant
public static final long NOTIFY_INTERVAL = 10 * 1000; // 10 seconds
// run on another Thread to avoid crash
private Handler mHandler = new Handler();
// timer handling
private Timer mTimer = null;
Intent intent = new Intent(this, UnityPlayerActivity.class);
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// cancel if already existed
if (mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
return super.onStartCommand(intent, flags, startId);
}
class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
// do action
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(intent);
}
});
}
}
}
Make a timer for when the app is in the onPause(), when the timer reaches 10 seconds you should pass an intent which will make your app active again (let's say taking the user back to the main view). You can save the current data of your app in something like shared preffs, so that information wont be lost in most situations.
In many cases this problem appears when a resource which you are trying to reload is not active anymore inside the application.
From the info you have shared it seems like you are not starting the service correctly. It would be nice if you can add a crash log so that we can debug it and see where is the problem.
I am working on a wallpaper application in which i am setting a gallery of images on wallpaper with shuffle effect for 5 min, 10 min etc. I am using service for this task. My service works well when app remains in background, but service get stopped when app get stopped.This is my code for service class:
public class WallpaperService extends Service {
ArrayList<String> arrayList;int counter = 0;
boolean serviceStopped;
private IBinder binder = new WallpaperServiceBinder();
public WallpaperService() {
}
private Handler mHandler;
private Runnable updateRunnable = new Runnable() {
#Override
public void run() {
if (serviceStopped == false)
{
createNotificationIcon();
}
queueRunnable();
}
};
public class WallpaperServiceBinder extends Binder {
public WallpaperService getService() {
return WallpaperService.this;
}
}
private void queueRunnable() {
// 600000 : cada 10 minutos, comprueba si hay nuevas notificaciones y actualiza la
// notification BAR
mHandler.postDelayed(updateRunnable, 5000);
}
#Override
public int onStartCommand(Intent intent,int flag, int start_id){
super.onStartCommand(intent,flag,start_id);
arrayList = intent.getStringArrayListExtra("image_url");
return START_STICKY;
}
#Override
public void onRebind(Intent intent) {
Log.v("Service","in onRebind");
super.onRebind(intent);
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public void onCreate() {
serviceStopped = false;
mHandler = new Handler();
queueRunnable();
}
#Override
public void onStart(Intent intent, int startid) {
}
public void createNotificationIcon()
{
counter += 1;
Toast.makeText(this, "Hello", Toast.LENGTH_SHORT).show();
Picasso.with(getApplicationContext()).load(arrayList.get(counter)).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
try {
final WallpaperManager wallpaperManager =
WallpaperManager.getInstance(getApplicationContext());
wallpaperManager.setBitmap(bitmap);
wallpaperManager.suggestDesiredDimensions(1080, 1920);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
//Here you should place a loading gif in the ImageView to
//while image is being obtained.
}
});
}}
This is the code i am using to start service:
Intent intent = new Intent(CategoryActivity.this,WallpaperService.class);
intent.putExtra("image_url",img_urls);
intent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
startService(intent);
bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
Have you added these lines in manifest file
<application> <service android:name=".ExampleService" /></application>
Important Fact about the bindService
If a component calls bindService() to create the service and onStartCommand() is not called, the service runs only as long as the component is bound to it. After the service is unbound from all of its clients, the system destroys it.
Try using Started Service
A started service is one that another component starts by calling
startService(), which results in a call to the service's
onStartCommand() method.
When a service is started, it has a lifecycle that's independent of
the component that started it. The service can run in the background
indefinitely, even if the component that started it is destroyed. As
such, the service should stop itself when its job is complete by
calling stopSelf(), or another component can stop it by calling
stopService().
An application component such as an activity can start the service by
calling startService() and passing an Intent that specifies the
service and includes any data for the service to use. The service
receives this Intent in the onStartCommand() method.
Handling onStartCommand
Notice that the onStartCommand() method must return an integer. The
integer is a value that describes how the system should continue the
service in the event that the system kills it. The default
implementation for IntentService handles this for you, but you are
able to modify it. The return value from onStartCommand() must be one
of the following constants:
START_NOT_STICKY If the system kills the service after onStartCommand() returns, do not recreate the service unless there are
pending intents to deliver. This is the safest option to avoid running
your service when not necessary and when your application can simply
restart any unfinished jobs.
START_STICKY If the system kills the service after onStartCommand() returns, recreate the service and call
onStartCommand(), but do not redeliver the last intent. Instead, the
system calls onStartCommand() with a null intent unless there are
pending intents to start the service. In that case, those intents are
delivered. This is suitable for media players (or similar services)
that are not executing commands but are running indefinitely and
waiting for a job.
START_REDELIVER_INTENT If the system kills the service after onStartCommand() returns, recreate the service and call
onStartCommand() with the last intent that was delivered to the
service. Any pending intents are delivered in turn. This is suitable
for services that are actively performing a job that should be
immediately resumed, such as downloading a file.
Note: In your case you should use Started Service and return START_STICKY or START_REDELIVER_INTENT (based on your requirement) in onStartCommand()
Check Official Documentation for detailed description of the Services.
I was recently fiddling around with the newest Android P version, trying to run a simple Service with the START_STICKY flag.
Basically, this is my setup:
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstance) {
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
}
MyService.java
public class MyService extends Service {
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.d(TAG, "onTaskRemoved()");
}
#Override
public void onLowMemory() {
super.onLowMemory();
Log.d(TAG, "onLowMemory()");
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()");
return START_STICKY;
}
}
Of course, I've added a service entry into the application's AndroidManifest file.
Testing the application on my older phone running Android Nougat, everything works as expected.
This is how the lifecycle looks like after starting the app:
On Android N
onCreate()
onStartCommand()
Now, after swiping off the application from the recents menu:
onTaskRemoved()
onCreate()
onStartCommand()
This is the behavior that I expect. But when I launch the application on my newer phone running Android P DP4 the lifecycle looks like this, when starting the app:
On Android P
onCreate()
onStartCommand()
So far, nothing different. But when I clear the app from the recent menu:
onTaskRemoved()
onCreate()
onDestroy()
Thanks to the START_STICKYflag, the service restarts, but instantly gets destroyed, even before having the chance to run the onStartCommand method.
Are there any changes that I am not aware of? The only changes to something service related that I could find are documented here. And it only describes that a foreground service now needs a specific permission to work. However, I am running a background service, and thus this information seems to be irrelevant to me.
Did anyone experience similar problems?
Thanks in advance!
You're looking in the behavioral changes of the wrong Android version. Android Oreo introduced Background Execution Limits which limits services in the background. TL;DR: Starting a service in the background will throw an IllegalStateException, use Jobs instead.
I have a service declared in manifest like
<service android:name=".services.ScreenOnService" android:process="#string/screenProcess"/>
all the service does is registering for Screen_on broadcast (As i always need the information that the Screen was turned on and not only if my app is running)
#Nullable
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
//All this service has to do is register for the screen on broadcast
//as this one can't be registere in manifest and the ACTION_USER_PRESENT is
//not guaranteed to be fired. (E.g. if no lock screen is used)
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
registerReceiver(screenEventReceiver,filter);
return START_STICKY;
}
#Override
public void onDestroy()
{
unregisterReceiver(screenEventReceiver);
super.onDestroy();
}
I start the service from my Application onCreate
#Override
public void onCreate() {
super.onCreate();
if(!isScreenOnServiceAlreadyRunning())
{
//Start the screen on service
Intent screenOnService = new Intent(this, ScreenOnService.class);
startService(screenOnService);
}
}
Everything is fine as long as the app is running. If I kill the app, the service in it's own process is also killed and I don't get why.
I found a promising article here http://fabcirablog.weebly.com/blog/creating-a-never-ending-background-service-in-android and hoped the best but even if I do this and send a broadcast, it will not work.
Why does the service stop working if the app is killed? I assumed it will keep running, as it's in it's own process. If what I want is not realisable with my approach, what's the best way to do so?
Thanks already.
#Hardcore_Graverobber I think you should start the service as a separate process,
please refer this tutorial
http://www.vogella.com/tutorials/AndroidServices/article.html
I am having a BroadcastReceiver in a Service.
I am registering receiver in service's oncreate() method like,
final MyReceiver myReceiver = new MyReceiver();
#Override
public void onCreate() {
IntentFilter filter = new IntentFilter(SOME_FILTER);
registerReceiver(myReceiver, filter);
}
Then I have created a method to unregister receiver and stop service like,
public void stopService(){
if(myReceiver != null){
try{
unregisterReceiver(myReceiver);
}catch(Exception e){
e.printStackTrace();
}
}
stopSelf();
}
But it does not stop the service. There is no exception, no error. Simply the service doesn't stop.
I have also tried it following way,
public void stopService(){
if(myReceiver != null){
try{
unregisterReceiver(myReceiver);
}catch(Exception e){
e.printStackTrace();
}
}
stopForeground(true);
stopSelf();
}
By doing this the Notification of Service being run in foreground hides but service's onDestroy() is not being called.
I also tried to put the code to unregister receiver in onDestroy() but after calling stopSelf() method onDestroy() is never called.
If I don't register the BroadcastReceiver in the service, everything works perfectly fine, service stops and onDestroy() gets called but when I register receiver then it doesn't stop.
Any ideas what's going on here?
Edit
This is how I am binding and starting the service
Intent serviceIntent = new Intent(MainActivity.this, MyService.class);
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
startService(serviceIntent);
And this is mConnection
MyService myService;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service){
LocalBinder binder = (LocalBinder) service;
myService = binder.getService();
isBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
Below is how I am unbinding the service and stopping it.
if(isBound){
unbindService(mConnection);
isBound = false;
}
myService.stopService();
myService = null;
While a Service is bound, it will never be destroyed.
http://developer.android.com/reference/android/app/Service.html
A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy() method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy().
While it is perfectly OK to have a Service that is both, bound and started, it makes for iffy lifecycle management issues (as you've just found out). If possible, you should decide if you need loose or tight coupling of your Service and then use a started or bound Service respectively. This will make your life easier.
Just found a solution of the same by hit and trial method.
I shifted the code to unregister the receiver in onDestroy() method and all worked.
#Override
public void onDestroy() {
super.onDestroy();
if(myReceiver != null){
try{
unregisterReceiver(myReceiver);
}catch(Exception e){
e.printStackTrace();
}
}
}
I think problem was occurring because I was trying to unregister the receiver before stopping the service.