I have an Android application that consists of several activities that are available to the user behind a login acitivity. What I want to do is to show a PIN/login activity when the user hits the HOME button (from any of the activities) and then subsequently returns to the application. Effectively, what I'd like to do is to log out the user when the HOME button is clicked.
From reading other posts, it's my understanding that there is no way to handle the HOME button click directly using a key click event handler. I have tried adding an intent filter for the CATEGORY_HOME intent in the activities:
@Override
public void onCreate( Bundle savedInstanceState ) {
IntentFilter homeIntentFilter = new IntentFilter();
homeIntentFilter.addCategory( Intent.CATEGORY_HOME );
BroadcastReceiver homeReceiver = new BroadcastReceiver() {
@Override
public void onReceive( Context context, Intent intent ) {
showHomeToast();
}
};
registerReceiver( homeReceiver, homeIntentFilter);
}
public void showHomeToast() {
Toast homeToast = Toast.makeText( this, "home 开发者_运维百科clicked", Toast.LENGTH_LONG );
homeToast.show();
}
But this doesn't seem to fire.
Additionally, since there are many activities in the application, triggering a logout in the onPause or onStop events seems problematic since they will fire when the user is simply switching to other activities in the application - and in that case, the user should not be logged out of the application. (also, from experimentation, onDestroy will not be invoked simply by hitting thing HOME button)
At this point, I feel like I'm fighting the Android architecture, so I'm looking for an alternate approach. I have contemplated trying to invert my approach and to use the onResume event, but again I'm unclear how to know whether a given activity is being resumed from another activity in the application (no PIN/login necessary) or because the user has invoked the application again.
Any approaches would be appreciated.
have you tried using the runOnUIThread() method for showHomeToast? It could be that the problem is that it is toasting from the wrong thread. I might look something like:
runOnUiThread(new Runnable(){
@Override
public void run() {
showHomeToast();
}
});
You could try to use the Application Class : which allows you to focus on the lifecycle of your app and not of it's components (never used it though...) here http://developer.android.com/reference/android/app/Application.html
After further reading, it's apparently not possible to receive notification of the Intent.CATEGORY_HOME intent, short of creating a custom home for the device, which was not the question here.
To provide the desired behavior, I ended up doing something a little shakier than I'd hoped - but it is a reasonable enough approach and it has been working. The summary of the approach is to have every activity update a singleton timestamp onPause, and then in the onResume of each activity, check how long it's been since that pause was set - if the difference is larger than some small amount, it means that the activity is being resumed from somewhere other than the app, and the PIN screen should be shown. A custom extension of the Application class provides an easy mechanism for managing the timestamp singleton and centralizing the checking code. Here is the code:
public class MyApplication extends Application {
private long mLastPause;
public long getLastPause() {
return mLastPause;
}
public void setLastPause() {
mLastPause = new Date().getTime();
}
public boolean isAppResuming() {
long now = new Date().getTime();
long millisecondsSinceLastPause = now - getLastPause();
return millisecondsSinceLastPause > 2000;
}
public Intent onResume() {
if ( shouldShowPINEntry() == true ) {
return new Intent( this, PINEnterActivity.class );
}
return null;
}
public boolean shouldShowPINEntry() {
if ( isAppResuming() == true || Session.isActive( this ) == false ) {
return true;
}
else {
Session.extend();
}
return false;
}
}
[the Session object in the code above is a separate singleton that determines whether the user has been inactive for too long. See this post for more on that pattern.]
All my activities then extend a common SecureActivity, which interacts with the MyApplication like so:
public class SecureActivity extends Activity {
@Override
protected void onResume() {
Intent resumeIntent = ( (MyApplication) this.getApplicationContext() ).onResume();
if ( resumeIntent != null ) {
startActivity( resumeIntent );
}
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
( (MyApplication) this.getApplicationContext() ).setLastPause();
}
}
I'm still interested if anyone else has a solid solution that doesn't rely on this "small interval between pause and resume", but this will do fine for now.
精彩评论