Android - System.exit(0) and restart activity and service - java

I'm making an Android app, and I need to completely restart the app in a moment. So, to do that, the only solution that has worked (and that I can remember) is to use System.exit(0). I have no idea why I have this code there (I can't remember why I tried it or where I saw it or if it was just an accident), but I know it's working, and I now that I was reviewing the code to apply this on a service, it didn't start the activity I wanted (an activity that would completely stop the app and restart the service from zero - or a service that would do the same thing, but the service isn't called, nor the activity, so I don't know if it works by calling a service or not - an activity i know it works, at least from another activity):
MainActivity.java (in the point I want to restart it)
Intent MainRestarter= new Intent();
MainRestarter.setClass(MainActivity.this, MainRestarter.class);
MainRestarter.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
MainRestarter.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(MainRestarter);
System.exit(0);
MainRestarter.java
Intent MainActivity = new Intent();
MainActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
MainActivity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
MainActivity.setClass(MainRestarter.this, MainActivity.class);
startActivity(MainActivity);
finish();
But I tested and it works too with:
MainActivity.java (in the point I want to restart it)
Intent MainActivity = new Intent();
MainActivity.setClass(MainActivity.this, MainActivity.class);
MainActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
MainActivity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(MainActivity);
System.exit(0);
From an answer on another thread (Difference between finish() and System.exit(0)):
"System.exit(0) - restarts the app with one fewer activity on the stack. So, if you called ActivityB from ActivityA, and System.exit(0) is called in ActivityB, then the application will be killed and started immediately with only one activity ActivityA" - the difference here is that (using the names there) I call the ActivityB from ActivityA, and then I call System.exit(0) on ActivityA, and it restarts with ActivityB. But this doesn't work with a Service no idea why...
I thought this should just stop the entire app, but after reading that answer, it got me confused. Btw, it only works if I the startActivity() is called, or the app will close completely. Can anyone explain me why this code works, and then explain why it doesn't work if I try the exact same code in a Service?
Thanks in advance!
EDIT: I know I can do this calling AlarmManager before System.exit(0), but I'd just like to know why that works, and if I can keep using it instead of AlarmManager (on the MainActivity, since on the service, for some reason the above doesn't work and I'd like also to know why if anyone knows), because I read it consumes more battery.

Related

Dealing with a service after the app was swiped and relaunched

I am working on an audio player app. The user may play the files, and a service is launched to allow them to play them in the background. I allow my service to continue playing the tracks even after the user chooses to swipe the app from the recent list.
Now, if the user swipes the app, the service will continue playing without issues but if the user opens the app using the notification associated with the service, I do not know how to handle this. To my surprise, the app actually continues working with the code above with no issues (as far as I can see).
Is there something I need to do to handle the said case? Do I need a way to reassign the service to the newly launched instance of my app?
Thanks.
Looks like you are already doing it. onStart() you check if the intent is null and if it is, you create a new intent and bind it to a service (if it exists) otherwise create a new service.
Since onStart() is called every time your activity (not application) comes back from background to the foreground (say you launched the setting page and then come back to the main activity), it seems excessive to bind service during onStart(). I would move binding inside onCreate() since onCreate() is only called once for an activity.
Checking for null intent seems weird and maybe redundant, if you move binding inside onCreate(), you can be sure that you are only binding when the activity is launched, and if service already exists, activity will just bind to it.

onTaskRemoved not getting called if the activity started by the service is removed

