How do I recreate the activity only once after opening the application?
I tried to do this, but it didn't work. Endlessly recreate()
refreshLang() in onCreate
private fun refreshLang() {
PreferenceManager.getDefaultSharedPreferences(this).apply {
val checkRun = getString("FIRSTRUN", "DEFAULT")
if (checkRun == "YES") {
PreferenceManager.getDefaultSharedPreferences(this#MainActivity).edit().putString("FIRSTRUN", "NO").apply()
recreate()
}
}
}
and SharPref.putString("FIRSTRUN", "YES").apply() in onDestroy to make it work again the next time you run it.
Please refer: Activity class
recreate()
It create new instance and initiates fresh activity lifecycle.
So when you call recreate() it will call onCreate() and will go in endless loop.
You have add some condition to avoid this overflow.
Edit:
Use .equals instead of ==
if ("YES".equals(checkRun)) {
PreferenceManager.getDefaultSharedPreferences(this#MainActivity).edit().putString("FIRSTRUN", "NO").apply()
recreate()
}
I suggest you not to use recreate(). It will call onCreate and onDestory().
Refer below code.
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean recreateRequested = true;
Intent currentIntent = getIntent();
if (currentIntent.hasExtra("recreateRequested")){
recreateRequested = currentIntent.getBooleanExtra("recreateRequested", true);
}
if (recreateRequested) {
Intent intent = new Intent(this, MyActivity.class);
intent.putExtra("recreateRequested", false);
startActivity(intent);
finish();
}
}
you can't compare two Strings like this in your if condition
checkRun == "YES"
these are two separated instances of String, so they never be equal in the this meaning (== - same object)
use this instead
"YES".equals(checkRun)
equals will compare "content" of compared objects, in String case it will compare text
use onResume Method
#Override
public void onResume() {
super.onResume(); // Always call the superclass method first
}
Related
I am using onStop() to save a boolean value which I need when the activity resumes.
Here is my code:
#Override
protected void onStop()
{
super.onStop();
Bundle bundle = new Bundle();
bundle.putBoolean("value",value);
getIntent().putExtras(bundle);
}
#Override
protected void onResume()
{
super.onResume();
if(getIntent().getExtras() != null)
{
Bundle bundle = getIntent().getExtras();
value = bundle.getBoolean("value");
}
}
My issue is no matter what the value of the boolean is, my onResume() always retrieves it as FALSE. This issue only occurs if I leave my activity using the BACK button. If I press home, things seem to work fine(i.e if the boolean was TRUE then onResume() retrieves it as TRUE.
Please do help me because I don't understand why onResume() always gets the value of the boolean as FALSE even when I save it as TRUE in onStop().
I also tried onRestart(), onPause() and onBackPressed() but I still can't get the proper boolean value to be saved.
You have two issues here.
the correct way to save values during activity destruction is to use onSaveInstanceState(Bundle) and get the value from the Bundle passed to onCreate(Bundle).
Check example below:
public class SavedInstanceExample extends AppCompatActivity {
private boolean myBoolean;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_savded_instace_example);
if (savedInstanceState != null) {
myBoolean = savedInstanceState.getBoolean("key");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("key", myBoolean);
}
}
When you press the back button the activity will be finished. That means completely gone. And values saved one the methods explained above will not be there.
The way to save something to survive the Activity being finished is to save it to the disk. One common/simple way to do it is using the SharedPreferences
When the Android application opens the following activity lifecycle methods will be called.
onCreate();
onStart();
onResume();
and when you press the back button, the application will be destroyed by calling following methods
onPause();
onStop();
onDestroy();
And in the second case when you press home button the following methods will be called
onPause();
onStop();
That means your application is not destroyed completely and you can open it from recent apps so that the activity re-appears by calling
onStart();
onStop();
That is why your code works in this case.
Activity gives onSavedInstanceState() method to save your data during configuration changes or something else.
Here is the link for Android documentation for
Activity
I would suggest you to read the Google Developers Link for Activity documentation.Google Developers Activity
The OP's code is basically right. onSavedInstanceState is no good if you are not destroying the activity but, for example, replacing a fragment in an activity with another fragment and then returning to it, in which case you have to use onStop and onResume as follows. This is Kotlin and it works but the principle is the same.
override fun onStop() {
super.onStop()
val bundle = Bundle()
bundle.putBoolean("BOOL", false)
activity?.intent?.putExtras(bundle)
}
override fun onResume() {
super.onResume()
if (activity?.intent?.extras != null) {
val bundle = activity?.intent?.extras
val bool = bundle?.getBoolean("BOOL")
println("BOOL is $bool")
}
}
My Java's a bit rusty but I suspect the OP's problem might have been that he mixed up boolean and Boolean?
I am new to android and learning things with fragments and have made a demo for it,in that i am having a fragment from which we can go to another activity at there some calculation is performing and after that we come back to frgament at that time i want to dislay that calculation value to my fragment's textview,So which life cycle method should i use to do so?i already used onresume which is not working...
public void onResume () {
super.onResume();
//tvFollowings.setText((sharedConnect.getCurrentUser().userFollowingCount)
// + " Following");
System.out.print("------user count is-------" + String.valueOf(sharedConnect.getCurrentUser().userFollowingCount));
Toast.makeText(getActivity(), "------user count is-------" + String.valueOf(sharedConnect.getCurrentUser().userFollowingCount), Toast.LENGTH_SHORT).show();
}
Yout have to use startActivityForResult(...) when calling your activity, then you can get any information you need in your fragments onActivityResult().
The best approach which works, toggle between onPause and onResume. No need to even bother the parent activity
private boolean allowRefresh = false;
#Override
public void onResume() {
super.onResume();
//Initialize();
if(allowRefresh){
allowRefresh=false;
//call your initialization code here
}
}
#Override
public void onPause() {
super.onPause();
if (!allowRefresh)
allowRefresh = true;
}
onResume will always be called when your fragment gets loaded, so initial state of allowRefresh should be false so the fragment does not get loaded twice
Once you open new activity whilst the fragment is active, onPause is called, here set allowRefresh to true only if allowRefresh is false.
When the fragment regains focus, check if allowRefresh is true and redo your initialization. A good code practice is put all your initialization code in one function.
You can use Bundle to do the same in Android
Create the intent:
Intent i = new Intent(this, ActivityTwo.class);
AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.autocomplete);
String getrec=textView.getText().toString();
//Create the bundle
Bundle bundle = new Bundle();
//Add your data to bundle
bundle.putString(“stuff”, getrec);
//Add the bundle to the intent
i.putExtras(bundle);
//Fire that second activity
startActivity(i);
Now in your second activity retrieve your data from the bundle:
//Get the bundle
Bundle bundle = getIntent().getExtras();
//Extract the data…
String stuff = bundle.getString(“stuff”);
You can refer here for more.POST
You can use the onResume() method of the Fragment
public class Fragment_ABC extends Fragment {
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_abc, container, false);
return view;
}
#Override
public void onResume() {
super.onResume();
// PERFORM YOUR OPERATION OVER HERE
}
}
Let me know if this works for you ! :)
In your fragment write below code and overide onActivityResult(int requestCode, int resultCode, Intent data) method
Intent intent = new Intent(getApplicationContext(),TrendingQuestions.class);
intent.putExtra("categoryId", Integer.parseInt(categoryId));
startActivityForResult(intent, 101);
In your next activity after you got the result just set result
Intent result = new Intent();
setResult(Activity.RESULT_OK, result);
finish();
If onActivityResult is not getting called please check this link
Then do one thing .. use the Activities onResume Method in which you are showing the Fragment and then from within this Activity's OnResume call the Fragment' Function where you want to refresh the Fragment.
For example.
You have a Activity_A in which you have defined the fragment, let it be Fragemtn_A. Now you are navigating to Activity_B from within this Fragment_A.
Now when you are leaving Activity_B, then the onResume() method of the Activity_A will be called for sure, and from the onResume() of Activity_A you can call the function of Fragment_A and perform your operations that you want.
For calling any fragment's function from withing the Activity you can follow this link :
Calling a Fragment method from a parent Activity
Let me know if this works for you! :)
In one method i start a new activity
public void start(){
Intent i = new Intent(mContext, Screen.class);
mContext.startActivity(i);
//Here i want to get the new activity
Activity a = ...
//Do something with new activity
}
After calling starActivity() i need to get that new Activity and doing something with it.
Is it possible??
EDIT:
Well i have these methods on my Screen class:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadedScreen = false;
}
public void loadScreen(String folderResources, String nameXml, String nameScren){
//Do something
}
loadScreen read an XML file and create by code all user interface, instead of doing in onCreate
In another class I call foo():
public void goToScreen(String nameScreen){
Class screen = Screen.class;
Intent i = new Intent(mContext, screen);
mContext.startActivity(i);
//Here in screen.getMethod... i need use a instance of Screen, which i think it have to be created in `startActivity()`
Method loadUrl = screen.getMethod("loadScreen", String.class, String.class, String.class);
loadUrl.invoke(screen, "folder-s","screen1","screen1.xml");
}
I need call to loadScreen after startActivitybecause this method load all views. I use reflection for doing this. So i need get that new Activity
After calling starActivity() i need to get that new Activity and doing something with it.
Once you call startActivity(), the other activity does not yet exist -- it will not exist for some time.
I need call to loadScreen after startActivitybecause this method load all views.
Call loadScreen() from onCreate() of the Screen activity.
If you wish to pass the values of folderResources, nameXml, and nameScren to Screen, do so by calling putExtra() on the Intent you use with startActivity(). Then, Screen can call getIntent().getStringExtra() in onCreate() to retrieve those values, in order to pass them to loadScreen().
I need to know a generic way to distinguish between a call of activity from launcher and a call from another activity from inside my app, or a BACK on the activity stack
Anyone? this is bugging me for quite a while now and i need to put it to rest...
Thanks in advance
JQCorreia
In the onCreate of your Activity, call getIntent(). If the Activity is started from the launcher (home screen) the values for getAction() will be android.intent.action.MAIN and the getCategories() will return a set which will contain the android.intent.category.LAUNCHER category.
If the activity is started from elsewhere these values may be null.
In addition to #advantej's answer, you can extend each start-call to that activity adding an extra to the starting intent (e.g. intent.putExtra("caller", this.getClass().getSimpleName());
In the activity's onCreate method you can check then what #advantej suggests.
If the initiator is not the home-screen icon, than you can check further if the intent.hasExtra("caller") returns true, and if so, what is it.
You can find it out from intent flag.
step 1:
Intent intent = getIntent();
int flag = intent.getFlag();
step 2:
if flag = Intent.FLAG_ACTIVITY_NEW_TASK
launch from other app or activities
else
launch from home page
in 2 cases the onRestart(); called, 1.when activity come from background, 2.when the user reach the activity by back button then sample solution:
use onBackPressed() function to set a flag.. so u know that onRestart called becouse of back button press...
in onRestart () check the flag and reset it and....
Based on advantej's answer, here is a full example that also hides the UP button if the activity was launched from a launcher icon:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sell);
/**
* If this activity was started from launcher icon, then don't show the Up button in the action bar.
*/
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
Intent intent = getIntent();
Set<String> intentCategories = intent.getCategories();
boolean wasActivityStartedFromLauncherIcon = Intent.ACTION_MAIN.equals(intent.getAction()) && intentCategories != null && intentCategories.contains(Intent.CATEGORY_LAUNCHER);
boolean showUpButton = !wasActivityStartedFromLauncherIcon;
actionBar.setDisplayHomeAsUpEnabled(showUpButton);
}
}
Here's convenience method so you don't need to write it yourself:
protected boolean isStartedByLauncher() {
if (getIntent() == null) {
return false;
}
boolean isActionMain = Intent.ACTION_MAIN.equals(getIntent().getAction());
Set<String> categories = getIntent().getCategories();
boolean isCategoryLauncher = categories != null && categories.contains(Intent.CATEGORY_LAUNCHER);
return isActionMain && isCategoryLauncher;
}
The simplest approach that I can think of would be to pass a flag while launching the activity from your own activities. You should also check if the activity was created or resumed, this can be done by setting a boolean in the onCreate method, and then checking it onResume.
Below is the code you can use (not tested):
Activity in which you want to check (say MainActivity.class):
Boolean onCreateCalled = false;
Boolean calledFromAppActivities = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onCreateCalled = true;
Bundle mainData = getIntent().getExtras();
if (mainData != null) {
if (getIntent().hasExtra("call_from_own_activity")) {
calledFromAppActivities = true;
}
}
.....
}
#Override
protected void onResume() {
super.onResume();
if (onCreateCalled && !calledFromAppActivities) {
// The app was not called from any of our activities.
// The activity was not resumed but was created.
// Do Stuff
}
// To stop it from running again when activity is resumed.
onCreateCalled = false;
....
}
When calling MainActivity from other activities, use the code below:
private void call_main () {
Intent i = new Intent(getApplicationContext(), MainActivity.class);
i.putExtra("call_from_own_activity", true);
startActivity(i);
}
After I do some change in my database, that involves significant change in my views, I would like to redraw, re-execute onCreate.
How is that possible?
UPDATE: Android SDK 11 added a recreate() method to activities.
I've done that by simply reusing the intent that started the activity. Define an intent starterIntent in your class and assign it in onCreate() using starterIntent = getIntent();. Then when you want to restart the activity, call finish(); startActivity(starterIntent);
It isn't a very elegant solution, but it's a simple way to restart your activity and force it to reload everything.
Call the recreate method of the activity.
Option 1
Call recreate() on your Activity.
However this method causes a flashing black screen to appear during the activity re-creation.
Option 2
finish();
startActivity(getIntent());
No "flashing" black screen here, but you'll see a transition between the old and the new instances with a not-so-pleasant black background. We can do better.
Option 3
To fix this, we can add a call to overridePendingTransition() :
finish();
startActivity(getIntent());
overridePendingTransition(0, 0);
Good bye black screen, but in my case I still see some kind of transition (a fade animation), on a colored background this time. That's because you're finishing the current instance of your activity before the new one is created and becomes fully visible, and the in-between color is the value of the windowBackground theme attribute.
Option 4
startActivity(getIntent());
finish();
Calling finish() after startActivity() will use the default transition between activities, often with a little slide-in animation. But the transition is still visible.
Option 5
startActivity(getIntent());
finish();
overridePendingTransition(0, 0);
To me, this is the best solution because it restarts the activity without any visible transition, like if nothing happened.
It could be useful if, for example, in your app you expose a way to change the display language independently of the system's language. In this case, whenever the user changes your app's language you'll probably want to restart your activity without transition, making the language switch look instantaneous.
Combining some answers here you can use something like the following.
class BaseActivity extends SherlockFragmentActivity
{
// Backwards compatible recreate().
#Override
public void recreate()
{
if (android.os.Build.VERSION.SDK_INT >= 11)
{
super.recreate();
}
else
{
startActivity(getIntent());
finish();
}
}
}
Testing
I tested it a bit, and there are some problems:
If the activity is the lowest one on the stack, calling startActivity(...); finish(); just exist the app and doesn't restart the activity.
super.recreate() doesn't actually act the same way as totally recreating the activity. It is equivalent to rotating the device so if you have any Fragments with setRetainInstance(true) they won't be recreated; merely paused and resumed.
So currently I don't believe there is an acceptable solution.
When I need to restart an activity, I use following code. Though it is not recommended.
Intent intent = getIntent();
finish();
startActivity(intent);
for API before 11 you cannot use recreate(). I solved in this way:
Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();
and in onCreate..
#Override
public void onCreate(Bundle savedInstanceState) {
if (getIntent().hasExtra("bundle") && savedInstanceState==null){
savedInstanceState = getIntent().getExtras().getBundle("bundle");
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//code
}
After looking for the gingerbread implement for recreate, I'd like to use following codes (for gingerbread):
activity.mMainThread.mAppThread.scheduleRelaunchActivity(activity.mToken, null, null, 0, false, null);
For these codes, it's from the implementation in higher api.
public void recreate() {
if (mParent != null) {
throw new IllegalStateException("Can only be called on top-level activity");
}
if (Looper.myLooper() != mMainThread.getLooper()) {
throw new IllegalStateException("Must be called from main thread");
}
mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, false);
}
Api-10 has no requestRelaunchActivity, however, from the diff, i found this:
public final void scheduleRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config) {
- ActivityClientRecord r = new ActivityClientRecord();
-
- r.token = token;
- r.pendingResults = pendingResults;
- r.pendingIntents = pendingNewIntents;
- r.startsNotResumed = notResumed;
- r.createdConfig = config;
-
- synchronized (mPackages) {
- mRelaunchingActivities.add(r);
- }
-
- queueOrSendMessage(H.RELAUNCH_ACTIVITY, r, configChanges);
+ requestRelaunchActivity(token, pendingResults, pendingNewIntents,
+ configChanges, notResumed, config, true);
}
So I think I could use scheduleRelaunchActivity instead of requestRelaunchActivity.
And I have written them using reflect:
package me.piebridge.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Build;
import android.os.IBinder;
public class GingerBreadUtil {
private static Field scanField(Class<?> clazz, String... names) {
for (String name : names) {
Field field;
try {
field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
}
try {
field = clazz.getField(name);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
}
}
return null;
}
public static void recreate(Activity activity) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
recreateHC(activity);
} else {
try {
recreateGB(activity);
} catch (InvocationTargetException e) {
e.getTargetException().printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static void recreateHC(Activity activity) {
((Activity) activity).recreate();
}
private static void recreateGB(Activity activity) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Field Activity$mToken = scanField(Activity.class, "mToken");
IBinder mToken = (IBinder) Activity$mToken.get(activity);
Field Activity$mMainThread = scanField(Activity.class, "mMainThread");
Object mMainThread = Activity$mMainThread.get(activity);
Field ActivityThread$mAppThread = scanField(mMainThread.getClass(), "mAppThread");
Object mAppThread = ActivityThread$mAppThread.get(mMainThread);
Method method = mAppThread.getClass().getMethod("scheduleRelaunchActivity",
IBinder.class, List.class, List.class, int.class, boolean.class, Configuration.class);
method.invoke(mAppThread, mToken, null, null, 0, false, null);
}
}
I'm using these codes for the back-porting of xposed framework.
Call the recreate() method from where you want to recreate your activity . This method will destroy current instance of Activity with onDestroy() and then recreate activity with onCreate().
If this is your problem, you should probably implement another way to do the view filling in your Activity. Instead of re running onCreate() you should make it so onCreate() calls your filling method with some argument. When the data changes, the filling method should get called with another argument.
The way I resolved it is by using Fragments. These are backwards compatible until API 4 by using the support library.
You make a "wrapper" layout with a FrameLayout in it.
Example:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Then you make a FragmentActivity in wich you can replace the FrameLayout any time you want.
Example:
public class SampleFragmentActivity extends FragmentActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.wrapper);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.fragment_container) != null)
{
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null)
{
return;
}
updateLayout();
}
}
private void updateLayout()
{
Fragment fragment = new SampleFragment();
fragment.setArguments(getIntent().getExtras());
// replace original fragment by new fragment
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
}
In the Fragment you inflate/replace you can use the onStart and onCreateView like you normaly would use the onCreate of an activity.
Example:
public class SampleFragment extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.yourActualLayout, container, false);
}
#Override
public void onStart()
{
// do something with the components, or not!
TextView text = (TextView) getActivity().findViewById(R.id.text1);
super.onStart();
}
}
Also depending on your situation, you may need getActivity().recreate(); instead of just recreate().
For example, you should use it if you are doing recreate() in the class which has been created inside class of activity.
In case you want to use recreate and target Android versions lower than 11, use ActivityCompat.recreate(...) using the platform support APIs.
I once made a test app that uploads, deletes, and then redownloads the database file using firebase cloud storage.
To display the data in database, the following code was the only solution I found. Neither recreate() nor finish() worked in this case.
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
System.exit(0);
If you want to pass a parameter to onCreate() then you have to create a new intent with adding extra and call StartActivity with it. Here is a simple example which i did using this way.
String eczSabit = sa.getItem(position).getValue();
if(!Util.IsNullOrEmpty(eczSabit)){
sabit = Long.parseLong(eczSabit);
Intent intent = new Intent(eczaneSegmentasyon.this,eczaneSegmentasyon.class);
intent.putExtra("sabit", sabit);
startActivity(intent);
}
i found out the best way to refresh your Fragment when data change
if you have a button "search", you have to initialize your ARRAY list inside the button
mSearchBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mList = new ArrayList<Node>();
firebaseSearchQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
Node p = dataSnapshot1.getValue(Node .class);
mList.add(p);
}
YourAdapter = new NodeAdapter(getActivity(), mList);
mRecyclerView.setAdapter(YourAdapter );
}
If you're just looking to re-do your view, I had the exact same issue. In the onResume function try putting this:
mView = new AndroidPinballView(getApplication());
This was also in my onCreate(), so putting this in the onResume worked for me :)