How to finish an application when it goes to the background - java

I need to finish an application when it goes to the background, I'm using method finishAffinity() but it seems it does not work, someone can tell me another alternative
#Override
protected void onPause() {
finishAffinity()
super.onPause();
}

Here's answer
finishAffinity() is not used to "shutdown an application". It is used to remove a number of Activitys belonging to a specific application from the current task (which may contain Activitys belonging to multiple applications).
Even if you finish all of the Activitys in your application, the OS process hosting your app does not automatically go away (as it does when you call System.exit()). Android will eventually kill your process when it gets around to it. You have no control over this (and that is intentional).
you can use this
public void endTask() {
// Is the user running Lollipop or above?
if (Build.VERSION.SDK_INT >= 21) {
// If yes, run the fancy new function to end the app and
// remove it from the task list.
finishAndRemoveTask();
} else {
// If not, then just end the app without removing it from
// the task list.
finish();
}
}
Source and read more

Related

How to fix crash handling in android 10

I have a Unity Scene built with Cardboard SDK and exported as a library for Android. The library is used to play videos in cardboard mode on the android app. it's not the whole app, but a part in it. The rest of the android app is built with Kotlin and Java.
I have implemented that and all the functions work as expected, but, exiting the scene crashes the android.
We tried various ways to clear player prefs and even clear memory before closing the scene. But on android it always crashes. I have two android phones with android 9 and 10 for testing.
In the android app, I have made it such that as soon as the app crashes, I try to recover. My crash is that some lateinit var variables are destroyed. Their value becomes null and recovering the previous activity crashes it. So right after I exit the unity scene, I load the dereferenced variables back into memory and everything works again.
Note: I have tried using Application.Quit(); in unity, but it just closes the whole app. On the other hand, I only want to close the running scene
In unity [I call a function goBack in android part to close the app]:
public void GoToHome()
{
Pause();
Stop();
Resources.UnloadUnusedAssets();
PlayerPrefs.DeleteAll();
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("goBack");
}
In App:
public void goBack()
{
UnityPlayer.currentActivity.finish();
finish();
loadDerereferencedVars();
}
This goes perfectly on android 9. On the other phone with android 10, after I close the scene, the app continues to function, but, there comes a message
When I click close app, the app continues to work.
I have checked the logs and there is a null pointer dereference cause for the crash in Unity Main >...
If you'd like to see the Unity Crash Log from LogCat in Android Studio
So, since the app is still running, I thought, it would be better to just hide the crash report and just let the user not know about this crash, but still report it.
I tried enclosing my app in Application and added a method to catch uncaughtException.
here is my application class:
public class MyApp extends Application {
private static final String TAG = "MyAPP";
#Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException (Thread thread, Throwable e) {
handleUncaughtException (thread, e);
}
});
}
/**
* Handles Uncaught Exceptions
*/
private void handleUncaughtException (Thread thread, Throwable e) {
// The following shows what I'd like, though it won't work like this.
Toast.makeText(getApplicationContext(), "Looks like I am having a bad day!", Toast.LENGTH_LONG).show();
Log.e("UncaughtException", "I found an exception!");
// Add some code logic if needed based on your requirement
}
}
Again, this works perfectly in Android 9 and I also got the error reported. However in the phone with android 10, I just get the crash report like the image above and no error is reported.
I want to know why the crash handling is not working and how can I fix it?
I would not finish the Activity you came from, instead just open a new intent (on UnityActivity). When you end this intent the app will come back to the last active Activity.
I will give you my script as an example:
public void sendJobToUnity(String fileName, boolean isNewJob){
//creates a new job. It exists inside the JobSelector Activity
isUnityLoaded = true;
//this is what you are looking for part1
Intent i = new Intent(JobSelector.this, MainUnityActivity.class); //same as (CurrentActivity.this, UnityActivity.this)
//those are how I send some data across the app. just ignore it
//i.putExtra("jobName", fileName);
//i.putExtra("isNewJob",isNewJob);
//i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivityForResult(i, 1); //this is what you are looking for part2
}
For closing it, in the MainUnityActivity Activity I have an override that Unity sends to Android in order to Unload the activity (not quit it completely cause you cannot load it again if you do it) like this:
#Override
protected void receiveJobAndUnloadUnity(String data){
saveCurrentJob(data); //saves the job it receives from Unity
mUnityPlayer.unload(); //this is what you are looking for part3
}
If you want to unload Unity from android you can put "mUnityPlayer.unload();" wherever you want, provided you have started the Activity the way I've shown you.
Note that "mUnityPlayer" is a default Unity variable and cannot be renamed