I am using oreo 8.1.0.
I am facing a weird problem whose solution I can't find on stackoverflow, hence I am writing this question. I know one solution that through foreground service, I can implement it but I don't find notification user friendly in my application context.
I will describe my problem using two cases.
Case 1:
When user opens my app by clicking on the icon and removes it from recent apps, then service automatically restarts. This is fine.
Case 2:
Here my app is closed and is not in recent apps.
When user copies a text, then my service starts one of the activity of my app but when he removes it from the recent apps, then my service gets stopped permanently.
So my problem lies in second case,I don't want my service to get killed. Even if it gets killed I want it to restart.
I tried all the methods mentioned on the stackoverflow like using START_STICKY and onTaskRemoved but I am not able to make it work.
Even I tried killing my activity whenever user clicks on on recent app button and remove it from the recent apps programmatically but this also did not work.
Though this restarts the service even in second case when user kills my app using the back button.
This part of the code is from the activity which opens when user copies some text.
#Override
public void finish() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
super.finishAndRemoveTask();
} else {
super.finish();
}
}
This part of the code is from the service that starts the activity.
#Override
public void onTaskRemoved(Intent rootIntent){
Log.d("testing 12","onTaskRemoved");
Intent restartServiceTask = new Intent(getApplicationContext(),CBWatcherService.class);
restartServiceTask.setPackage(getPackageName());
PendingIntent restartPendingIntent =PendingIntent.getService(getApplicationContext(), 1,restartServiceTask, PendingIntent.FLAG_ONE_SHOT);
AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(this.ALARM_SERVICE);
myAlarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartPendingIntent);
super.onTaskRemoved(rootIntent);
}
#Override
public int onStartCommand(Intent intent,int flag,int startId){
super.onStartCommand(intent, flag, startId);
return START_STICKY;
}
EDIT 1
I just need the service to remain alive.Here are the things that will not hinder the user experience in my app case
1. Killing the activity by yourself programitically when onPause is called so that service does not get killed is acceptable if you make it happen
2. Showing the notification for few second is acceptable
3. Restarting the service is acceptable
From Android Oreo there is a paradigm shift to limit background service execution. It was a frequent criticism affecting battery life, performance and security. As posted in the comments above there are alternative approaches such as JobScheduler.
Refactoring services to the JobScheduler pattern can be quite involved. I advise you look into changing your IntentService to a JobintentService from the Android support v4 library. It uses JobScheduler on Oreo and later targets but reverts to the older IntentService design on older devices. You just need to replace your override of onHandleIntent with onHandleWork in your Service implementation.
Add
android:permission="android.permission.BIND_JOB_SERVICE"
to the service declaration in your AndroidManifest.xml. It can also be useful to add
<uses-permission android:name=”android.permission.WAKE_LOCK” />
But, saying all that, reading through your question, it seems to me your basic complaint is with the cosmetic issue of foreground services requiring a notification. In my view, your solution is either to simply use Context.startForegroundService, or make sure your service is bound. Either way there is visible content to the user that the service is running. You will find it an uphill struggle to try to subvert Android design decisions; better to embrace it - they are wanting you to show these notifications from now on.
Anyway updating your code for newer Android targets is still good practice even if you can't completely avoid those notification icons.
This was the problem
Whenever my service used to start the activity, my service used to get destroyed after the activity used to get started.
Why onTaskRemoved was not working?
The thing I was doing was not working because my service used to get destroyed and hence it was not active to listen to onTaskRemoved.
How I solved it?
The solution to this problem was putting a check in the activity(started by service) to check whether the service is alive or not. As in my case service was getting destroyed. Hence I need to start the service again if the service is not alive.
It even fits the OREO design pattern as we can start the background service when the app is in foreground and the service will stay alive even if the activity gets destroyed.
On Oreo though after sometime service gets destroyed but this is a different problem.
More Info

Q: Android Dev - Single Background Timer in Service plus Action After

