我有一个显示联系人列表的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,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条件,但实际上该视图已经有了我之前的联系人列表.是什么赋予了?如何避免重新创建列表?我已经尝试过使用实例变量,但无济于事.

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

解决方法

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

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

When your activity is destroyed because the user presses Back or the
activity finishes itself,the system’s concept of that Activity
instance is gone forever because the behavior indicates the activity
is no longer needed. However,if the system destroys the activity due
to system constraints (rather than normal app behavior),then although
the actual Activity instance is gone,the system remembers that it
existed such that if the user navigates back to it,the system creates
a new instance of the activity using a set of saved data that
describes the state of the activity when it was destroyed.

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

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

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

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

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

如何避免在Android上的onCreate上重新创建视图?的更多相关文章

  1. ios – 如何在UIActivityViewController调用然后关闭后执行操作

    解决方法在这种情况下,您可以使用completionHadler:

  2. Swift iOS 9通讯录访问

    viewmode=list我的stackoverflow前言:在iOS9之前,一直使用AddressBook这个framework来访问用户通讯录。

  3. [Swift] Enum 好用, Enum 可以更易用

    只需要写少量的几行声明:如下.选中,右键,选择"Services|generate_enum"然后如下代码就自动生成了:怎么样?当然还有其他选项可以使用.如果你有其他需要麻烦告诉我.当然有PR最好了.最后来张动图感受一下:代码在:OSCGitGithub

  4. swift – 交换机:枚举交换机问题:不是int的成员

    我在Swift中编写了我的第一个项目,由于某种原因,我无法找出为什么我的枚举和开关不工作属性开关我得到的错误是枚举大小写“viewmodeFavourite”不是“Int!”类型的成员所以我改为这个,因为它不是一个Int!forStoryboard)然后我得到枚举大小写模式不能匹配非枚举类型“Int”的值你必须将contactviewmode声明为Contactviewmode而不是Int。如果您真的希望它是Int,那么您必须通过将变量与枚举情况的rawValue属性进行比较来更改交换机中的大小写:但除非

  5. android – 如何在服务中正确调用startIntentSenderForResult?

    还是有其他正确的方法吗?)>然后,在onActivityResult()中,完成活动,首先通知您的服务解决问题.瞬态活动对用户来说是不可见的.我承认这个解决方案是理论上的,但它应该有效.

  6. android – Slider Menu片段中的可交换选项卡

    我已经通过引用thistutorial实现了导航抽屉,现在我想要做的是在片段内显示滑动标签.即当我点击导航抽屉中的一个项目时,让我们说第一个项目,它应显示该项目的滑动标签.如果item1是Events,当我点击它时,它应该显示滑动标签.但我面临以下问题:–>如何在片段内实现视图寻呼机?

  7. Android架构组件ViewModel – 如何在测试Activity上模拟ViewModel?

    我正在尝试设置类似于GithubbrowserSample的UI测试,看起来示例项目只有Frag的模拟viewmodel而不是Activity的示例.这是我的代码,我试图通过模拟viewmodel来测试Activity.但viewmodel未在Activity中的onCreate()之前设置.有人可以帮我解决这个问题吗?解决方法JUnit@Rules在@Before方法之前进行设置,因此您的活动在

  8. android – 如何在对话框上添加进度条

    每当我想在我的应用程序中显示进度条时,我调用此方法,此方法将ProgressBar添加到我的布局中.问题:我想在Dialog上显示此进度条,但Dialog始终显示在上面.这种情况可以做些什么?解决方法尝试这样的东西,它应该全局工作:

  9. android – 无法获得连接工厂客户端 – 与谷歌地图战斗

    另一天另一个问题,我终于设法在我的Android应用程序上设置正确的谷歌地图,或者至少我以为我已经完成了它,整个程序开始,它甚至调用应该“打印”地图的类,但是我唯一能看到的是一个带有谷歌标签的网格[在角落里].我检查了dalvik监视器和错误E/MapActivity(394):Couldn’tgetconnectionfactoryclient发生.我已经在stackoverflow网站上找到了

  10. android – 远程服务如何将消息发送到绑定的Activity?

    例如,我的活动绑定到同一个应用程序的正在运行的后台服务,向它发送一条消息,一旦收到此消息,服务就会向活动回复一条消息..我该如何实现?你能指点我一些解释这个主题的文件吗?

