146

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?

Pentium10
  • 204,586
  • 122
  • 423
  • 502

17 Answers17

154

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.

Alireza Noorali
  • 3,129
  • 2
  • 33
  • 80
Steve Haley
  • 55,374
  • 17
  • 77
  • 85
  • 9
    actually i think when the device orientation changes the activity's oncreate is called in a similar way.. so i don't mind doing this. startActivity(getIntent()); finish(); – Raja Mar 21 '10 at 19:42
  • it isnt smart to do startActivity(getIntent()) as it will just layer activities on top of activities. Need to end the old activity – Fallenreaper Oct 08 '12 at 20:24
  • 8
    @Fallenreaper I suggested calling `finish()` immediately after the `startActivity()` for precisely that reason... – Steve Haley Oct 08 '12 at 22:28
  • startActivity(starterIntent) I used in onPause. Its working fine with onBackPressed clicked but failed to relaunched when pressed Home. please help! – Ranjitsingh Chandel Jan 04 '14 at 12:25
  • 7
    I achieved it calling first `finish();` then `startActivity(starterIntent);` – Carlo Espino Oct 15 '14 at 17:42
  • 3
    So which is it? finish() and Then startActivity? Or the other way around? – Jeff Padgett Sep 13 '18 at 20:47
  • Note that previous activity is still in Task and will be destroyed after 10seconds, not right away – Jemshit Dec 20 '21 at 10:47
99

Call the recreate method of the activity.

FernandoEscher
  • 2,940
  • 2
  • 28
  • 27
  • 21
    This is ok if your app is only targeting SDK level 11 and above. Otherwise I'd go with Steve Haley's approach. – TalkLittle Dec 15 '11 at 22:53
  • 1
    @FernandoEscher Unfortunately that is only available on Honeycomb devices and up. – IgorGanapolsky Feb 10 '13 at 19:20
  • 2
    where to call recreate method – SAndroidD May 22 '14 at 08:27
  • 1
    recreate method call repaetdedly fourcefully close the app – SAndroidD May 22 '14 at 08:47
  • I used to utilze `recreate()` but now I see an odd problem where radio buttons do not get reset when recreating, but they do when `finish(); startActivity(getIntent());` so I'm using this for now and see how it works over the next days or weeks. – Ben Oct 05 '18 at 15:06
  • recreate causes the crash ```E/ActivityInjector: get life cycle exception java.lang.ClassCastException: android.os.BinderProxy cannot be cast to android.app.servertransaction.ClientTransaction``` – nAkhmedov Sep 11 '22 at 13:26
72

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.

Mickäel A.
  • 9,012
  • 5
  • 54
  • 71
  • 1
    A problem with option 5 is it adds the previous activity to the backstack. Call this several times and your user has to click back a bunch of times to get to the real previous page. – Ollie May 24 '19 at 11:20
  • 1
    @Ollie I use the approach to restart the "whole" app and use `finishAffinity` instead of `finish` in option 5. Note that my main activity has the `android:launchMode="singleTask"` set. – Bruno Bieri Oct 02 '20 at 14:27
  • 5th option is very helpful to recreate activity without any animation. – M DEV Jul 10 '22 at 18:43
38

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:

  1. If the activity is the lowest one on the stack, calling startActivity(...); finish(); just exist the app and doesn't restart the activity.
  2. 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.

Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • 5
    `Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB` instead of using `11` – S.Thiongane Feb 19 '14 at 12:33
  • 4
    11 is rigth, .HONEYCOMB not right, because your code in SDK < 11 not know wtat is HONEYCOMB. – Tapa Save Apr 13 '14 at 18:12
  • 6
    replace `startActivity(getIntent());finish();` to `finish();startActivity(getIntent());` – ahmed hamdy Jun 09 '14 at 16:28
  • No, according to recommendation you should target the highest available sdk, so honeycomb will be available at compile time, and the int constant is carried within your application. I believe it is a common pattern to use a sdk int greater than minimum sdk int. – Hai Zhang Mar 04 '15 at 01:38
24

When I need to restart an activity, I use following code. Though it is not recommended.

Intent intent = getIntent();
finish();
startActivity(intent);
Ayush Goyal
  • 2,079
  • 8
  • 32
  • 47
7

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

}
3

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.

liudongmiao
  • 455
  • 4
  • 7
  • Fantastic work! I tested in an emulator, and this approach is backwards compatible to `Build.VERSION_CODES.ECLAIR_MR1` (v7). It may work on older versions as well. – Tim Cooke Aug 12 '16 at 21:05
3

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().

neo
  • 71
  • 1
  • 9
1

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();
    }
}
Spikey
  • 11
  • 1
1

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.

MrSnowflake
  • 4,724
  • 3
  • 29
  • 32
1

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.

danyapd
  • 2,516
  • 1
  • 14
  • 23
1

In case you want to use recreate and target Android versions lower than 11, use ActivityCompat.recreate(...) using the platform support APIs.

bompf
  • 1,374
  • 1
  • 18
  • 24
  • Oops, I just saw that the method was introduced in **SDK level** 11, not Android 11. I guess it could have been useful in the old days of Android. – bompf Jun 02 '22 at 10:17
0

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);
Hasan El-Hefnawy
  • 1,249
  • 1
  • 14
  • 20
0

Worked!

    intent.flags = Intent.FLAG_ACTIVITY_NO_ANIMATION
    startActivity(intent)
    overridePendingTransition( 0, 0)
    finish()
Fahmi Eshaq
  • 318
  • 3
  • 10
-4

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 :)

999k
  • 6,257
  • 2
  • 29
  • 32
Scumble373
  • 227
  • 3
  • 7
-4

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 );

        }
eglease
  • 2,445
  • 11
  • 18
  • 28
-4

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 targetValue = sa.getItem(position).getValue();
if (!Util.IsNullOrEmpty(eczSabit)) {
    String regex = "^[+-]?\\d+$"; // regex to match a valid Long number
    if (eczSabit.matches(regex)) {
        Long targetValueLong = Long.parseLong(targetValue);
        Intent intent = new Intent(eczaneSegmentasyon.this, eczaneSegmentasyon.class);
        intent.putExtra("sabit", targetValueLong);
        startActivity(intent);
    } else {
        // handle the case where eczSabit is not a valid Long number
        // for example, show an error message to the user
    }
}
    

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // your code here
        Long extraLongValue = 
        intent.getLongExtra("sabit", 0L);

    }
}


              
Jeff Bootsholz
  • 2,971
  • 15
  • 70
  • 141
Mustafa Güven
  • 15,526
  • 11
  • 63
  • 83