Hello,
I've done some research, but to no avail. Also my previous question didn't work as planned.
So here is exactly what I want to do:
1.) On my MainActivity, the User enters a Numerical value in an EditText.
2.) When they press an "OK" Button, it starts a Service to run a Timer for how long they entered.
3.) When the the Timer time runs out, the Service completes some additional Actions.
Questions:
1.) Can I simply use the Button to start the Service via an Intent, then in the Service put the code?
1b.) Can't figure out exactly how to get the User input from the EditText, from within Service.
2.) Can I run the "additional Actions" when the Timer runs out from WITHIN the Service?
2b.) Or, when the Timer is up, do I need to fire a BroadcastReceiver to complete the Actions?
3.) Do I need to add anything special such as Intent-Filters in my Manifest?
Basically, I'm having trouble figuring out what code goes where.
Currently I'm using a combination of Alarm Manager, PendingIntent, and Intent.
Any help would be greatly appreciated, as I've been trying to do this correctly for nearly a month.
I may be somewhat new to programming Android, but I'm eager to learn, so thank you in advance!
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void timerButtonClick(View view) {
EditText timerValue = (EditText) findViewById(R.id.timerValue);
assert timerValue != null;
int timerInt = Integer.parseInt(timerValue.getText().toString());
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent timerIntent = new Intent(this, TimerService.class);
PendingIntent timerPendingIntent = PendingIntent
.getService(this.getApplicationContext(), 234324243, timerIntent, 0);
alarmManager.set(AlarmManager.RTC,
System.currentTimeMillis() + (timerInt * 1000), timerPendingIntent);
finish();
}
}
NOTE: Keep in mind, I'm trying to put the Timer INSIDE my Service, NOT in my Main Activity.. So I assume much of this Code needs to be moved to my Service. But again, not sure exactly how to do this.
Thanks!
1.) Yes you can (see here).
1b.) No you can not. Service has no UI interactions at all, but you can create an activity for "after actions". (Edit: But You can pass EditText data from MainActivity to Service using Intent Extras) (see starting activity from service.)
2.) You can do almost anything or "additional Actions" when the Timer runs out from within the Service, without UI. (see services tutorial)
2b.) No, you dont need that.
3.) It depends on your timer logic, intent-filters are only needed when you are receiving any broadcasts. If you write timer logic by simply taking difference between time, there is no need, but if you do it with something like ACTION_TICK logic which triggers after each minute, you do need to declare intent filter. (see declare action tick intent filter)
You will also need to declare service in AndroidManifest.xml. If your java class name is MyBackgroundService, simply put this in AndroidManifest.xml:
<service android:name=".MyBackgroundService">
</service>
Do ask me if anything remains unclear.
Update:
I myself am in learning phase and one thing I learned is to look at the official docs first. There is a class CountDownTimer in android, which gives you countdown implementation.
use onFinish() of this class to perform whatever action you want to perform.
first argument of constructor is how long you want to run countdown, second is how much time you want for tick() event to occur.
start countdown by calling .start() method.
Update:
For putting extras and start service:
Intent serviceIntent = new Intent(this, MyBackgroundService.class);
String time = editText.getText().toString();
serviceIntent.putExtra("TIME_INTERVAL", time);
startService(serviceIntent);
No need for pending intent. You can start with this:
Create an activity that has : EditText and a Button.
Create onClick button listener code, which will first check the numeric input is correct or not (number format, negative value etc.).
If the input is valid you create an Intent for Service class, add data to intent using intent.putExtra("key","numericValue")
Start service (calling start service method) with intent.
In service class receive data from intent, then do calculation in time difference code.
In service, start a while loop that will check time difference at each loop, and when desired time is elapsed start an activity that will do your action after.
Please note that service class has a bit different implementation than activity class.
If your minimum time difference is in minutes, you can use action tick logic link above to see how you implement a service that can run your logic code every minute. In your case logic is also given in above links (time difference). Also I have provided how you retrieve data from intents.
Please try to dig into some code, then comeback here if you get stuck, I (and we the SO community) will surely help, if you are still stuck, I can only write whole codes on weekends, so you will have to try yourself until then.

How to run activity, if app in background?

I writing the network application and i have a problem with starting activity if the application in background. I want to start activity when some data comes to network. In my Actity A a have a receiver and when it receive some answer from server, it must run the Activity B. But if the App in background, Activity B not starting and metod onCreate() doesn`t execute. It execute only when the user go back to App. But its not really what i want, becouse in Activity B i need to start timer and i neen to enable GPS and some other work. Besides that, Activity B receive some data too, and if B not existing - this receiver will never receive anything.
I tryed IntentServise, but its not working - result the same as without him.
Any ideas? Thanks for any information :-)
Maybe your receiver is not getting intents when your app is background, for example if you're unregistering it in onDestroy method...
try declaring your broadcast receiver in manifest. In broadcast receiver class use starActivity to call act B. This works for me.
If you still have some problems maybe you should provide some source code(for example function where you're working with intents) to clarify your question.
You can't force activity to come back from background. You can use status bar to show notification for a user. Think also about it that this a mobile device, someone can in the middle of conversation or use GPS as navigation in car.

Android App/Activity To Start Fresh Completely every time it starts or resumes?

I have a kid's app for Android and there are some unique considerations for this application since the app has basically no navigation (it's for young kids). I do not want to break my app UI (which has been successful on iPhone) by adding a quit/restart button.
What I really need is fairly simple -- I want my activity/app to start clean and new every single time it starts. Whether it's an initial load or whatever -- basically any time onResume is called I want a completely fresh instance of my app.
I initially thought I could just exit/quit/finish the app when the user leaves. But I haven't found a way to do this that doesn't cause crashes on start. Also every thread/stack overflow post about that idea is filled with people wagging their fingers and saying you should never ever quit an app on android.
If I can't quit the app onExit, is there something I can do to restart my activity every time onResume is called? (or would that be an infinite loop?).
Would greatly appreciate any help!
Try starting your main activity in onResume, and clearing the activity stack:
public void onResume() {
super.onResume();
startActivity(new Intent(this, MainScreen.class).addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
}
maybe these aren't the correctl flags to add, but check out the other Intent flags and this could do what you want!
intent flags documentation
Ended up getting it to work fine by calling finish() in onPause().
Again, I appreciate the advice from people saying "this is not how Android does things". I've got a pretty good understanding of the best practices at this point. This is an unusual situation for an unusual type of user.
in your reload you can try this..
onStop();
onCreate(getIntent().getExtras());

Categories

Resources