Risposte:
AGGIORNAMENTO : Android SDK 11 ha aggiunto un recreate()metodo alle attività.
L'ho fatto semplicemente riutilizzando l'intento che ha avviato l'attività. Definisci un intento starterIntentnella tua classe e assegnalo onCreate()nell'uso starterIntent = getIntent();. Quindi, quando vuoi riavviare l'attività, chiamafinish(); startActivity(starterIntent);
Non è una soluzione molto elegante, ma è un modo semplice per riavviare la tua attività e costringerla a ricaricare tutto.
finish()subito dopo il startActivity()per proprio questo motivo ...
finish();allorastartActivity(starterIntent);
Chiama il metodo di ricreazione dell'attività.
recreate()ma ora vedo uno strano problema in cui i pulsanti di opzione non vengono ripristinati durante la ricreazione, ma lo fanno quando finish(); startActivity(getIntent());lo sto usando per ora e vedo come funziona nei prossimi giorni o settimane.
Combinando alcune risposte qui puoi usare qualcosa come il seguente.
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();
}
}
}
L'ho provato un po 'e ci sono alcuni problemi:
startActivity(...); finish();esiste semplicemente l'app e non riavvia l'attività.super.recreate()in realtà non si comporta come se si ricrea completamente l'attività. È equivalente a ruotare il dispositivo, quindi se ne hai Fragmentcon setRetainInstance(true)non verranno ricreati; si è semplicemente fermato e ha ripreso.Quindi attualmente non credo che ci sia una soluzione accettabile.
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMBinvece di usare11
startActivity(getIntent());finish();afinish();startActivity(getIntent());
Chiama recreate()il tuo Activity. Tuttavia, questo metodo fa apparire una schermata nera lampeggiante durante la ricreazione dell'attività.
finish();
startActivity(getIntent());
Nessuno schermo nero "lampeggiante" qui, ma vedrai una transizione tra le vecchie e le nuove istanze con uno sfondo nero non così piacevole. Possiamo fare di meglio.
Per risolvere questo problema, possiamo aggiungere una chiamata a overridePendingTransition():
finish();
startActivity(getIntent());
overridePendingTransition(0, 0);
Addio schermo nero, ma nel mio caso vedo ancora una sorta di transizione (un'animazione in dissolvenza), questa volta su uno sfondo colorato. Questo perché stai finendo l'istanza corrente della tua attività prima che quella nuova venga creata e diventi completamente visibile, e il colore intermedio è il valore dell'attributo del windowBackgroundtema.
startActivity(getIntent());
finish();
Chiamata finish() dopo startActivity() utilizzerà la transizione predefinita tra le attività, spesso con un po 'di slide-in animazione. Ma la transizione è ancora visibile.
startActivity(getIntent());
finish();
overridePendingTransition(0, 0);
Per me questa è la soluzione migliore perché riavvia l'attività senza nessuna transizione visibile, come se non fosse successo niente.
Potrebbe essere utile se, ad esempio, nella tua app esponi un modo per cambiare la lingua di visualizzazione indipendentemente dalla lingua del sistema. In questo caso, ogni volta che l'utente cambia la lingua della tua app, probabilmente vorrai riavviare la tua attività senza transizione, rendendo il cambio di lingua istantaneo.
Quando ho bisogno di riavviare un'attività, utilizzo il seguente codice. Anche se non è consigliato.
Intent intent = getIntent();
finish();
startActivity(intent);
per le API precedenti alla 11 non è possibile utilizzare recreate (). Ho risolto in questo modo:
Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();
e 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
}
Dopo aver cercato l'attrezzo per pan di zenzero recreate, vorrei utilizzare i seguenti codici (per il pan di zenzero):
activity.mMainThread.mAppThread.scheduleRelaunchActivity(activity.mToken, null, null, 0, false, null);
Per questi codici, proviene dall'implementazione in api superiori.
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 non ha requestRelaunchActivity, tuttavia, dal diff, ho trovato questo:
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);
}
Quindi penso che potrei usare scheduleRelaunchActivityinvece di requestRelaunchActivity.
E li ho scritti usando riflettere:
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);
}
}
Sto usando questi codici per il back-porting del framework xposed.
Build.VERSION_CODES.ECLAIR_MR1(v7). Potrebbe funzionare anche su versioni precedenti.
Se questo è il tuo problema, dovresti probabilmente implementare un altro modo per eseguire la visualizzazione compilando la tua attività. Invece di eseguire nuovamente onCreate(), dovresti fare in modo che onCreate()chiami il tuo metodo di riempimento con qualche argomento. Quando i dati cambiano, il metodo di riempimento dovrebbe essere chiamato con un altro argomento.
Il modo in cui l'ho risolto è usando Fragments . Questi sono compatibili con le versioni precedenti fino all'API 4 utilizzando la libreria di supporto.
Si crea un layout "wrapper" con un FrameLayout in esso.
Esempio:
<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>
Quindi crei una FragmentActivity in cui puoi sostituire FrameLayout ogni volta che vuoi.
Esempio:
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();
}
Nel Fragment che gonfi / sostituisci puoi usare onStart e onCreateView come faresti normalmente con onCreate di un'attività.
Esempio:
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();
}
}
Una volta ho creato un'app di prova che carica, elimina e quindi scarica nuovamente il file di database utilizzando l'archiviazione cloud Firebase. Per visualizzare i dati nel database, il codice seguente è stata l'unica soluzione che ho trovato. Né recreate()né ha finish()funzionato in questo caso.
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
System.exit(0);
ho scoperto il modo migliore per aggiornare il tuo frammento quando i dati cambiano
se hai un pulsante "cerca", devi inizializzare la tua lista ARRAY all'interno del pulsante
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 );
}
Se vuoi passare un parametro a onCreate (), devi creare un nuovo intento con l'aggiunta di extra e chiamare StartActivity con esso. Ecco un semplice esempio che ho fatto usando in questo modo.
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);
}
Se stai solo cercando di rifare la tua visione, ho avuto lo stesso identico problema. Nella onResumefunzione prova a mettere questo:
mView = new AndroidPinballView(getApplication());
Questo era anche nel mio onCreate(), quindi mettere questo nel ha onResumefunzionato per me :)