Listen for Home button press - android

Is there a way to listen for the user pressing the Home button?
I wanted to override the Home button functionality, but I have read in many places that "For security reasons we can't override home button". Can we override the Home button, or not?
I have tried with various code snippets. One sample I took from the below site:
http://www.coderzheaven.com/2012/06/02/override-hardware-home-button-android-listen-home-button-click-android/
I tested it in Latest Samsung J8 Phone but it did not work.

My question is can we override home button or Can't?
Answer: since android 4.0, you can not override home button as a non-system app.
But there are some ways to listen whether users have pressed home button. If you are interested in this, I would supply some solutions for you.
Edit: Add some solutions to listen home button pressed.
I supply you two ways to listen home button pressed event.
First, reigster a Broadcast Receiver.
class HomeKeyBroadCastReceiver extends BroadcastReceiver {
final String SYSTEM_DIALOG_REASON_KEY = "reason";
//press Home button
final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
//press recent app button
final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
// long press home button
final String SYSTEM_DIALOGS_REASON_LONG_PRESS_HOME_KEY = "globalactions";
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if (reason != null) {
if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
// press home , do something
} else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
// press recent app , do something
} else if (reason.equals(SYSTEM_DIALOGS_REASON_LONG_PRESS_HOME_KEY)) {
// long press home button , do something
}
}
}
}
}
// register Receiver
AppUtils.context.registerReceiver(homeKeyBroadCastReceiver, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
Another way, you can register lifecycle callback in your application.
application.registerActivityLifecycleCallbacks(new HomeButtonListerLifecycleCallbacks());
public class HomeButtonListerLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
// check threshold
private final int CHECK_DELAY = 200;
private Handler handler;
private Runnable checkRunnable;
public HomeButtonListerLifecycleCallbacks() {
this.handler = new Handler(Looper.getMainLooper());
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
ZZLocalPushInfoManager.getInstance().onCreateActivity(activity);
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
if (handler != null && checkRunnable != null) {
handler.removeCallbacks(checkRunnable);
}
}
#Override
public void onActivityPaused(final Activity activity) {
if (handler != null) {
if (checkRunnable != null) {
handler.removeCallbacks(checkRunnable);
}
handler.postDelayed(checkRunnable = new Runnable() {
#Override
public void run() {
// Here user has left your app. mostly they pressed home button,
// but they also can go to other app by notification,etc.
}
}, CHECK_DELAY);
}
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}

Related

Callback when task goes into background or comes into foreground?

I have an activity A, it launches custom-tab. I need to know while the custom tab is open, if the task (of which the activity is part of) goes to background or comes to foreground.
I am aware of this question How to detect when an Android app goes to the background and come back to the foreground . The solutions mentioned for this question don't work for me because as soon as custom tab is launched, the onbackground callback is received, which is not what I want. I want onbackground callback, when the task containing the activity A goes to background.
Using the CustomTabsCallback you can listen when the Tab becomes hidden (goes into background) using the TAB_HIDDEN callback or TAB_SHOWN callback when the Tab becomes visible (goes into foreground).
From the Documentation:
TAB_HIDDEN
Sent when the tab becomes hidden.
TAB_SHOWN
Sent when the tab becomes visible.
Below is a full working example of how you can use the above callbacks:
public class CustomTabsActivity extends AppCompatActivity {
private CustomTabsServiceConnection mCustomTabsServiceConnection;
private CustomTabsClient mCustomTabsClient;
private CustomTabsSession mCustomTabsSession;
private CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.customTabsButton).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showCustomTabs();
}
});
initCustomTabs();
}
#Override
protected void onStart() {
super.onStart();
CustomTabsClient.bindCustomTabsService(this, "com.android.chrome", mCustomTabsServiceConnection);
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onStop() {
super.onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
private void initCustomTabs() {
mCustomTabsServiceConnection = new CustomTabsServiceConnection()
{
#Override
public void onCustomTabsServiceConnected(#NotNull ComponentName componentName, #NotNull CustomTabsClient customTabsClient)
{
mCustomTabsClient = customTabsClient;
mCustomTabsClient.warmup(0L);
mCustomTabsSession = mCustomTabsClient.newSession(new CustomTabsCallback()
{
#Override
public void onNavigationEvent(int navigationEvent, Bundle extras) {
switch (navigationEvent)
{
case CustomTabsCallback.TAB_SHOWN:
//Sent when the tab becomes visible (goes into foreground)
break;
case CustomTabsCallback.TAB_HIDDEN:
//Sent when the tab becomes hidden (goes into background)
break;
}
}
});
builder.setSession(mCustomTabsSession);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mCustomTabsClient = null;
}
};
CustomTabsClient.bindCustomTabsService(this, "com.android.chrome", mCustomTabsServiceConnection);
}
private void showCustomTabs(){
builder.setShowTitle(true);
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(this, Uri.parse("https://stackoverflow.com/"));
}
}
The relationship between your activity and chrome custom tabs depends on the launchMode. You can launch the custom tab in current stack or a new stack.

Application Level onResume Android

Problem
The idea is very simple. Whenever an user comes back to my app from the Recents I want to show a simple dialog prompting with the password.
I know how to prompt the dialog with password, but my problem is how do I understand that the user has entered my app from the recents. If I put the prompt in the onResume in every activity, then it will get triggered everytime even if the user doesn't enter from the Recents menu.
There are lots of activities and fragments in my app. So, I would love to have a more generic or application level solution.
Implement Application.ActivityLifecycleCallbacks, that will provide all activity callback in your application class.
public class AppController extends Application implements
Application.ActivityLifecycleCallbacks
{
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
You could try with this flag FLAG_ACTIVITY_LAUNCHER_FROM _HISTORY:
if((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY )!=0){
Log.d(TAG, "Called from history");
//clear flag from history
Intent intent = getIntent().setFlags( getIntent().getFlags() & (~ Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY));
setIntent(intent);
}
Source : Android - detecting application launch from home or history
When "A" Activity is start from recent, this flag is present.
Now this flag will be also present if "A" activity call "B" activity and on "B" user press back.
So you have to check flag and when you detect it you have clear intent by removing this flag, source: Remove a Paint Flag in Android
Try below sample
/**
* TODO : After update to API level 14 (Android 4.0),
* We should implement Application.ActivityLifecycleCallbacks
*/
public class GlobalApplication extends android.app.Application
{
private boolean inForeground = true;
private int resumed = 0;
private int paused = 0;
public void onActivityResumed( Activity activity )
{
++resumed;
if( !inForeground )
{
// Don't check for foreground or background right away
// finishing an activity and starting a new one will trigger to many
// foreground <---> background switches
//
// In half a second call foregroundOrBackground
}
}
public void onActivityPaused( Activity activity )
{
++paused;
if( inForeground )
{
// Don't check for foreground or background right away
// finishing an activity and starting a new one will trigger to many
// foreground <---> background switches
//
// In half a second call foregroundOrBackground
}
}
public void foregroundOrBackground()
{
if( paused >= resumed && inForeground )
{
inForeground = false;
}
else if( resumed > paused && !inForeground )
{
inForeground = true;
}
}
}
Put below code in your all activities.
public class BaseActivity extends android.app.Activity
{
private GlobalApplication globalApplication;
#Override
protected void onCreate()
{
globalApplication = (GlobalApplication) getApplication();
}
#Override
protected void onResume()
{
super.onResume();
globalApplication.onActivityResumed(this);
}
#Override
protected void onPause()
{
super.onPause();
globalApplication.onActivityPaused(this);
}
#Override
public void onDestroy()
{
super.onDestroy();
}
}
I would suggest using LifecycleObserver. If your Application class implements this interface it marks a class as a LifecycleObserver, it does not have any methods, instead, it relies on OnLifecycleEvent annotated methods. The usage is simple:
public class AndroidApplication extends Application implements LifecycleObserver {
#OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppStart() {
//enter code here
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppStop() {
//enter code here
}
...etc
}
With Lifecycle.Event you can access all lifecycle states through Enum. It is part of androidx.

Android - does defining a button static leak my activity? Can I avoid it?

I need the button to be static so I can enable it/ disable it form my services in case the activity is shown. Still I setOnClickListener and anyway static views are considered dangerous. Do I leak ? Can I avoid it ?
public class MonitorActivity extends FragmentActivity implements
OnClickListener {
private static Button updateButton; // static??
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_monitor);
// button
updateButton = (Button) findViewById(R.id.update_data_button);
updateButton.setOnClickListener(this); // oops ?
}
public static void onDataUpdated(Context ctx) {
if (updateButton != null) { //that's why I need it static
updateButton.setEnabled(true); // + set the text etc
}
}
public static void onUpdating() {
if (updateButton != null) {
updateButton.setEnabled(false);
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.update_data_button:
serviceIntent.putExtra(MANUAL_UPDATE_INTENT_KEY, true);
this.startService(serviceIntent);
}
}
#Override
protected void onResume() {
super.onResume();
Boolean isUpdating = AccessPreferences.get(this, updateInProgressKey,
false);
// set the button right
updateButton.setText((isUpdating) ? defaultUpdatingText
: getResources().getString(R.string.update_button_text));
updateButton.setEnabled(!isUpdating);
}
}
I think You can create BroadcastReceiver in MonitorActivity. And send extras message from Service to enable/disable button.
I suggest you use LocalBroadcastManager
In your Activity define a BroadcastReceiver and register the Broadcast in onStart()onResume() and unregister it in onStop()onPause().
From your Service send the Broadcast to the Activity if the Activity is active it will receive the Broadcast and update the UI, if not nothing will happen.
Define another BroadcastReceiver in your Service, Register the Broadcast in onCreate() and Unregister it in onDestroy().
When your Activity is started send a Broadcast to the Service and let the Service reply to the Activity using the first Broadcast to update the UI.
UPDATE
After doing some investigation I found you're correct "sticky broadcasts are discouraged", but if you check the date of that post it's on 2008 - before Google implemented the LocalBroadcastManager.
And I have checked the source code of LocalBroadcastManager, it's not a real Broadcast it's an interface, Singleton with a list of BroadcastReceivers (not global and no IPC communication).
I really hate public static and I always avoid them. every body should.
So yes - the static button would leak my activity. I came up with callback below but it is ugly. I finally solved it by making the Activity extend OnSharedPreferenceChangeListener
public final class MonitorActivity extends FragmentActivity implements
OnClickListener, OnSharedPreferenceChangeListener {
private Button updateButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
updateButton = (Button) findViewById(R.id.update_data_button);
updateButton.setOnClickListener(this); //no need to unregister methinks
}
#Override
public synchronized void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
if (updateInProgressKey.equals(key)) {
final Boolean isUpdating = AccessPreferences.get(this,
updateInProgressKey, false);
// set the button right
updateButton.setText((isUpdating) ? sDefaultUpdatingText
: sUpdateButtonTxt);
updateButton.setEnabled(!isUpdating);
}
}
#Override
protected void onStart() {
super.onStart();
AccessPreferences.registerListener(this, this);
AccessPreferences.callListener(this, this, updateInProgressKey);
}
#Override
protected void onStop() {
// may not be called (as onStop() is killable), but no leak,
// see: http://stackoverflow.com/a/20493608/281545
AccessPreferences.unregisterListener(this, this);
super.onStop();
}
}
Callback
onPause() is guaranteed to run - so I null the static fields there and populate them on onResume(). I only do a read from default shared preferences so it should not take long in the synchronized blocks (I have to synchronize cause the service might call onUpdating() or onDataUpdated() any odd time). Not sure about unregistering the listener though
public class MonitorActivity extends FragmentActivity implements
OnClickListener {
private static TextView dataTextView; //null this onPause() to avoid a leak
private static Button updateButton; // null this onPause() to avoid a leak
// ...
public static synchronized void onDataUpdated(Context ctx) {
if (updateButton != null) {
updateButton.setEnabled(true); // + set the text etc
}
}
public static synchronized void onUpdating() {
if (updateButton != null) {
updateButton.setEnabled(false);
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.update_data_button:
serviceIntent.putExtra(MANUAL_UPDATE_INTENT_KEY, true);
this.startService(serviceIntent);
}
}
#Override
protected void onResume() {
super.onResume();
synchronized (MonitorActivity.class) {
Boolean isUpdating = AccessPreferences.get(this,
updateInProgressKey, false);
updateButton = (Button) findViewById(R.id.update_data_button);
updateButton.setOnClickListener(this);
// set the button right
updateButton.setText((isUpdating) ? defaultUpdatingText
: getResources().getString(R.string.update_button_text));
updateButton.setEnabled(!isUpdating);
}
}
#Override
protected void onPause() {
synchronized (MonitorActivity.class) {
updateButton.setOnClickListener(null); // TODO : needed ??
dataTextView = updateButton = null; // to avoid leaking my activity
}
super.onPause();
}
}
There are 3 solutions for you:
Set button = null when context is destroyed(onStop);
Use WeakReference for button field, Example:
private static WeakReference<Button> updateButton;
Not creating static button. It's always hold the context.

