Відповіді:
ОНОВЛЕННЯ : Android SDK 11 додав recreate()метод до заходів.
Я зробив це, просто використовуючи наміри, які розпочали діяльність. Визначте намір starterIntentу своєму класі та призначте його за onCreate()допомогою starterIntent = getIntent();. Потім, коли ви хочете відновити діяльність, зателефонуйтеfinish(); startActivity(starterIntent);
Це не дуже елегантне рішення, але це простий спосіб перезапустити свою діяльність і змусити її перезавантажити все.
finish()одразу після цього startActivity()саме з цієї причини ...
finish();потімstartActivity(starterIntent);
Викличте метод відтворення діяльності.
recreate()але зараз я бачу дивну проблему, коли перемикачі не відновлюються під час відтворення, але вони роблять, коли finish(); startActivity(getIntent());я зараз це використовую і бачу, як це працює протягом наступних днів або тижнів.
Поєднуючи тут деякі відповіді, ви можете використовувати щось на зразок наступного.
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();
}
}
}
Я трохи перевірив це, і є деякі проблеми:
startActivity(...); finish();просто існує програми та не перезапускає діяльність.super.recreate()насправді не діє так само, як повністю відтворювати діяльність. Це еквівалентно обертанню пристрою, тому якщо у вас є якісь Fragmentелементи, setRetainInstance(true)вони не будуть відтворені; просто призупинився і відновився.Тож наразі я не вірю у прийнятне рішення.
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMBзамість того, щоб використовувати11
startActivity(getIntent());finish();наfinish();startActivity(getIntent());
Телефонуйте recreate()на своє Activity. Однак цей метод спричиняє появу миготливого чорного екрану під час відновлення діяльності.
finish();
startActivity(getIntent());
Тут немає «блимаючого» чорного екрана, але ви побачите перехід між старим та новим екземплярами з не дуже приємним чорним фоном. Ми можемо зробити краще.
Щоб виправити це, ми можемо додати виклик до overridePendingTransition():
finish();
startActivity(getIntent());
overridePendingTransition(0, 0);
Прощавай чорний екран, але в моєму випадку я все-таки бачу якийсь перехід (зникаюча анімація) на кольоровому тлі цього разу. Це тому, що ви закінчуєте поточний екземпляр своєї діяльності до того, як новий буде створений і стане повністю видимим, а колір проміжків - це значення windowBackgroundатрибуту теми.
startActivity(getIntent());
finish();
Зателефонувавши finish() після, startActivity() буде використано перехід за замовчуванням між видами діяльності, часто з невеликою анімацією про слайд. Але перехід все ще видно.
startActivity(getIntent());
finish();
overridePendingTransition(0, 0);
Для мене це найкраще рішення, оскільки воно відновлює діяльність без видимого переходу, як якщо б нічого не сталося.
Це може бути корисно, якщо, наприклад, у вашому додатку ви відкриєте спосіб змінити мову відображення незалежно від мови системи. У цьому випадку, кожного разу, коли користувач змінить мову вашої програми, ви, ймовірно, захочете перезапустити свою діяльність без переходу, завдяки чому мовний перемикач виглядає миттєвим.
Коли мені потрібно перезапустити діяльність, я використовую наступний код. Хоча це не рекомендується.
Intent intent = getIntent();
finish();
startActivity(intent);
для API до 11 ви не можете використовувати відтворити (). Я вирішив таким чином:
Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();
і в 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
}
Шукаючи пряниковий інструмент recreate, я хотів би скористатися такими кодами (для пряників):
activity.mMainThread.mAppThread.scheduleRelaunchActivity(activity.mToken, null, null, 0, false, null);
Для цих кодів це від реалізації у вищих 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 не має запитуRelaunchActivity, однак з розл. Я виявив таке:
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);
}
Тому я думаю, що міг би використати scheduleRelaunchActivityзамість цього requestRelaunchActivity.
І я написав їх за допомогою рефлексу:
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);
}
}
Я використовую ці коди для зворотного перенесення xposed фреймворку.
Build.VERSION_CODES.ECLAIR_MR1(v7). Це може працювати і на старих версіях.
Якщо це ваша проблема, ви, ймовірно, повинні реалізувати інший спосіб зробити перегляд, заповнюючи свою діяльність. Замість повторного запуску onCreate()вам слід зробити так, щоб onCreate()викликав ваш метод заповнення деяким аргументом. Коли дані змінюються, метод заповнення повинен викликати інший аргумент.
Я вирішив це за допомогою фрагментів . Вони підтримуються назад до API 4 за допомогою бібліотеки підтримки.
Ви робите макет "обгортки" із рамкою FrameLayout.
Приклад:
<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>
Тоді ви робите FragmentActivity, на яку ви можете замінити FrameLayout в будь-який час.
Приклад:
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();
}
У надутому / заміненому фрагменті ви можете використовувати onStart і onCreateView, як звичайно, він би використовував onCreate активності.
Приклад:
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();
}
}
Я колись зробив тестовий додаток, який завантажує, видаляє, а потім повторно завантажує файл бази даних, використовуючи хмарне сховище firebase. Щоб відобразити дані в базі даних, наступний код був єдиним знайденим рішенням. Ні, recreate()ні finish()працювали в цій справі.
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
System.exit(0);
я знайшов найкращий спосіб оновити ваш фрагмент при зміні даних
якщо у вас є кнопка "пошук", ви повинні ініціалізувати свій список ARRAY всередині кнопки
mSearchBtn.setOnClickListener (новий View.OnClickListener () {
@Override public void onClick (Переглянути 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 );
}
Якщо ви хочете передати параметр onCreate (), вам слід створити новий намір із додаванням додаткового та викликати за допомогою нього StartActivity. Ось простий приклад, який я зробив, використовуючи цей спосіб.
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);
}
Якщо ви просто хочете знову переглянути свій погляд, у мене виникла точно така ж проблема. У onResumeфункції спробуйте поставити це:
mView = new AndroidPinballView(getApplication());
Це було і в моєму onCreate(), тому поклавши це на onResumeвідпрацьоване для мене :)