Réponses:
MISE À JOUR : Android SDK 11 a ajouté une recreate()méthode aux activités.
Je l'ai fait en réutilisant simplement l'intention qui a lancé l'activité. Définissez une intention starterIntentdans votre classe et attribuez-la en onCreate()utilisant starterIntent = getIntent();. Ensuite, lorsque vous souhaitez redémarrer l'activité, appelezfinish(); startActivity(starterIntent);
Ce n'est pas une solution très élégante, mais c'est un moyen simple de redémarrer votre activité et de la forcer à tout recharger.
finish()immédiatement après le startActivity()pour cette raison précisément ...
finish();puisstartActivity(starterIntent);
Appelez la méthode recréer de l'activité.
recreate()mais maintenant je vois un problème étrange où les boutons radio ne sont pas réinitialisés lors de la recréation, mais ils le font quand finish(); startActivity(getIntent());je l'utilise pour le moment et je vois comment cela fonctionne au cours des prochains jours ou semaines.
En combinant quelques réponses ici, vous pouvez utiliser quelque chose comme ce qui suit.
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();
}
}
}
Je l'ai testé un peu, et il y a quelques problèmes:
startActivity(...); finish();existe simplement et ne redémarre pas l'activité.super.recreate()n'agit pas réellement de la même manière que recréer totalement l'activité. Il est équivalent à la rotation du dispositif , donc si vous avez des Fragments avec setRetainInstance(true)elles ne seront pas recréés; simplement mis en pause et repris.Donc, actuellement, je ne pense pas qu'il existe une solution acceptable.
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMBau lieu d'utiliser11
startActivity(getIntent());finish();tofinish();startActivity(getIntent());
Appelez recreate()votre Activity. Cependant, cette méthode fait apparaître un écran noir clignotant lors de la recréation de l'activité.
finish();
startActivity(getIntent());
Pas d'écran noir "clignotant" ici, mais vous verrez une transition entre les anciennes et les nouvelles instances avec un fond noir pas si agréable. On peut faire mieux.
Pour résoudre ce problème, nous pouvons ajouter un appel à overridePendingTransition():
finish();
startActivity(getIntent());
overridePendingTransition(0, 0);
Au revoir écran noir, mais dans mon cas je vois encore une sorte de transition (une animation de fondu), sur un fond coloré cette fois. C'est parce que vous terminez l'instance actuelle de votre activité avant que la nouvelle ne soit créée et devienne entièrement visible, et la couleur intermédiaire est la valeur de l' windowBackgroundattribut de thème.
startActivity(getIntent());
finish();
L'appel finish() après startActivity() utilisera la transition par défaut entre les activités, souvent avec une petite animation de diapositives. Mais la transition est toujours visible.
startActivity(getIntent());
finish();
overridePendingTransition(0, 0);
Pour moi, c'est la meilleure solution car elle redémarre l'activité sans aucune transition visible, comme si de rien n'était.
Cela peut être utile si, par exemple, dans votre application, vous exposez un moyen de changer la langue d'affichage indépendamment de la langue du système. Dans ce cas, chaque fois que l'utilisateur change la langue de votre application, vous voudrez probablement redémarrer votre activité sans transition, ce qui rend le changement de langue instantané.
Lorsque j'ai besoin de redémarrer une activité, j'utilise le code suivant. Bien que ce ne soit pas recommandé.
Intent intent = getIntent();
finish();
startActivity(intent);
pour l'API antérieure à 11, vous ne pouvez pas utiliser receate (). J'ai résolu de cette manière:
Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();
et dans 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
}
Après avoir recherché l'outil de pain d'épice pour recreate, j'aimerais utiliser les codes suivants (pour le pain d'épice):
activity.mMainThread.mAppThread.scheduleRelaunchActivity(activity.mToken, null, null, 0, false, null);
Pour ces codes, c'est de l'implémentation dans une API supérieure.
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 n'a pas de requestRelaunchActivity, cependant, à partir du diff, j'ai trouvé ceci:
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);
}
Je pense donc que je pourrais utiliser à la scheduleRelaunchActivityplace de requestRelaunchActivity.
Et je les ai écrits en utilisant refléter:
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);
}
}
J'utilise ces codes pour le back-porting du framework xposed.
Build.VERSION_CODES.ECLAIR_MR1(v7). Cela peut également fonctionner sur les anciennes versions.
Si tel est votre problème, vous devriez probablement implémenter une autre façon de remplir la vue de votre activité. Au lieu de le relancer, onCreate()vous devriez faire en sorte qu'il onCreate()appelle votre méthode de remplissage avec un argument. Lorsque les données changent, la méthode de remplissage doit être appelée avec un autre argument.
La façon dont je l'ai résolu est en utilisant des fragments . Ceux-ci sont rétrocompatibles jusqu'à l'API 4 en utilisant la bibliothèque de support.
Vous créez une mise en page "wrapper" avec un FrameLayout.
Exemple:
<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>
Ensuite, vous créez un FragmentActivity dans lequel vous pouvez remplacer le FrameLayout à tout moment.
Exemple:
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();
}
Dans le fragment que vous gonflez / remplacez, vous pouvez utiliser onStart et onCreateView comme vous utiliseriez normalement le onCreate d'une activité.
Exemple:
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();
}
}
Une fois, j'ai créé une application de test qui télécharge, supprime, puis retélécharge le fichier de base de données à l'aide du stockage cloud Firebase. Pour afficher les données dans la base de données, le code suivant était la seule solution que j'ai trouvée. Ni recreate()ni finish()travaillé dans ce cas.
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
System.exit(0);
J'ai découvert la meilleure façon d'actualiser votre fragment lorsque les données changent
si vous avez un bouton "recherche", vous devez initialiser votre liste ARRAY à l'intérieur du bouton
mSearchBtn.setOnClickListener (nouveau 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 );
}
Si vous souhaitez passer un paramètre à onCreate (), vous devez créer un nouvel intent en ajoutant un supplément et appeler StartActivity avec. Voici un exemple simple que j'ai fait en utilisant cette façon.
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 vous cherchez simplement à refaire votre vue, j'ai eu exactement le même problème. Dans la onResumefonction, essayez de mettre ceci:
mView = new AndroidPinballView(getApplication());
C'était aussi dans mon onCreate(), donc mettre cela dans le onResumetravaillé pour moi :)