Android Loader vs AsyncTask on button tap

I have an activity which requires no data from server on load - just plain init for ui
UI has several buttons.
User clicks one of them and app sends request to server (rest call)
While request is processing spinner is shown (for about 10 seconds)
For now it uses AsyncTask - so if app changes portrait to landscape - activity is restarted and I loose the process
Second option is to use Loader - the problem is that it is started on button tap - not on activity start
This leads to many exceptions - when LoaderManager sends events to non-started item
Is there any solution?
few comments:
- 10 seconds is just for example
- lock user to one orientation is not an option
- service is overkill for simple rest call
public class TestActivity extends FragmentActivity {
private Button one;
private Button two;
private final int ONE_ID = 0;
private final int TWO_ID = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
one = (Button) findViewById(R.id.one);
two = (Button) findViewById(R.id.two);
one.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getLoaderManager().restartLoader(ONE_ID, null, callbacks);
}
});
two.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getLoaderManager().restartLoader(ONE_ID, null, callbacks);
}
});
Loader<AsyncTaskLoaderResult<Result>> loader = getLoaderManager().getLoader(ONE_ID);
if (loader != null) {
getLoaderManager().initLoader(ONE_ID, null, callbacks);
}
loader = getLoaderManager().getLoader(TWO_ID);
if (loader != null) {
getLoaderManager().initLoader(TWO_ID, null, callbacks);
}
}
public static class AsyncTaskLoaderResult<E> {
public E data;
public Bundle args;
}
public static class Result {
}
private LoaderManager.LoaderCallbacks<AsyncTaskLoaderResult<Result>> callbacks = new LoaderManager.LoaderCallbacks<AsyncTaskLoaderResult<Result>>() {
#Override
public Loader<AsyncTaskLoaderResult<Result>> onCreateLoader(int id, Bundle args) {
/**
* according different Id, create different AsyncTaskLoader
*/
switch (id) {
case ONE_ID:
return new OneAsyncTaskLoader(TestActivity.this);
case TWO_ID:
return new TwoAsyncTaskLoader(TestActivity.this);
}
return null;
}
#Override
public void onLoadFinished(Loader<AsyncTaskLoaderResult<Result>> loader, AsyncTaskLoaderResult<Result> data) {
/**
* handle result
*/
switch (loader.getId()) {
}
getLoaderManager().destroyLoader(loader.getId());
}
#Override
public void onLoaderReset(Loader<AsyncTaskLoaderResult<Result>> loader) {
}
};
public static class OneAsyncTaskLoader extends AsyncTaskLoader<AsyncTaskLoaderResult<Result>> {
private AsyncTaskLoaderResult<Result> result;
public OneAsyncTaskLoader(Context context) {
super(context);
}
#Override
protected void onStartLoading() {
super.onStartLoading();
if (result != null) {
deliverResult(result);
} else {
forceLoad();
}
}
#Override
public AsyncTaskLoaderResult<Result> loadInBackground() {
/**
* send request to server
*/
result = new AsyncTaskLoaderResult<Result>();
result.data = null; // result.data comes from server's response
return result;
}
}
public static class TwoAsyncTaskLoader extends AsyncTaskLoader<AsyncTaskLoaderResult<Result>> {
private AsyncTaskLoaderResult<Result> result;
public TwoAsyncTaskLoader(Context context) {
super(context);
}
#Override
protected void onStartLoading() {
super.onStartLoading();
if (result != null) {
deliverResult(result);
} else {
forceLoad();
}
}
#Override
public AsyncTaskLoaderResult<Result> loadInBackground() {
/**
* send request to server
*/
result = new AsyncTaskLoaderResult<Result>();
result.data = null; // result.data comes from server's response
return result;
}
}
}
First, you can eliminate the orienatation change issue by declaring
android:configChanges="orientation"
or savedInstanceState()
But the real problem here is having the user stare at a spinner for 10 seconds. Most users aren't going to be patient enough for this. I don't know what your app is doing so its hard to give an accurate suggestion but I can say that you need to do your network stuff in your AsyncTask but allow the user to do other things
You can allow the user to do other things while the AsyncTask finishes or put that code in a [Service(http://developer.android.com/guide/components/services.html). Either way, don't make your users stare at a screen for 10 seconds of spinning...they won't be YOUR users for long
If you're using an AsyncTask for this you might want to either use a Service instead or use onRetainNonConfigurationInstance or Fragment.setRetainInstance to allow the AsyncTask to live through configuration changes.
Or disable configuration changes: I've used that in the past with some success.
Here's a good article on the subject:
http://www.javacodegeeks.com/2013/01/android-loaders-versus-asynctask.html
Anyways, as #codeMagic mentioned, AsyncTask with android:configChanges="orientation|screenSize" should be enough for you (it prevents activity from being recreated on config changes)

Android object value changed when resume

I got a VERY STRANGE situation...(to me)
For example, 2 objects,
1 is an activity member boolean called isInPage,
2 is a static bitmap object called bmpPhoto.
When I get into my own activity called FacebookShareActivity
isInPage will be true until I quit this activity,
bmpPhoto will be given a picture.
After onCreare() and onResume(), there is no any code running, until user click some GUI.
What I did is close screen by press hardware power button, and maybe wait 5 or 10 minutes.
OK, now I press porwe again to wake phone up, unlock screen,
and my FacebookShareActivity goes back to front.
And I click my GUI button to check variable value via Logcat, it says:
isInPage=false;
And I forget bmpPhoto's value, but on my GUI, the photo just gone,
not displayed anymore...
How is this happen ?
And it just not happen every time after I do that......
What if I override onSaveInstanceState(Bundle savedInstanceState) and
onRestoreInstanceState(Bundle savedInstanceState) ?
Will it help ?
And what about the bitmap object ?
Still don't know how is that happen...
Did I miss something ?
I really need your help, please everyone~
Following is part of my code, quite long...
The "isPageRunning" and "bmp" changed sometime when back from desktop, but not everytime.
public class FacebookShareActivity extends Activity
{
private Bundle b=null;
private Bitmap bmp=null;
private boolean isFacebookWorking=false;
private boolean isPageRunning=true; //This value sometime changed when back from desktop, but not every time
protected void onCreate(Bundle savedInstanceState)
{
Log.i(Constants.TAG, "ON Facebook Share create......");
super.onCreate(savedInstanceState);
setContentView(R.layout.facebook_share);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
private void initUI()
{
btnBack=(Button)findViewById(R.id.btnBack);
btnBack.setOnClickListener(new ButtonClickHandler());
formImage=(RelativeLayout)findViewById(R.id.form_image);
formImage.setDrawingCacheEnabled(true);
btnShare=(Button)findViewById(R.id.btnShare);
btnShare.setOnClickListener(new ButtonClickHandler());
txtIntroText=(TextView)findViewById(R.id.txtIntroText);
txtIntroText.setOnClickListener(new ButtonClickHandler());
txtIntroText.setText(getUploadInImageText());
photo=(ImageView)findViewById(R.id.photo);
bmp=Constants.PROFILE.getName().getPhoto();
if(bmp!=null)
{photo.setImageBitmap(bmp);} //bmp wouldn't be null, it filled by some other activity before
}
#Override
protected void onResume()
{
super.onResume();
Log.i(Constants.TAG, "Trying to set UI on resume...");
b=getIntent().getExtras();
// ...
// ... Get some String value passed from prev activity
facebook=new Facebook("123456789012345"); //Test
asyncFacebook=new AsyncFacebookRunner(facebook);
initUI();
System.gc();
}
#Override
public void onBackPressed()
{
Log.d(Constants.TAG, "Activity receive back key...");
lockButtons(false);
return;
}
private void lockButtons(boolean b)
{
if(isPageRunning)
{
btnBack.setClickable(!b);
btnShare.setClickable(!b);
}
}
private class DelayReleaseKey implements Runnable
{
public void run()
{
try{Thread.sleep(10000);}
catch(InterruptedException ie){}
handler.sendEmptyMessage(0);
}
}
private class ButtonClickHandler implements OnClickListener
{
public void onClick(View v)
{
if(v==btnBack)
{
if(isFacebookWorking)
{ShowAlertDialog(Constants.MESSAGE_FACEBOOK_WORK);}
else
{
lockButtons(true);
formImage=null;
photo=null;
b=null;
facebook=null;
isPageRunning=false;
Intent intent=new Intent(FacebookShareActivity.this, PracticeListActivity.class);
startActivity(intent);
FacebookShareActivity.this.finish();
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right);
}
}
if(v==btnShare)
{
lockButtons(true);
facebookLogin();
}
}
}
}
Now I know i must override onSaveInstanceState, onRestoreInstanceState.
They can help me to save variable like String, int, boolean...
What about Bitmap ?
And what if my variable is static ?
Now try again.
public class FacebookShareActivity extends Activity
{
private Bundle b=null;
private static Bitmap bmp=null;
private static boolean isFacebookWorking=false;
private static boolean isPageRunning=true; //This value sometime changed when back from desktop, but not every time
protected void onCreate(Bundle savedInstanceState)
{
Log.i(Constants.TAG, "ON Facebook Share create......");
super.onCreate(savedInstanceState);
setContentView(R.layout.facebook_share);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
private void initUI()
{
btnBack=(Button)findViewById(R.id.btnBack);
btnBack.setOnClickListener(new ButtonClickHandler());
formImage=(RelativeLayout)findViewById(R.id.form_image);
formImage.setDrawingCacheEnabled(true);
btnShare=(Button)findViewById(R.id.btnShare);
btnShare.setOnClickListener(new ButtonClickHandler());
txtIntroText=(TextView)findViewById(R.id.txtIntroText);
txtIntroText.setOnClickListener(new ButtonClickHandler());
txtIntroText.setText(getUploadInImageText());
photo=(ImageView)findViewById(R.id.photo);
bmp=Constants.PROFILE.getName().getPhoto();
if(bmp!=null)
{photo.setImageBitmap(bmp);} //bmp wouldn't be null, it filled by some other activity before
}
#Override
protected void onResume()
{
super.onResume();
isPageRunning = true;
Log.i(Constants.TAG, "Trying to set UI on resume...");
b=getIntent().getExtras();
// ...
// ... Get some String value passed from prev activity
facebook=new Facebook("123456789012345"); //Test
asyncFacebook=new AsyncFacebookRunner(facebook);
initUI();
System.gc();
}
#Override
protected void onPause()
{
isPageRunning = false;
}
#Override
public void onBackPressed()
{
Log.d(Constants.TAG, "Activity receive back key...");
lockButtons(false);
return;
}
private void lockButtons(boolean b)
{
if(isPageRunning)
{
btnBack.setClickable(!b);
btnShare.setClickable(!b);
}
}
private class DelayReleaseKey implements Runnable
{
public void run()
{
try{Thread.sleep(10000);}
catch(InterruptedException ie){}
handler.sendEmptyMessage(0);
}
}
private class ButtonClickHandler implements OnClickListener
{
public void onClick(View v)
{
if(v==btnBack)
{
if(isFacebookWorking)
{ShowAlertDialog(Constants.MESSAGE_FACEBOOK_WORK);}
else
{
lockButtons(true);
formImage=null;
photo=null;
b=null;
facebook=null;
isPageRunning=false;
Intent intent=new Intent(FacebookShareActivity.this, PracticeListActivity.class);
startActivity(intent);
FacebookShareActivity.this.finish();
overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right);
}
}
if(v==btnShare)
{
lockButtons(true);
facebookLogin();
}
}
}
}
For primitive values, you should use onSaveInstanceState. For restoring you can use onRestoreInstanceState or you can some code in onCreate like this:
if(savedInstanceState != null) {
// restore old state
} else {
// a fresh start
}
Now for restoring objects like Bitmap if they are not expensive to create and doesn't make your UI sluggish, create them again on restore. If you do not want to that then use onRetainNonConfigurationInstance and code will look like this:
#Override
public Object onRetainNonConfigurationInstance () {
return bmp;
}
#Override
public void onCreate() {
if
bmp = (Bitmap)getLastNonConfigurationInstance();
}
WARNING: This api is deprecate, you might use it on old platforms. I put it here for illustration purpose. The new way to do this is more involving.
Here is detailed ref:
getLastNonConfigurationInstance
onRetainNonConfigurationInstance

Categories

Resources