После некоторых изменений в моей базе данных, которые связаны с существенным изменением в моих представлениях, я хотел бы перерисовать, повторно выполнить onCreate.
Как это возможно?
После некоторых изменений в моей базе данных, которые связаны с существенным изменением в моих представлениях, я хотел бы перерисовать, повторно выполнить onCreate.
Как это возможно?
ОБНОВЛЕНИЕ: Android SDK 11 добавил метод recreate()
к действиям.
Я сделал это, просто повторно использовав намерение, положившее начало деятельности. Определите намерение starterIntent
в вашем классе и назначьте его в onCreate()
, используя starterIntent = getIntent();
. Затем, когда вы хотите возобновить действие, позвоните finish(); startActivity(starterIntent);
Это не очень элегантное решение, но это простой способ перезапустить свою деятельность и заставить ее перезагрузить все.
Вызвать recreate метод активности.
Объединяя некоторые ответы здесь, вы можете использовать что-то вроде следующего.
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)
, они не будут воссозданы; просто приостановился и возобновился.Поэтому в настоящее время я не считаю, что есть приемлемое решение.
Когда мне нужно перезапустить действие, я использую следующий код. Хотя это не рекомендуется.
Intent intent = getIntent();
finish();
startActivity(intent);
Вызовите recreate()
для вашей Activity
. Однако этот метод приводит к появлению мигающего черного экрана во время повторного создания действия.
finish();
startActivity(getIntent());
Здесь нет "мигающего" черного экрана, но вы увидите переход между старым и новым экземплярами с не очень приятным черным фоном. Мы можем сделать лучше.
Чтобы это исправить, мы можем добавить вызов overridePendingTransition()
:
finish();
startActivity(getIntent());
overridePendingTransition(0, 0);
До свидания черный экран, но в моем случае я все еще вижу какой-то переход (анимация исчезновения), на этот раз на цветном фоне. Это потому, что вы заканчиваете текущий экземпляр своей деятельности до того, как новый будет создан и станет полностью видимым, а промежуточный цвет является значением windowBackground
темы windowBackground
.
startActivity(getIntent());
finish();
Вызов startActivity()
finish()
после startActivity()
будет использовать переход по умолчанию между действиями, часто с небольшой вставкой анимации. Но переход все еще виден.
startActivity(getIntent());
finish();
overridePendingTransition(0, 0);
Для меня это лучшее решение, потому что оно перезапускает активность без видимого перехода, как будто ничего не произошло.
Это может быть полезно, если, например, в вашем приложении вы предлагаете способ изменить язык отображения независимо от языка системы. В этом случае всякий раз, когда пользователь меняет язык вашего приложения, вы, вероятно, захотите перезапустить свою деятельность без перехода, чтобы переключение языка выглядело мгновенно.
для API до 11 вы не можете использовать recreate(). Я решил таким образом:
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, однако, из diff, я нашел это:
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);
}
Поэтому я думаю, что вместо requestRelaunchActivity
можно использовать scheduleRelaunchActivity
.
И я написал их с помощью размышлений:
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 framework.
Если это ваша проблема, вы должны, вероятно, реализовать другой способ сделать вид, заполняющий вашу активность. Вместо повторного запуска onCreate()
вы должны сделать так, чтобы onCreate()
вызывал ваш метод заполнения некоторым аргументом. Когда данные изменяются, метод заполнения должен вызываться с другим аргументом.
Как я решил, используя Fragments. Они обратно совместимы до 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();
}
}
Вызовите метод recreate()
откуда вы хотите воссоздать свою деятельность. Этот метод уничтожит текущий экземпляр Activity с помощью onDestroy()
а затем заново onCreate()
действие с помощью onCreate()
.
Возможно, это перебор, но: fooobar.com/questions/21649/... (перезапускает приложение, обеспечивая обходной путь для проблемы утечки ресурсов собственной библиотеки.)
Однажды я сделал тестовое приложение, которое загружает, удаляет, а затем перезагружает файл базы данных, используя облачное хранилище Firebase.
Для отображения данных в базе данных единственным решением, которое я нашел, был следующий код. Ни recreate()
, ни finish()
в этом случае не работали.
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
System.exit(0);
Если вы хотите передать параметр 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
:)