如何避免在Android上的onCreate上重新创建视图?

我有一个显示联系人列表的FragmentActivity

这是我的onCreate方法:

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_human_list); if (findViewById(R.id.human_detail_container) != null) { // The detail container view will be present only in the // large-screen layouts (res/values-large and // res/values-sw600dp). If this view is present, then the // activity should be in two-pane mode. mTwoPane = true; // In two-pane mode, list items should be given the // 'activated' state when touched. ((HumanListFragment) getSupportFragmentManager() .findFragmentById(R.id.human_list)) .setActivateOnItemClick(true); } if (savedInstanceState == null || !savedInstanceState.getBoolean("displayed_contacts")) displayContacts(); } 

我的onSaveInstanceState

 @Override protected void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putBoolean("displayed_contacts", true); } 

而且我不确定这是否相关,但这是我的displayContacts以防万一:

 private void displayContacts() { // Init variables String[] SelectColumns = new String[] { Contacts._ID, Contacts.DISPLAY_NAME_PRIMARY, Contacts.PHOTO_URI }; String rawContactID, displayName, phoneNumber; InputStream thumbnailPhoto; Cursor c, infoC; // Outer cursor (fetches all contact IDs) c = getContentResolver().query( Contacts.CONTENT_URI, SelectColumns, Contacts.HAS_PHONE_NUMBER + " = 1 ", null, Contacts.DISPLAY_NAME_PRIMARY); Log.v(getPackageName(), "Found " + (c != null ? c.getCount() : "0") + " contacts"); try { if (c.moveToFirst()) { do { // Columns rawContactID = c.getString(c.getColumnIndex(SelectColumns[0])); displayName = c.getString(c.getColumnIndex(SelectColumns[1])); String[] selectPhone = {CommonDataKinds.Phone.NUMBER}; thumbnailPhoto = openThumbnail(Long.valueOf(rawContactID)); infoC = getContentResolver().query( CommonDataKinds.Phone.CONTENT_URI, selectPhone, CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] {rawContactID}, null ); infoC.moveToFirst(); phoneNumber = infoC.getString(0); // Adds items to ListView HumanContent.addItem(new HumanContent.HumanItem(rawContactID, displayName, phoneNumber != "n/a" ? phoneNumber : "", thumbnailPhoto)); Log.v(getPackageName(), "Cursor position: " + c.getPosition() + ", contact ID: " + rawContactID); infoC.close(); } while (c.moveToNext()); c.close(); } displayed_contacts = true; } catch (Exception e) { Log.e(getPackageName(), e.getMessage()); } } 

现在是这样的:

当我使用后退键退出应用程序,然后通过图标再次打开它时; 即使列表保存在内存中,列表也会重新创建:所以我在同一视图中获得了一个双重联系人列表。

在这种情况下savedInstanceState为null,因此达到了if条件,但实际上该视图已经有了我之前的联系人列表。 是什么赋予了? 如何避免重新创建列表? 我已经尝试过使用实例variables,但无济于事。

我还想避免100%重复列表 – 如果我可以重用现有的视图,真棒。

首先,您的savedInstanceState为空的原因 – 系统仅保存由于系统约束而被销毁的活动的状态。 如果退出活动,它将被永久销毁,并且不会保存任何状态。

相关文档: http : //developer.android.com/training/basics/activity-lifecycle/recreating.html

当您的活动因用户按下Back或活动自行完成而被销毁时,系统对该Activity实例的概念将永远消失,因为该行为表明不再需要该活动。 但是,如果系统因系统约束(而不是正常的应用程序行为)而破坏活动,那么虽然实际的Activity实例已经消失,但系统会记住它存在,如果用户导航回到它,系统会创建一个新的活动的实例,使用一组保存的数据来描述销毁时的活动状态。

因此,看起来您的特定问题是,当您的Activity消失时,您的静态HumanContact类仍然在内存中,而您的新Activity将使用另一个联系人副本加载它。

有几种方法可以解决这个问题。 首先,您可以在HumanContent上实现一个方法来清除其所有项目,并在您启动Activity的新实例时调用它。 这样可以确保您的数据是最新的,但这意味着您必须重新加载您的联系人。

其次,如果你想真正避免重新加载数据,我建议为独立于Activity的联系人创建某种缓存。 您应该将Activity视为相当短暂的,它可以并且将被频繁地销毁和重新创建,而缓存可以持久存在。

HumanContent似乎已经在某种程度上填补了这一责任。 您正在使用它来存储您的数据,并且它会持续超出您的Activity的生命周期。 您还可以向其添加一个方法,以检查是否已加载联系人,如果没有加载它们本身。 这样,它就可以完全控制加载和缓存数据,而活动只能负责显示这些数据。 请注意这种types的解决方案,即您没有在内存中存储太多数据,而是在您希望数据发生更改时重新加载缓存,并注意在某些情况下系统可能会重新启动您的进程,因此您的缓存必须准备好重新加载您的数据,以防它被销毁。

至于保留您的视图,如果用户退出您的Activity,则调用finish(),并且您的Activity将被销毁。 请记住,在这种情况下,系统不再具有Activity的任何概念,因此无法保留这些视图以供重用。

这很简单。 在您的活动中按照这些步骤操作

  • 在Activity类的旁边声明listview对象listview_adapter对象
  • OnCreate()方法中初始化listview对象listview_adapter对象 ,并在displayContacts()中添加内容。

那你绝对不会得到内容复制。

始终建议使用缓存来保留数据。 正如Groucho所提到的,你可以使用存储选项查看以下链接了解详情。

http://developer.android.com/guide/topics/data/data-storage.html

我曾经遇到过类似的问题。 我不确定这是多么合法,但我使用的代码如下,它修复了很多:

 private static ViewGroup view1; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mCurrentActivity = getActivity(); if (view1 == null) { settleFragment(inflater); } else { if (view1.getParent() != null && view1.getParent() instanceof ViewGroup) { ((ViewGroup) view1.getParent()).removeView(view1); } } return view1; } 