How to keep timer running when closing the app?

i have code like this , i wanna make timer keep running when i close the app.
private void startStop() {
if (timerStatus == TimerStatus.STOPPED) {
setTimerValues();
setProgressBarValues();
timerStatus = TimerStatus.STARTED; startCountDownTimer();
} else {
timerStatus = TimerStatus.STOPPED;
stopCountDownTimer();
}
}
Assuming you want something like starting the timer, see the progress bar move and if you come back to your app after an hour, it should have advanced by that time.
The easiest approach would be to store the time at which the timer was started in a shared preference and update your timer periodically using System.currentTimeMillis()-startTime
All left to do is restore the shared preference in your Activity's onCreate

Use rx java to load reference data but blocking if necessary

I am trying to implement a solution for storing reference data in the database of my app.
The data is initially stored as JSON files, which I will need to sync from a server on each launch. I have a local copy of the files baked into the app. Each launch I have to check shared preferences for a version. And if it not present, I assume it is the first launch. So i need to read in the files, write the files to the database and fire on completed when that is done. The first screen expects this data to be in the database, so I will be not showing the UI for that screen in this scenario, until the process completes.
However in the future the network call to sync these files can happen asynchronously so want to be able to fire on completed on my observable as soon as i see the shared prefs have a version number and then ill kick of the update completely asynchronously
How can i set up a stream to represent this. I think the stream type will probably be void and i will just fire onCompleted/error as the subscriber doesnt care about the data, only what the process is complete
You could do something like this:
updateChecker.hasUpdates()
.flatMap(hasUpdates -> {
if (hasUpdates) {
return dataUpdater.update();
}
return Observable.just(false);
})
Assuming that
class UpdateChecker {
public Observable<Boolean> hasUpdates() {
return Observable.just(true); // Replace by API call
}
}
class DataUpdater {
public Observable<Boolean> update() {
// update the database here
return Observable.just(true);
}
}

App behaves different after exit and re-enter

