Odpowiedzi:
AKTUALIZACJA : Android SDK 11 dodał recreate()metodę do działań.
Zrobiłem to, po prostu ponownie wykorzystując intencję, która zapoczątkowała działanie. Zdefiniuj intencję starterIntentw swojej klasie i przypisz ją onCreate()za pomocą starterIntent = getIntent();. Następnie, gdy zechcesz wznowić aktywność, zadzwońfinish(); startActivity(starterIntent);
Nie jest to bardzo eleganckie rozwiązanie, ale jest to prosty sposób na ponowne uruchomienie aktywności i wymuszenie ponownego załadowania wszystkiego.
finish()zaraz po tym startActivity()właśnie z tego powodu ...
finish();potemstartActivity(starterIntent);
Wywołaj metodę odtwarzania aktywności.
recreate()ale teraz widzę dziwny problem, w którym przyciski radiowe nie są resetowane podczas odtwarzania, ale robią to, kiedy finish(); startActivity(getIntent());używam tego teraz i zobaczę, jak to działa w ciągu następnych dni lub tygodni.
Łącząc tutaj niektóre odpowiedzi, możesz użyć czegoś takiego jak poniżej.
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();
}
}
}
Trochę to przetestowałem i jest kilka problemów:
startActivity(...); finish();po prostu istnieje aplikacji i nie powoduje ponownego uruchomienia działania.super.recreate()w rzeczywistości nie działa tak samo, jak całkowite odtworzenie czynności. Jest to równoważne z obracaniem urządzenia, więc jeśli masz jakieś Fragmentpliki, setRetainInstance(true)nie zostaną one odtworzone; po prostu zatrzymał się i wznowił.Więc obecnie nie wierzę, że istnieje akceptowalne rozwiązanie.
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMBzamiast używać11
startActivity(getIntent());finish();nafinish();startActivity(getIntent());
Zadzwoń recreate()do swojego Activity. Jednak ta metoda powoduje, że podczas odtwarzania aktywności pojawia się migający czarny ekran.
finish();
startActivity(getIntent());
Brak „migającego” czarnego ekranu, ale zobaczysz przejście między starymi i nowymi instancjami z niezbyt przyjemnym czarnym tłem. Możemy zrobić lepiej.
Aby to naprawić, możemy dodać wywołanie do overridePendingTransition():
finish();
startActivity(getIntent());
overridePendingTransition(0, 0);
Żegnaj czarny ekran, ale w moim przypadku nadal widzę jakieś przejście (animacja zanikania), tym razem na kolorowym tle. Dzieje się tak, ponieważ kończysz bieżącą instancję swojej aktywności, zanim nowa zostanie utworzona i stanie się w pełni widoczna, a kolor pośredni jest wartością windowBackgroundatrybutu motywu.
startActivity(getIntent());
finish();
Wywołanie finish() po startActivity() spowoduje użycie domyślnego przejścia między czynnościami, często z małą animacją wsuwaną. Ale przejście jest nadal widoczne.
startActivity(getIntent());
finish();
overridePendingTransition(0, 0);
Dla mnie jest to najlepsze rozwiązanie, ponieważ uruchamia ponownie aktywność bez widocznego przejścia, jakby nic się nie stało.
Może to być przydatne, jeśli na przykład w swojej aplikacji ujawnisz sposób zmiany języka wyświetlania niezależnie od języka systemu. W takim przypadku za każdym razem, gdy użytkownik zmieni język aplikacji, prawdopodobnie będziesz chciał ponownie uruchomić swoją aktywność bez przejścia, dzięki czemu zmiana języka będzie wyglądać na natychmiastową.
Kiedy muszę ponownie uruchomić działanie, używam następującego kodu. Chociaż nie jest to zalecane.
Intent intent = getIntent();
finish();
startActivity(intent);
dla API przed 11 nie możesz użyć recate (). Rozwiązałem w ten sposób:
Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();
i w 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
}
Poszukując narzędzia do piernika dla recreate, chciałbym użyć następujących kodów (dla pierników):
activity.mMainThread.mAppThread.scheduleRelaunchActivity(activity.mToken, null, null, 0, false, null);
W przypadku tych kodów pochodzi z implementacji w wyższym 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 nie ma requestRelaunchActivity, jednak z różnicy znalazłem to:
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);
}
Więc myślę, że mógłbym użyć scheduleRelaunchActivityzamiastrequestRelaunchActivity .
Napisałem je za pomocą refleksji:
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);
}
}
Używam tych kodów do wstecznego przenoszenia platformy Xposed.
Build.VERSION_CODES.ECLAIR_MR1(v7). Może działać również na starszych wersjach.
Jeśli to jest twój problem, prawdopodobnie powinieneś zaimplementować inny sposób wypełniania widoku w swoim działaniu. Zamiast uruchamiać ponownie onCreate(), powinieneś tak zrobić, aby wywołać onCreate()metodę wypełniania z jakimś argumentem. Gdy dane ulegną zmianie, metoda fill powinna zostać wywołana z innym argumentem.
Sposób, w jaki to rozwiązałem, polega na użyciu fragmentów . Są one kompatybilne wstecz do API 4 przy użyciu biblioteki obsługi.
Tworzysz układ „opakowujący” z FrameLayout w nim.
Przykład:
<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>
Następnie tworzysz FragmentActivity, w którym możesz zamienić FrameLayout w dowolnym momencie.
Przykład:
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();
}
W fragmencie, który nadmuchujesz / zastępujesz, możesz użyć onStart i onCreateView tak, jak normalnie używałbyś onCreate działania.
Przykład:
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();
}
}
Kiedyś stworzyłem aplikację testową, która przesyła, usuwa, a następnie ponownie pobiera plik bazy danych przy użyciu magazynu w chmurze Firebase. Aby wyświetlić dane w bazie danych, poniższy kod był jedynym rozwiązaniem, które znalazłem. Ani recreate()nie finish()działał w tym przypadku.
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
System.exit(0);
Znalazłem najlepszy sposób na odświeżenie Twojego fragmentu, gdy zmienią się dane
jeśli masz przycisk „szukaj”, musisz zainicjować listę ARRAY wewnątrz przycisku
mSearchBtn.setOnClickListener (new View.OnClickListener () {
@Override public void onClick (widok 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 );
}
Jeśli chcesz przekazać parametr do onCreate (), musisz utworzyć nową intencję, dodając dodatkowe i wywołać z nią StartActivity. Oto prosty przykład, który zrobiłem w ten sposób.
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);
}
Jeśli chcesz tylko powtórzyć swój pogląd, miałem dokładnie ten sam problem. W onResumefunkcji spróbuj umieścić to:
mView = new AndroidPinballView(getApplication());
To też było w moim onCreate(), więc włożenie tego onResumezadziałało dla mnie :)