随机推荐

  1. bluetooth-lowenergy – Altbeacon库无法在Android 5.0上运行

    昨天我在Nexus4上获得了Android5.0的更新,并且altbeacon库停止了检测信标.似乎在监视和测距时,didEnterRegion和didRangeBeaconsInRegion都没有被调用.即使RadiusNetworks的Locate应用程序现在表现不同,一旦检测到信标的值,它们就不再得到更新,并且通常看起来好像信标超出了范围.我注意到的一点是,现在在logcat中出现以下行“B

  2. android – react-native动态更改响应者

    我正在使用react-native进行Android开发.我有一个视图,如果用户长按,我想显示一个可以拖动的动画视图.我可以使用PanResponder实现这一点,它工作正常.但我想要做的是当用户长按时,用户应该能够继续相同的触摸/按下并拖动新显示的Animated.View.如果您熟悉Google云端硬盘应用,则它具有类似的功能.当用户长按列表中的任何项目时,它会显示可拖动的项目.用户可以直接拖

  3. android – 是否有可能通过使用与最初使用的证书不同的证书对其进行签名来发布更新的应用程序

    是否可以通过使用与最初使用的证书不同的证书进行签名来发布Android应用程序的更新?我知道当我们尝试将这样的构建上传到市场时,它通常会给出错误消息.但有没有任何出路,比如将其标记为主要版本,指定市场中的某个地方?解决方法不,你不能这样做.证书是一种工具,可确保您是首次上传应用程序的人.所以总是备份密钥库!

  4. 如何检测Android中是否存在麦克风?

    ..所以我想在让用户访问语音输入功能之前检测麦克风是否存在.如何检测设备上是否有麦克风.谢谢.解决方法AndroidAPI参考:hasSystemFeature

  5. Android – 调用GONE然后VISIBLE使视图显示在错误的位置

    我有两个视图,A和B,视图A在视图B上方.当我以编程方式将视图A设置为GONE时,它将消失,并且它正下方的视图将转到视图A的位置.但是,当我再次将相同的视图设置为VISIBLE时,它会在视图B上显示.我不希望这样.我希望视图B回到原来的位置,这是我认为会发生的事情.我怎样才能做到这一点?编辑–代码}这里是XML:解决方法您可以尝试将两个视图放在RelativeLayout中并相对于彼此设置它们的位置.

  6. android – 获得一首歌的流派

    我如何阅读与歌曲相关的流派?我可以读这首歌,但是如何抓住这首歌的流派,它存放在哪里?解决方法检查此代码:

  7. android – 使用textShadow折叠工具栏

    我有一个折叠工具栏的问题,在展开状态我想在文本下面有一个模糊的阴影,我使用这段代码:用:我可以更改textColor,它可以工作,但阴影不起作用.我为阴影尝试了很多不同的值.是否可以为折叠文本投射阴影?

  8. android – 重用arm共享库

    我已经建立了armarm共享库.我有兴趣重用一个函数.我想调用该函数并获得返回值.有可能做这样的事吗?我没有任何头文件.我试过这个Android.mk,我把libtest.so放在/jni和/libs/armeabi,/lib/armeabi中.此时我的cpp文件编译,但现在是什么?我从objdump知道它的名字编辑:我试图用这个android.mk从hello-jni示例中添加prebuild库:它工作,但libtest.so相同的代码显示以下错误(启动时)libtest.so存在于libhello-j

  9. android – 为NumberPicker捕获键盘’Done’

    我有一个AlertDialog只有一些文本,一个NumberPicker,一个OK和一个取消.(我知道,这个对话框还没有做它应该保留暂停和恢复状态的事情.)我想在软键盘或其他IME上执行“完成”操作来关闭对话框,就像按下了“OK”一样,因为只有一个小部件可以编辑.看起来处理IME“Done”的最佳方法通常是在TextView上使用setonEditorActionListener.但我没有任何Te

  10. android – 想要在调用WebChromeClient#onCreateWindow时知道目标URL

    当我点击一个带有target=“_blank”属性的超链接时,会调用WebChromeClient#onCreateWindow,但我找不到新的窗口将打开的新方法?主页url是我唯一能知道的东西?我想根据目标网址更改应用行为.任何帮助表示赞赏,谢谢!

返回
顶部