Android Studio Back Button Problems - java

For so far. I have created a simple quiz application on Android Studio. Everything works fine, including when I go from the FirstActivity.java to the Next Activity, which is named SecondActivity.java, and close the first activity with finish(),when the button is pressed, as shown in the following code:
public void onClick () {
button_next = (Button)findViewById(R.id.nextbtn);
button_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(FirstActivity.this, SecondActivity.class));
finish();
}
});
The code works great But when I try to go from the Second Activity to the First Activity (Closing the Second Activity and going back to the first Activity), neither finish() nor onBackPressed() is working, it just closes the application completely, what code do I need to as soon as I press the button, close the SecondActivity.class and go to the FirstActivity.class?

If you want to go back to previous activity, dont put finish after you change your activity.
public void onClick() {
button_next = (Button) findViewById(R.id.nextbtn);
button_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(FirstActivity.this, SecondActivity.class));
}
});
}

If you have so many activities ,there is another way handle activity life cycle:
public class MyActivityManager {
private static MyActivityManager instance;
private Stack<Activity> activityStack;//activity's stack
private MyActivityManager() {
}
//singleton
public static MyActivityManager getInstance() {
if (instance == null) {
instance = new MyActivityManager();
}
return instance;
}
//push an activity to stack
public void pushOneActivity(Activity actvity) {
if (activityStack == null) {
activityStack = new Stack<Activity>();
}
activityStack.add(actvity);
}
//get last activity,fifo
public Activity getLastActivity() {
return activityStack.lastElement();
}
//remove an activity
public void popOneActivity(Activity activity) {
if (activityStack != null && activityStack.size() > 0) {
if (activity != null) {
activity.finish();
activityStack.remove(activity);
activity = null;
}
}
}
//finish all activity
public void finishAllActivity() {
if (activityStack != null) {
while (activityStack.size() > 0) {
Activity activity = getLastActivity();
if (activity == null) break;
popOneActivity(activity);
}
}
}
}
at the FirstActivity,you shall add
MyActivityManager.getInstance().pushOneActivity(FirstActivity.this);
at the SecondActivity, you want to go FirstActivity or other activity:
startActivity(new Intent(FirstActivity.this, SecondActivity.class));
MyActivityManager.getInstance().finishAllActivity();
finish();

Related

When multiple clicks on activity navigation click, why 2nd activity lifecycle methods calling double times

