I have a cordova (ionic) app that facilitates entering a lot of form data. This form data is saved to localStorage until it is ready to be published.
So keep the app quick I am not saving to the disk everytime and input changes. I am saving when the user navigates away from the page.
The problem I'm having is that the user may enter a lot of data on one page, and close the app without navigating. This is an obvious use case but I'm not sure how to get in front of it without frequently going back to the disk.
Is there a way I can quickly save when the app is exited? I know I can listen to the "pause" event in cordova apps but is that the same when the app is exited? Does an exit emit "pause" ?
If not, what are some strategies for handling this?
TLDR: Listening to the pause event is the right strategy.
The pause event fires when the native platform puts the application
into the background, typically when the user switches to a different
application.
Source
The pause event is the only way to let you know your app is being put in the background. On some mobile platforms you don't even have the possibility to exit your app (in iOS for example), as the platform is managing this for you. So listening to the pause event is your only choice as you loose control once the app is paused. Therefore listening to the pause event is the right strategy.
See following code snippet:
document.addEventListener("pause", onPause, false);
function onPause() {
// Save the application state here
}
In detail I have implemented a storage service with a save-method, which is called in the OnPause-handler.
Pause only fires when going to background. Why you say "to keep the app quick"? it's javascript, you can save to disk every field when is filled and it can be asynchronous.
function onLoad() {
document.addEventListener("deviceready", onDeviceReady, false);
document.addEventListener("pause", onPause, false);
function onDeviceReady() {
var pageNow = document.getElementsByTagName(body);
var currentPage = JSON.stringify(pageNow);
localStorage.setItem("uiState", currentPage);
}
function onPause() {
//retrieve info here
var pageShow = document.getElementsByTagName(body);
let techStack = localStorage.getItem("uiState");
// JSON.parse(techStack); //unnecessary because the parser will detect HTML
pageShow.innerHTML(techStack);
}
}
you can get the current state of the UI in any element, just use a different selector.
Related
I have a react-native-init App which uses appState to detect when an app goes background in order to hide the screen that the user was using (for example a list of emails), and put an image in front of it until the user calls the app foreground again and is authenticated.
This is to prevent any person, checking which are the current opened apps, from seeing what the last screen that the user was checking in my app looks like, and see the image instead (like a splash screen).
This can be easily achieved in iOS because iOS has three stages:
active: when the app is in foreground being used.
inactive: When the app is in transition about to go background.
background: When the app is already in background.
So when the app goes inactive, a flag in the component state is changed and a component with an image is shown instead of the current screen.
handleAppStateChange = (nextAppState) => {
if (nextAppState.match(/inactive|background/)) {
this.setState({ showSplashScreen: true })
}
if (this.state.appState.match(/background/) && nextAppState === 'active') {
this.setState({ showSplashScreen: false })
}
}
However, android uses only active and background appStates, so when it goes background the function is called with background as nextAppState and the flag showSplashScreen in the state is changed to true, but seems like since the app is already background the component does not react to the state change and when you check the list of opened apps you still see the last screen been used, a screen that can contain sensitive data.
Is there any way to detect in react-native Android when the app is going to go background so that the current screen can be replaced with an image before going background?
THere's mechanisms built into Android to prevent the leak of sensitive data. Use them, do NOT attempt to overwrite with an image- or at least don't rely on that alone.
The correct way to do this is to set the SECURE flag on the window, so that the Android OS will take care of this and other possible issues for you, such as screen shots. The code to do that is
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE);
This can be placed in your activity's onCreate, before setContentView is called.
Take a look on the Activity Life Cycle of android apps, you can check the following link
there are three stages that can help you
onPause: called when activity is not visible to the user.
onStop: called when activity is no longer visible to the user.
onResume: called when activity will start interacting with the user again.
When my app completes some async tasks, it notifies UI about it.
For example:
user clicks on "Do work" button inside of my application -> async work started
and switches to another app -> state is saved
then "work" inside my app is finished and View-s updated -> async work finished (note that my activity is paused)
User rotates the phone and then navigating back to my app
problem: state is restored and View's state updated in 3 step is gone while work was finished!
How to deal with such cases?
Is there any way to save settings after app is paused?
Consider using MvpQueuingBasePresenter or Model-View-Intent which deals better with lifecycle related things.
I think you should update the state of the view in onResume method from that activity.
ref: https://developer.android.com/guide/components/activities/activity-lifecycle.html
My application sometimes resets the UI into the initial UI state just like after the first initialization.
The event is occurred when I use another application while the problematic application is sent to background / is sleeping. Then when I change back to the problematic application, it displays the initial state of UI (The initial state of the main page).
I suppose I need to save its state before I minimize the application on OnSleep() event and restore it back on OnResume() event.
How can I do this?
I have solved the problem by using global variable to store whether the application is still running or not.
public MainPage()
{
InitializeComponent();
if(Config.Config._RunningGetLocationThread == true)
{
lbl_Title.Text = "Tracker is running...";
btn_StartTracking.Text = "Stop Tracking!";
}
else
{
btn_StartTracking.Text = "Start Tracking!";
lbl_Title.Text = "Tracker is not running";
}
}
Config.Config._RunningGetLocationThread == true is the global variable and set to true when the application is first started.
I think there should be a better way to save the state of the UI elements. If anyone know the best way to save state UI elements, please share here.
Is there any way to know in "real-time", via broadcast I guess, when a user has cleared data of the app?
I have a widget showing some user details, which are stored in the Preferences, but when the user clear the app data, I am not able to know it until the next refresh/update (the onUpdate() call) which is every 30min.
During that time, the widget is showing useless values. So I need to trigger somehow any broadcast to capture it from a receiver and update the widget when that happens.
Is that possible?
Looks like there is no way to get an event for that. The app's process should be terminated after clearing data. https://stackoverflow.com/a/10701338/450243
You can use a service that implements a http://developer.android.com/reference/java/util/prefs/PreferenceChangeListener.html to monitor when your preferences change.
Even if the service is killed by the system, if you use START_STICKY it will be brought to live, and you'll be able to determine if your keys are available or has been deleted. I've used this approach in a couple of apps and it works like a charm.
If you want to make even more efficient, you can add a receiver for screen on/off, so you can start your service only when the screen starts and terminate your service when the screen gets on.
Hope it helps.
You can also have a look at this solution, you will not exactly get a callback but you will get a fighting chance to update your widget before clearing the data
android:manageSpaceActivity=".path.to.MyActivity"
This will replace the button "Clear Data" from the settings to "Manage Space". Now you can redirect the user to a custom activity that is controlled by you.
The launch of the activity will act as callback for you. Manipulate your data in your activity and use the following code
private void clearPreferences() {
try {
// clearing app data
Runtime runtime = Runtime.getRuntime();
runtime.exec("pm clear YOUR_APP_PACKAGE_GOES HERE");
} catch (Exception e) {
e.printStackTrace();
}
}
to clear the app data.
I have the following script that monitors the android back button actions -
document.addEventListener("backbutton", backKeyDown, true);
function backKeyDown() {
if($.mobile.activePage.is('#homepage')){
setTimeout( function() {navigator.app.exitApp();}, 100 );
}
else {
setTimeout( function() {$.mobile.changePage("#homepage");}, 100 );
}
}
I would like to also close the app when the physical home button is pressed - does anyone know how to detect this?
Cheers
Paul
You can't do that but you can kill your app in onPause() method instead see more here
EDIT:
Doing that in onPause will get your app killed whenever the user leaves the activity, I am not sure if there is a way to do what you want in android though, also is not recommended!
You can create some complex broadcast messaging system that sends messages from your activities to the application instance at a given interval of time and if you don't get any message in the application instance for x seconds then you know that the app is in background..
You can do that using a base activity class that sends messages at x seconds until onPause is called and extend that activity in all the other activities that you use so you can have this behaviour.
This is for sure not the best option that is out there and will consume battery life depending on the implementation so you have to be really sure that you need this before implementing such thing.
Capturing the Hardware's Home key event is bad approach and Android will never allow you to do that. and for closing the app, android framework will automatically send your app to background so you don't need to care about closing your app on Home button pressed event.
I agree with Adil.. but if you really want to or need to exit your app, adding the same listener/function for PhoneGap's "pause" event would probably do the trick.