App resumes to wrong activity when singleTask flag is used - android

MainActivity in my app has launchMode set to singleTask. If I start ActivityB from MainActivity, then put app to background and start my app from applications screen it does not resume correctly. ActivityB automatically finishes and MainActivity resumes. I expect ActivityB to resume instead. Why is this happening and what could I do to make it work normally? It works OK without singleTask flag but I need that flag for other purposes.
By the way, my app resumes correctly from recent apps screen.

Use the following code in the LAUNCHER Activities.
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!isTaskRoot()) {
finish();
return;
}
// Rest of your onCreate code goes here
}

Activity B is closed because it launched from Activity A, this is normal behavior for android because Activity A needs to be restarted (singleTask) and all related instance will be kill/finish.
So, what you can do is implement shared-preference.
your activity A should be like this :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//// read share preference
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
int defaultValue = getResources().getInteger("MYSHARE_PRFERENCE");
int isOpened = sharedPref.getInt("IS_ACTIVITY_B_ALREADY_OPENED", defaultValue);
if (isOpened == 1)
{
//resume activity B
startActivity(new Intent(MainActivity.this, ActivityB.class));
}
////
findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this, ActivityB.class));
//// write on share preference
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("IS_ACTIVITY_B_ALREADY_OPENED", 1);
editor.commit();
////
}
});
}
}
P.S : I didn't compile it yet, the code might be error on compile. But share preference can be solution for your problem.

Related

Shared preferences not working as expected

Below is my code to the MainActivity.java of my project, this is the welcome like screen for my app and should only appear first time user opens the app. Otherwise the user should get to see the Medicine_Activity.java which is also triggered when the user presses "Get Started" button on MainActivity. In order to implement this i came across something known as SharedPreferences and tried to implement it. But it isnt working quite as expected, the MainActivity flashes for a second before Medicine_Activity is launched. I am new so please help me out
Here is a video clip to view this bug in action - https://www.dropbox.com/s/fqbo9urb6xnh3pd/WhatsApp%20Video%202019-06-20%20at%202.12.50%20PM.mp4?dl=0
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button btnGetStarted;
#Override
protected void onCreate(Bundle savedInstanceState) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
boolean previouslyStarted = prefs.getBoolean(getString(R.string.pref_previously_started), false);
if(!previouslyStarted) {
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(getString(R.string.pref_previously_started), Boolean.TRUE);
edit.apply();
} else{
Intent intent = new Intent(this, Medicine_Activity.class);
startActivity(intent);
}
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); //will hide the title
getSupportActionBar().hide(); // hide the title bar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN); //enable full screen
setContentView(R.layout.activity_main);
Button btnGetStarted = findViewById(R.id.btnGetStarted);
btnGetStarted.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent intent = new Intent(this, Medicine_Activity.class);
startActivity(intent);
}
}
Use commit() while storing the true and finish() the MainActivity.
if(!previouslyStarted) {
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(getString(R.string.pref_previously_started), true);
edit.commit();
} else{
Intent intent = new Intent(this, Medicine_Activity.class);
startActivity(intent);
finish();
}
A short explanation: commit() writes the data synchronously (blocking the thread its called from). It then informs you about the success of the operation. However, apply() schedules the data to be written asynchronously. It does not inform you about the success of the operation.
Quoting from Documentation:
Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures

Changes are not applied to all the activities

I implemented night mode in my app.User can change the night mode settings in profile activity.The order of activities are as follows.
TabbedActivity>>DisplayActivity,ProfileActivity
The changed settings are applied only in current activity.(i.e profile activity).If the user presses back button,changes are not applied to that activities.Anyone help me to apply changes to all the activites.When we close the app and open again.changes are applied.But back press doesn't work.
This is the code I am using.
#Override
protected void onCreate(Bundle savedInstanceState) {
final SharedPreferences sharedPreferences =
getSharedPreferences("NIGHT_MODE", MODE_PRIVATE);
int result=sharedPreferences.getInt("NIGHT_MODE_OPTION",0);
if (result==2){
setTheme(R.style.darkTheme);
}else setTheme(R.style.AppTheme);
loadLocale();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
final SharedPreferences.Editor editor = getSharedPreferences("NIGHT_MODE", MODE_PRIVATE).edit();
if (result==2){
night.setChecked(true);
}
night.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
editor.putInt("NIGHT_MODE_OPTION",AppCompatDelegate.MODE_NIGHT_YES);
editor.apply();
startActivity(getIntent());
}else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
editor.putInt("NIGHT_MODE_OPTION",AppCompatDelegate.MODE_NIGHT_NO);
editor.apply();
startActivity(getIntent());
}
}
});
}
Since you are not considering Android lifecycle. You configure everything inside onCreate. However, while switching between activities current activity's lifecycle change accordingly. Here is lifecycle is explained very well
Solution:
When you come back to the previous activity, onResume is called. You should apply all changes inside this method
override fun onResume() {
super.onResume()
//Read your settings from SharedPrefs then apply, here
}
'i think the better practice would to restart/reset app everytime the theme is changed'
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
finish();

On-boarding slider screen