When i multiple taps on a activity passing button, it takes activity1 has been pause state and after a few seconds activity2 has been come to foreground/visible to the user state.
my problem is , when we are moving on activities with multiple taps, it takes few seconds to user has been wait for next activity come to the visible state. it's really a bad practice.
Here is Call Logs of acticity lifecycle methods:
calling pause - Activity1
call: calling noti create - Activity2
call: calling noti start - Activity2
call: calling noti resume- Activity2
call: calling noti pause- Activity2
//2nd time calls of lifecycle methods
calling noti create- Activity2
call: calling noti start- Activity2
call: calling noti resume- Activity2
Here is Button click of activity navigation:
#OnClick({R.id.card_notification})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.card_notification:
startActivity(new Intent(context, NotificationsActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
break;
}
}
if i remove setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP), activity2 opens multiple times when multiple taps on button click.
I tried with set launch mode in the manifest file.
<activity android:launchMode=”singleTop” />
in this case also activity 2 takes few mill seconds to come to visible state.
Note: When single tap/click everything works fine.
Please help me, what's going wrong in this scenario.
Here 2nd activity code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_noti_detail);
Log.e("call", "noti create");
context = this;
ButterKnife.bind(this);
setToolbar();
callApi("");
etSearchh.setOnEditorActionListener((v, actionId, event) ->
{
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
isSearch = true;
//membersList = null;
callApi(etSearchh.getText().toString().trim());
CommonUtils.hideKeyboard(this);
return true;
}
return false;
});
etSearchh.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.toString().length() > 0) {
iv_clearSearch.setVisibility(View.VISIBLE);
} else {
iv_clearSearch.setVisibility(View.INVISIBLE);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
iv_clearSearch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
iv_clearSearch.setVisibility(View.GONE);
etSearchh.setText("");
//membersList = null;
callApi("");
}
});
}
private void callApi(String searchBy) {
new NotificationController(apiCallBack, context, searchBy).callTokenAPI();
}
private void setToolbar() {
toolbarTitle.setText(MyApplication.getLabelModel().getLabels().getTT_NOTIFICATIONS());
etSearchh.setHint(MyApplication.getLabelModel().getLabels().getSEARCH_NOTIFICATION());
}
private void setRecycler(List<Notifications> notifications) {
mAdapter = new NotificationAdapter(notifications, context);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mAdapter);
}
#OnClick(R.id.iv_back)
public void onViewClicked() {
onBackPressed();
}
#Override
protected void onStart() {
Log.e("Call", "calling noti start");
super.onStart();
}
#Override
protected void onResume() {
Log.e("Call", "calling noti resume");
super.onResume();
}
#Override
protected void onStop() {
Log.e("Call", "calling noti stop");
super.onStop();
}
#Override
protected void onPause() {
Log.e("Call", "calling noti pause");
super.onPause();
}
To prevent multiple executions of button presses, you need to add a boolean variable that you use to remember that the button has been clicked and ignore the button click as "noise" if you see it again. Using your example, do this:
Add a boolean member variable to your class:
private boolean buttonClicked;
In onViewClicked() method, set the variable buttonClicked and ignore the click if it was already set:
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.card_notification:
// Ignore if already clicked
if (buttonClicked) {
return;
}
startActivity(new Intent(context, NotificationsActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
// Remember that the button was clicked
buttonClicked = true;
break;
}
This will prevent multiple clicks from starting multiple copies of NotificationsActivity. When the user returns to this Activity, you will want to reset buttonClicked in onResume() so that the user can again click the button (otherwise the user will only be able to click the button once!).

show app lock pattern dialog when unlocking the phone

I have MainActivity and on its onResume method I call pattern lock to create and confirm user identity. User visits and leave this MainActivity back and forth while active on the app as well as when phone is in sleep mode and user unlocks it. These both scenarios will call onRestart, onStart and onResume methods, but I only want to revoke the pattern in unlock scenario.
handlePattern() method needs a proper distinguishing to be called.
How to distinguish this when I call the handlePattern method ?
MainActivity.class
onCreate(){}
onResume(){
//help needed to know that user is just visiting activity in app back and forth
or came back after unlocking the screen.
if(isPatternCallRequired){
handlePattern()
}
}
In your onStop() method call you can check if the player is in sleep mode and cache the boolean.
PowerManager pm = (PowerManager)
_context.getSystemService(Context.POWER_SERVICE);
boolean isInSleepMode = !pm.isScreenOn();
Check for the build version
if( Build.VERSION.SDK_INT >= 20)
// use isInteractive()
else
// use isScreenOn()
in onRestart which will get called when you resume from sleep - based on the cached value you can show the pattern to unlock.
You may need to reset the cached value once you are done using it.
onResume may not be a right API for the call as it will be called even when your activity loads.
Edited answer based on your comment
You can try ActivityLifecycleCallbacks too like this,
First, Register your Application in your Application class.
public class StackApp extends Application {
private static final String TAG = StackApp.class.getSimpleName();
public static final String INTENT_ACTION_APP_STATE_CHANGE = "intent_action_app_state_change";
public static final String INTENT_DATA_IS_IN_BACKGROUND = "intent_data_is_in_background";
private static int mNumRunningActivities = 0;
private static AtomicBoolean mIsAppInForeground = new AtomicBoolean();
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= 14) {
// registerActivityLifecycleCallbacks is supported only from the SDK version 14.
registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(Activity activity) {
mNumRunningActivities++;
if (mNumRunningActivities == 1) {
notifyAppState(false);
Log.i(TAG, "APP IN FOREGROUND");
}
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
mNumRunningActivities--;
if (mNumRunningActivities == 0) {
notifyAppState(true);
}
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}
/**
* To notify App state whether its in ForeGround or in Background
*
* #param isInBackground
*/
private void notifyAppState(boolean isInBackground) {
if (isInBackground) {
mIsAppInForeground.set(false);
} else {
mIsAppInForeground.set(true);
}
sendAppStateChangeBroadcast(isInBackground);
}
public static boolean isInForeground() {
return mIsAppInForeground.get();
}
private void sendAppStateChangeBroadcast(boolean isInBackground) {
Log.i(TAG, "sendAppStateChangeBroadcast - isInBackground : " + isInBackground);
Intent intent = new Intent();
intent.setAction(INTENT_ACTION_APP_STATE_CHANGE);
intent.putExtra(INTENT_DATA_IS_IN_BACKGROUND, isInBackground);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
And register the broadcast and listen whether the App is going background or foreground like this Sample Activity example
public class SampleMyActivity extends AppCompatActivity {
private OnAppStateReceiver mAppStateReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample_my);
mAppStateReceiver = new OnAppStateReceiver();
IntentFilter filter = new IntentFilter(StackApp.INTENT_ACTION_APP_STATE_CHANGE);
LocalBroadcastManager.getInstance(this).registerReceiver(mAppStateReceiver, filter);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mAppStateReceiver != null) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mAppStateReceiver);
}
}
private class OnAppStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!TextUtils.isEmpty(action) && StackApp.INTENT_ACTION_APP_STATE_CHANGE.equalsIgnoreCase(action)) {
boolean isGoingBackground = intent.getBooleanExtra(StackApp.INTENT_DATA_IS_IN_BACKGROUND, false);
if (isGoingBackground) {
//Your app is not vissible to the use
} else {
// App is visible to the user.
}
}
}
}
}
Note: If you want to listen in Multiple Activity you can create a base
class and add the listener there and you can do the operation, In that
case you can reduce a lot of code.