Cordova, Version 3.5.0-0.2.6
<body><script>
alert("documentready");
document.addEventListener("deviceready", function() {
alert("deviceready");
}, false);
</script></body>
I enter the app after deploying, I get 'documentready' and 'deviceready' alerted.
I leave the app with the back button.
I get 'documentready' only.
When I force-close the app with the taskmanager or re-deploy it, I get both alerts.
I want this behaviour to occur also after normal re-entering the app.
I would prefer a solution where there is no evidence left that the app has been opened before, after I leave it. Nothing restored from garbage collection etc. Ideally executing the same log as the force-close method from the task manager.
OK: I want, when I close my app via back button, that exactly the same happens, as when I open the task manager and force my app to close. Is this at least theoretically possible?
Alternatively, I would like the app, when left via back-button, to be in a 'hibernate-like' state, that if I re-enter it it behaves absolutely like it has never been left (call same logic as when the menu/home button is pressed).
QUESTION STILL OPEN - 50RS BOUNTY TO EARN
Add this to your mainActivity.java (whatever it is called in your project):
#Override
public void onBackPressed() {
finish();
}
I'm not sure why you'd want such behavior, but you can kill the app on back press (or on finish).
Calling android.os.Process.killProcess(android.os.Process.myPid()) is just like a forcing a stop from the task manager.
Add this to your CordovaActivity and it should kill everything without any remains:
#Override
public void onBackPressed() {
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
I've implemented the same thing, I used the backbutton event from cordova. You can find more about the backbutton event here: link. I can't find documentation about the app.exitApp() function but I do know it is only available for android and amazon-fireos.
See code snippet below, you only need to know when you want to exit, but you might know that from the document.location object or something. Hope it helps.
document.addEventListener("backbutton", function (evt) {
// replace this with some logic (maybe document.location) to now if you are on the main page or not
if (true) {
// Check if methods exists
if (typeof navigator.app !== "undefined" && typeof navigator.app.exitApp !== "undefined") {
evt.preventDefault();
navigator.app.exitApp();
}
} else {
history.back();
}
}, false);
This should work:
In my_app_dir->config.xml add
<preference name="KeepRunning" value="false" />
And below
document.addEventListener("deviceready", function() {...
add
document.addEventListener('backbutton', function() {
navigator.app.exitApp();
}, false);
Afterwards open cmd, go to your project folder and run cordova build android; cordova run --device android;
What works for me, the problem might be that the DOM is not ready when you add the event listener. And may be caused by a faster load due to the app being cached. Use a self executing function to add the event listener and you will be sure the DOM is loaded.
function domIsReady() {
alert('DOM is ready')
}
function deviceIsReady() {
alert('Device is Ready')
}
( function() {
if (document.readyState === "complete") {
domIsReady();
} else {
if (window.addEventListener) {
window.addEventListener('DOMContentLoaded', domIsReady, false);
} else {
window.attachEvent('onload', domIsReady);
}
};
document.addEventListener("deviceready", deviceIsReady, true);
}());

Problem with java.awt.Desktop

I have a button in my program that, when pressed, is supposed to take you to my wiki page about the program. I used the following line to do so:
java.awt.Desktop.getDesktop().browse(new java.net.URI("http://supuh.wikia.com/wiki/BHT"));
The problem is that, no matter what environment in which the program is run, I always get the following error:
java.security.AccessControlException: access denied (java.awt.AWTPermission showWindowWithoutWarningBanner)
does anyone know how I can fix this? Note that this only works in the one program. Any other program I make can use the same method with no problem.
Exit hook
At the start of my program, this hook is added. The program runs fine without it...
System.setSecurityManager(new SecurityManager()
{
#Override
public void checkExit(int status)
{
closeFile(status);
}
});
this hook is needed, but the browse(URI uri) method in question won't work with it. Solutions?
This means you are running with a security manager:
SecurityException - if a security manager exists and it denies the AWTPermission("showWindowWithoutWarningBanner") permission, or the calling thread is not allowed to create a subprocess; and not invoked from within an applet or Java Web Started application
If this is an applet, or a Java Web Start app - sign your jar.
Update Adding a security manager to detect program exit is wrong. There are multiple ways to do this properly. In your case I guess this would be most appropriate:
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
#Override
public void run() {
closeFile();
}
));
Swing-specific solutions are:
if you don't have to perform extra actions, use frame.setDefaultCloseAction(Frame.EXIT_ON_CLOSE)
use addWindowStateListener and check for WindowEvent.WINDOW_CLOSED
That said, two notes:
you must not hold files open for a long time. Use try/catch/finally to open and close them whenever they are needed.
if you really need a security manager at some point, make sure you override the appropriate method of the SecurityManager that checks whether you can open the link. (won't tell you which one, so that you are not tempted to jump onto this solution, which is wrong)
To summarize, I'd go for setDefaultActionOnClose, and close each file right after I finish reading/writing it.
Update 2: After you linked to your original question describing what exactly are you trying to achieve, things change a bit. You are trying to prevent exit, so you do need a SecurityManager. This makes it so that you should override the checkPermission method and do nothing there (i.e. don't throw exceptions), at least when these permissions are checked (they are checked when browse is called):
new AWTPermission("showWindowWithoutWarningBanner")
new FilePermission("<<ALL FILES>>", SecurityConstants.FILE_EXECUTE_ACTION)
Update 3 Here's how exactly to override the method:
#Override
public void checkPermission(Permission permission) {
if (permission instanceof AWTPermission) {
if (permission.getName().equals("showWindowWithoutWarningBanner")) {
return;
}
}
if (permission instanceof FilePermission) {
if (permission.getActions().equalsIgnoreCase("execute")) {
return;
}
}
java.security.AccessController.checkPermission(permission);
}
(you can go without the outer if-s)
Update 4 The above method will work only if you have given permissions to your program. Otherwise it is a not-well documented behaviour of the JVM that overriding security managers are not allowed to be unprivileged. Take a look at this report - the comments say how to work it around.
To make your life simpler, you can simply #Override public void checkPermission(..) with an empty method body.
Instead of using your own SecurityManager, install a shutdown hook instead:
Runnable runnable = new Runnable() {
closeFile(status);
}
Runtime.getRuntime().addShutdownHook(new Thread (runnable, "Close file"));

Categories