¿Reactivar / recrear programáticamente una actividad?

Después de hacer algún cambio en mi base de datos, que implica un cambio significativo en mis puntos de vista, me gustaría volver a dibujar, volver a ejecutar onCreate.

¿Cómo es eso posible?

Actualización: Android SDK 11 agregó un método recreate () a las actividades.

Lo he hecho simplemente reutilizando la intención que inició la actividad. Defina un intento de starterIntent intencionado en su clase y onCreate() en onCreate() usando starterIntent = getIntent(); . A continuación, cuando desee reiniciar la actividad, llame a finish(); startActivity(starterIntent); finish(); startActivity(starterIntent);

No es una solución muy elegante, pero es una forma sencilla de reiniciar su actividad y obligarla a recargar todo.

Llame al método recreate de la actividad.

Combinando algunas respuestas aquí puedes usar algo como lo siguiente.

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

Pruebas

Lo probé un poco, y hay algunos problemas:

  1. Si la actividad es la más baja de la pila, llamar startActivity(...); finish(); startActivity(...); finish(); Sólo existe la aplicación y no reinicia la actividad.
  2. super.recreate() no actúa de la misma manera que recreando totalmente la actividad. Es equivalente a girar el dispositivo así que si tienes cualquier Fragment s con setRetainInstance(true) no serán recreados; Simplemente se detuvo y se reanudó.

Así que actualmente no creo que haya una solución aceptable.

Cuando necesito reiniciar una actividad, utilizo el siguiente código. Aunque no es recomendable.

 Intent intent = getIntent(); finish(); startActivity(intent); 

Para API antes de 11 no puede utilizar recreate (). He resuelto de esta manera:

 Bundle temp_bundle = new Bundle(); onSaveInstanceState(temp_bundle); Intent intent = new Intent(this, MainActivity.class); intent.putExtra("bundle", temp_bundle); startActivity(intent); finish(); 

Y en 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 } 

Después de buscar el implemento de pan de jengibre para recreate , me gustaría usar los siguientes códigos (para pan de jengibre):

 activity.mMainThread.mAppThread.scheduleRelaunchActivity(activity.mToken, null, null, 0, false, null); 

Para estos códigos, es a partir de la implementación en api superior.

 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 no tiene requestRelaunchActivity, sin embargo, de la diff, encontré esto:

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

Así que creo que podría usar scheduleRelaunchActivity lugar de requestRelaunchActivity .

Y los he escrito usando reflexionar:

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

Estoy usando estos códigos para el back-porting de marco xposed.

Si este es su problema, probablemente debería implementar otra forma de hacer la vista rellenando su Actividad. En lugar de volver a ejecutar onCreate() , debe hacerlo tan onCreate() llama a su método de llenado con algún argumento. Cuando los datos cambian, el método de llenado debe ser llamado con otro argumento.

La forma en que resolví es mediante el uso de fragmentos . Estos son compatibles con versiones anteriores hasta la API 4 mediante la biblioteca de soporte.

Haces un diseño "wrapper" con un FrameLayout en él.

Ejemplo:

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

Entonces usted hace una FragmentActivity en la que puede reemplazar FrameLayout cuando quiera.

Ejemplo:

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

En el fragmento que inflar / reemplazar puede utilizar el onStart y onCreateView como usted normalmente utilizaría el onCreate de una actividad.

Ejemplo:

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

Tal vez sea una exageración, pero: https://stackoverflow.com/a/13173279/755804 (vuelve a iniciar una aplicación, proporcionando una solución para el problema de la pérdida nativa de recursos de la biblioteca.)

Si quieres pasar un parámetro a onCreate () entonces tienes que crear una nueva intención con añadir extra y llamar a StartActivity con ella. Aquí está un ejemplo simple que hice usando esta manera.

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

Si sólo está buscando volver a hacer su punto de vista, tenía exactamente el mismo problema. En la función onResume pruebe a poner esto:

 mView = new AndroidPinballView(getApplication()); 

Esto también fue en mi onCreate() , por lo que poner esto en el onResume trabajado para mí 🙂

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.