How to refresh my Textview from another activity

In my app, I am deleting data from my databasehelper class, and I want the Textview in the mainActivity to display the new changed data.So far this is my code.
public void DeleteData(){
bDelete.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Integer deletedRows = myDb.deleteData(etID.getText().toString());
if(deletedRows > 0) {
reload.Redraw();
Toast.makeText(MainActivity.this, "Shit should work", Toast.LENGTH_LONG).show();
}
}})
This is in my second activity, where I call the refresh function
public void Redraw() {
displayMsg.postInvalidate();
}
Just in case, my text
public void nexttime() {
Cursor res = myDb.GetFirstTime();
if (res.getCount() == 0) {
displayMsg.setText("No Appointment was found");
return;
}
StringBuffer buffer = new StringBuffer();
while (res.moveToNext()) {
StringBuffer nextA = buffer.append("Date :" + res.getString(4) + "\n");
displayMsg.setText(nextA);
}}
Have your main activity update its own TextView in its onResume().
Whenever one activity is running, other activities do not exist. More precisely, they may exist, but you can never depend on it. Never attempt to directly access one activity instance from another.

Go to an activity from anywhere

I am implementing a login system. The user needs to be redirected to the login activity from any previous activity if the token is no longer valid. I can go to the login activity with this
new Intent(CurrentActivity.this, NextActivity.class);
But this needs the current activity. I just want to go to the login activity no matter where I am. I cannot know where I am because this is inside an entirely different package.
you should probably register in the Application class to ActivityLifecycleCallbacks and if the user is not registered send them to the correct Activity.
just be sure to not endlessly send them from the login page to itself
EDIT:
adding some code and explanation.
In order to figure out if an Activity that shouldn't be alive is going through lifecycle events you'll need to implement some sort of a gate keeper. Previously it used to be some sort of static state that is kept in the Application class and holds the current activity and sometime even the stack of current activities.
This was far from a complete solution and had issues due to different tasks and even isolated procesies.
In API 14 Android introduced the Activity lifecycle callbacks which can be passed into the method registerActivityLifecycleCallbacks int the Application class.
What you want to do basically is the following:
class ThepooshApplication extends Application {
private static sIsRegistered = false;
public static setIsRegistered(boolean isRegistered) { sIsRegistered = isRegistered; }
public void onCreate() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks(){
#Override
void onActivityCreated(Activity activity, Bundle savedInstanceState){
if (!sIsRegistered && !(activity instanceof LoginActivity)) {
Intent loginIntent = new Intent(this, LoginActivity.class);
loginIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(loginIntent);
}
}
#Override
void onActivityStarted(Activity activity) { /*empty method*/ }
#Override
void onActivityResumed(Activity activity) { /*empty method*/ }
#Override
void onActivityPaused(Activity activity) { /*empty method*/ }
#Override
void onActivityStopped(Activity activity) { /*empty method*/ }
#Override
void onActivitySaveInstanceState(Activity activity, Bundle outState) { /*empty method*/ }
#Override
void onActivityDestroyed(Activity activity) { /*empty method*/ }
});
}
}
You must add FLAG_ACTIVITY_NEW_TASK flag to your intent
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Try some like this
Intent i = new Intent();
i.setClass(this,TestActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Replace TestActivity.class for your target activity

Android back button freezes when using onkeydown method or overriding onbackbuttonpressed

public boolean onKeyDown(int keyCode, KeyEvent event){
if (isSub2&&keyCode == KeyEvent.KEYCODE_BACK) {
Intent intent = new Intent(ctxx, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
isReturning = true;
return false;
}
else {
return super.onKeyDown(keyCode, event);
}
}
}
There are two Activities Main--Sub2.
When you push a button in Main you can go to Sub2.
This code is in Sub2. I want to use back button on the bottom to make the MainActivity put on the top of stack not killing Sub2.
When I run it on the phone it works all right at first,
but after few more times of going back in Sub2 and going to Sub2 again
the back button stops working.
I don't know what is making the back button freeze.. any ideas?
ps) i've tried using handlers inside the method and overriding onBackButtonPressed() instead of using onKeyDown..
but no difference at all..
Not sure why your button freezes. It would be helpful to see what you are doing in the main activity. Here's an example that works for me and does not freeze:
You can put this in the main activity:
#Override
protected void onStart() {
super.onStart();
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SubActivity.class);
//****** Uncomment the following line if you want to re-use the subactivity instead of launching a new one
//intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
});
}
And this in the sub-activity:
#Override
public void onBackPressed() {
//super.onBackPressed();
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}

Categories

Resources