你可以适应settleFragment(inflater); 与你的方法。 神奇的是关于名为view1静态variables。 片段初始化后,它将填满数据。 Fragments的其他实例将简单地从其前父级中拆分view1并将其粘贴到自己身上。

由于对象保存在ram中,因此文件存储缓存速度非常快。 如果OS垃圾收集对象,则静态variables将再次为null,并且在重新创建视图时不会发生重复。

你无法阻止onCreate函数执行。 但是,您可以应用解决方法以避免重复列表,您可以从列表视图中删除所有项目,然后让它重新填充列表视图。

 @Override public void onPause () { super.onPause(); //........... } @Override public void onStop () { super.onPause(); //............ } 

检查您是否可以在片段中使用这些方法?

实现这一目标的最简单方法是执行Nullcheck

 if(yourcomponent==null) { initializecomponent(); } 

这可能会阻止您的视图重新创建。

完成在displayContacts()中加载数据后,可以在共享首选项中保存标志(displayed_contacts)。 在onCreate()中检查首选项值,并相应地调用displayContacts()。

我在使用Fragments时遇到了同样的问题。

我们有如上所述的现有方法。 如果您发现自己处于困境,那么您可以尝试如下所述: –

  • 使用false启动布尔值。
  • 获取数据后,将布尔值设置为true。
  • 现在重新启动OnCreate()检查该布尔值是true还是false。 如果为false则需要再次提取该数据,否则您无需获取该数据。 放置条件相同。

你要检查控制器。

而不是尝试检查您存储的值。 首先将一个variables作为Bundle。 将其保存在onCreate方法中。

 Bundle bdlSaveInstant; // Declare at top before onCreate() method. /* Initialise in onCreate() method. After super.onCreate(savedInstanceState); setContentView(R.layout.activity_human_list); bdlSaveInstant = savedInstanceState; */ @override onBackPressed() { bdlSaveInstant.putBoolean("displayed_contacts", true); } @override onDestroy() { bdlSaveInstant.putBoolean("displayed_contacts", true); } 

试试这个会奏效。

在你的on create方法中只需清除你的列表。因为每次它都会转到create方法并使列表清除(which)是你以前的数据加载。

要么

检查你的列表if(list.size == null)然后在else块(list.setAdapter)中调用你的API。

希望它会奏效。