Answers:
更新:Android SDK 11 recreate()为活动添加了一种方法。
我已经通过简单地重用开始活动的意图来做到这一点。starterIntent在课程中定义一个意图,并onCreate()使用进行分配starterIntent = getIntent();。然后,当您要重新启动活动时,请致电finish(); startActivity(starterIntent);
这不是一个非常优雅的解决方案,但是它是重新启动活动并强制其重新加载所有内容的简单方法。
finish()立即致电startActivity()...
finish();然后startActivity(starterIntent);
调用活动的recreate方法。
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);
对于11之前的API,您不能使用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没有requestRelaunchActivity,但是,从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);
}
所以我想我可以用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)。它也可能适用于旧版本。
我解决它的方法是使用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();
}
在您添加/替换的片段中,您可以像通常使用活动的onCreate一样使用onStart和onCreateView。
例:
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);
我发现了在数据更改时刷新片段的最佳方法
如果您有按钮“搜索”,则必须在按钮内初始化阵列列表
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 );
}
如果要将参数传递给onCreate(),则必须添加一个额外的参数来创建一个新的Intent,并使用它来调用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);
}