I have used a built in library to create "android on-boarding slider screen". The library is implementation 'com.github.apl-devs:appintro:v4.2.3'. The intro screen should open only first time when the app is launched but it opens everytime i run my app. How to launch is only the first time?
public class IntroActivity extends AppIntro {
private PrefManager prefManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addSlide(AppIntroFragment.newInstance("First","This is the first page",
R.drawable.sugar, ContextCompat.getColor(getApplicationContext(),R.color.colorAccent)));
addSlide(AppIntroFragment.newInstance("Second","This is the second page",
R.drawable.baseline_card_giftcard_black_24dp, ContextCompat.getColor(getApplicationContext(),R.color.colorPrimary)));
addSlide(AppIntroFragment.newInstance("Third","This is the third page",
R.drawable.baseline_fastfood_black_18dp, ContextCompat.getColor(getApplicationContext(), R.color.colorPrimaryDark)));
}
#Override
public void onDonePressed(Fragment currentFragment) {
super.onDonePressed(currentFragment);
Intent intent = new Intent(IntroActivity.this,MainActivity.class);
startActivity(intent);
}
#Override
public void onSkipPressed(Fragment currentFragment) {
super.onSkipPressed(currentFragment);
Intent intent = new Intent(IntroActivity.this,MainActivity.class);
startActivity(intent);
}
}
From the documentation for the library, available here:
Finally, declare the activity in your Manifest like so:
<activity android:name="com.example.example.intro"
android:label="#string/app_intro" />
Do not declare the intro as your main app launcher unless you want the intro to launch every time your app starts. Refer to the wiki for an example of how to launch the intro once from your main activity.
This is what the Wiki is referring to:
If the above method is unclear or you're not able to implement the same, then try writing the following code which uses SharedPreferences in your MainActivity.java file:-
/* In your onCreate method */
SharedPreferences sp = getSharedPreferences(MyPrefs, Context.MODE_PRIVATE);
if (!sp.getBoolean("first", false)) {
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("first", true);
editor.apply();
Intent intent = new Intent(this, IntroActivity.class); // Call the AppIntro java class
startActivity(intent);
}
This code reads a shared preference, and if it is found to not exist, or if it's value is false, it creates or edits the preference (so that the condition fails next time) then opens the intro screen.

Dynamically Add button from one activity to another

i am working on an app in which, button Onclick dynamically created a button from one activity and button is appeared in another activity.
So, for your button, see the code below. I'm just using SharedPreferences for testing if button has been clicked before or not.
// Inside your onCreate() method of your SecondActivity.java
((Button)findViewById(R.id.activity2_button)).setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View v) {
getSharedPreferences("SharedPreferences", Context.MODE_PRIVATE).edit().putBoolean("ShowButton", true).commit(); // put Boolean inside SharedPreferences
Intent main = new Intent(this, FirstActivity.class);
main.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(main);
finish();
}
}
And now, the FirstActivity.java code :
public class FirstActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity1_layout);
if (getSharedPreferences("SharedPreferences", Context.MODE_PRIVATE).getBoolean("ShowButton", false))
((Button)findViewById(R.id.activity1_button)).setVisibility(View.VISIBLE);
else
((Button)findViewById(R.id.activity1_button)).setVisibility(View.GONE);
}
}
Test it, and tell me if this works great. Hope it will work for you, Darkball60 :)

Start activity only once

I want my app to start a activity only the first time the app launches.
Any one got any idea?
I found this but it only shows a black screen.
public class WhatsNew extends Activity {
public static final String PREFS_NAME = "MyPrefsFile";
protected void onCreate(Bundle state){
super.onCreate(state);
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean dialogShown = settings.getBoolean("dialogShown", false);
if (!dialogShown) {
// AlertDialog code here
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("dialogShown", true);
editor.commit();
}
}
}
When the app launches, set a flag in the activity preferences that the activity has already run. Default your setting to false, and then only start that activity if the flag isn't set. Note that if the user cleans your application data, or uninstalls it and later installs it again the activity would show again.
I think that you talk about activities like "log" page that you would launch only once in your application's whole life.
For this, you can use sharedPreferences:
SharedPreferences prefs;
SharedPreferences.Editor editor;
and below your startActivity(intent), you add:
prefs = getSharedPreferences("nbRepet",Context.MODE_PRIVATE);
editor = prefs.edit();
editor.putInt("nbRepet", 1);
editor.commit();
Now your variable nbRepet have 1 as value.
After that, you can add these lines ABOVE your startActivity(intent) to verify that your activity was never launched before:
//here you recover nbRepet's value..
preferences = MainActivity.this.getSharedPreferences("nbRepet", MODE_PRIVATE);
int value = preferences.getInt("nbRepet", 0);
//.. and you verify if your activity is launched before.
if(value<1)
{
startActivity(intent);
}
You will need an Activity which checks a persisted boolean. ie,
onCreate(Bundle bundle)
{
boolean firstRun = // persistance method here
Intent toForward;
if(firstRun)
// Create an intent to start you "only once" activity
// persist "firstRun" as false;
else
// Create an intent for your usual startup
startActivity(toForward);
finish();
}
this will do the job for you
package com.example.startup;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main); //we don't need this line
SharedPreferences settings=getSharedPreferences("prefs",0);
boolean firstRun=settings.getBoolean("firstRun",false);
if(firstRun==false)//if running for first time
{
SharedPreferences.Editor editor=settings.edit();
editor.putBoolean("firstRun",true);
editor.commit();
Intent i=new Intent(MainActivity.this,Second.class);//Activity to be launched For the First time
startActivity(i);
finish();
}
else
{
Intent a=new Intent(MainActivity.this,Main.class);//Default Activity
startActivity(a);
finish();
}
}
}
Depends on what "first time" means. Easiest way is to put some flag into the SharedPreferences... but that can stay around for a while. ^^
If you mean that onCreate should be invoked only once when "start only once when app is launched", you could set the launchMode of the acitivty to singleInstance or singleTask in the manifest.
See my answer in this post, regarding this same issue.
I recommend checking the SharedPreference value for whether the app has previously been ran, inside of the onResume().

Categories

Resources