【问题标题】:Android - return to previous activity without re-creating itAndroid - 返回上一个活动而不重新创建它
【发布时间】:2019-06-18 15:05:45
【问题描述】:

我有一个包含 >100 个对象的数据库。每个对象都有一个特定的图像文件名、主题字符串、标题字符串和 pdf 文件名。

我有一个活动,它是对象的网格视图。

第一次创建网格视图时,会加载要显示的对象数组。数组的确切内容可能因我第一次打开活动时运行的数据库查询而异。

默认设置是检索并显示数据库中的所有对象。但是,我有时只检索和显示对象的子集(基于主题)。

单击网格中的按钮会打开一个显示该对象 pdf 的活动。很好。

问题是,当我从 PDF 活动“返回”时,会重新创建网格视图。始终使用“默认”所有对象。

因此,如果我有一个仅显示某个“主题”对象的网格视图,如果我随后打开 pdf 活动,则在返回时重新创建网格视图并显示所有对象,而不是 pdf 活动之前的原始网格视图开始了。

问题: 1) 如何在不重新创建网格视图的情况下返回网格视图?

代码:

public class SubjectListActivity extends AppCompatActivity {

String DB_NAME = "XXXXX.sqlite";
String TABLE_NAME = "XXXXX";
DataBaseHelper myDBHelper;


private GridView gridView;
private MyAdapter myAdapter;

private ArrayList<Subject> subjectsArrayList;
private Context context;
private String subjectAreas = ""; // this is sent to the activity from whichever activity opened it.  


protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_subject_list);

    Bundle extras = getIntent().getExtras();
    if (extras != null) {
        subjectAreas = extras.getString("subjectAreas");
    }

    gridView = findViewById(R.id.gv);


    // Database
    AssetDatabaseOpenHelper assetDatabaseOpenHelper = new AssetDatabaseOpenHelper(this, DB_NAME);
    assetDatabaseOpenHelper.saveDatabase();
    myDBHelper = new DataBaseHelper(this, DB_NAME);

    // populates subjectsArray
    subjectsArrayList = populateSubjects();

    loadGrid();

    // listener
    gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

            String title = subjectsArrayList.get(position).getSubjectTitle();
            String iconStyle = subjectsArrayList.get(position).getSubjectIconStyle();
            String pdf = subjectsArrayList.get(position).getSubjectPDF();
            String ref = subjectsArrayList.get(position).getSubjectRefs();
            String linked = subjectsArrayList.get(position).getSubjectLinked();

            Intent intent =  new Intent(view.getContext(), SubjectActivity.class);

            intent.putExtra("title", title);
            intent.putExtra("icon", iconStyle);
            intent.putExtra("pdf", pdf);
            intent.putExtra("ref", ref);
            intent.putExtra("linked", linked);
            intent.putExtra("subjectAreas", subjectAreas);

            startActivityForResult(intent, 1);


        }
    });

}


private void loadGrid(){

    myAdapter = new MyAdapter(getApplicationContext(), subjectsArrayList);
    gridView.setAdapter(myAdapter);

}

// The SQL query that populates the subjectArray depends on the 'subjectAreas' string which is set when the activity first opens. The default is 'getAllSubjects'
private ArrayList<Subject>  populateSubjects() {

    Cursor res = myDBHelper.getAllSubjects(TABLE_NAME);

    if (subjectAreas.equals("emerg")){res = myDBHelper.getEmergSubjects(TABLE_NAME);}
    else if (subjectAreas.equals("all")){res = myDBHelper.getAllSubjects(TABLE_NAME);}
    else if (subjectAreas.equals("ax")){res = myDBHelper.getAxSubjects(TABLE_NAME);}
    else if (subjectAreas.equals("mx")){res = myDBHelper.getMxSubjects(TABLE_NAME);}
    else if (subjectAreas.equals("ref")){res = myDBHelper.getRefSubjects(TABLE_NAME);}
    else if (subjectAreas.equals("cal")){res = myDBHelper.getCalSubjects(TABLE_NAME);}
    else if (subjectAreas.equals("search")){res = myDBHelper.getSearchSubjects(TABLE_NAME, keywords);}


        ArrayList<Subject> list = new ArrayList<>();

            if (res.getCount() == 0) {

            } else {
                while (res.moveToNext()) {
                    Subject subject = new Subject();
                    subject.setSubjectID(res.getString(0));
                    subject.setSubjectTitle(res.getString(1));
                    subject.setSubjectIconStyle(res.getString(2));
                    subject.setSubjectPDF(res.getString(3));
                    subject.setSubjectKeywords(res.getString(4));
                    subject.setSubjectLinked(res.getString(5));
                    subject.setSubjectRefs(res.getString(6));
                    list.add(subject);
                }

            }

            return list;
        }


// Tried sending 'back' subjectAreas from PDF activity and re-populating the array and gridview - this doesn't seem to be called  
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 1) {
        if(resultCode == RESULT_OK) {
            subjectAreas = data.getStringExtra("subjectAreas");
            subjectsArrayList = populateSubjects();
            myAdapter = new MyAdapter(getApplicationContext(), subjectsArrayList);
            gridView.invalidateViews();
            gridView.setAdapter(myAdapter);
        }
    }
}

}

提前致谢

更新: 使用 savedInstanceState 来“保存”我的 subjectAreas 字符串,我使用了以下内容:

    private String subjectAreas = "";
private static final String subjectAreasSaved = "";

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_subject_list);

    Bundle extras = getIntent().getExtras();
    if (extras != null) {
        subjectAreas = extras.getString("subjectAreas");
        title = extras.getString("title");
        keywords = extras.getStringArrayList("keywords");
    }

    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        subjectAreas = savedInstanceState.getString(subjectAreasSaved);
    }

还有:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putString(subjectAreasSaved, subjectAreas);
    super.onSaveInstanceState(savedInstanceState);
}

当第二个活动是开放式的时是否会自动调用 onSaveINstanceState 还是我需要调用它?目前似乎没有任何事情发生

【问题讨论】:

  • 我建议您编辑您的问题并提供此活动的minimal reproducible example,显示它何时以及如何设置网格,以及它如何启动 PDF 查看活动。与活动输出的屏幕截图相比,该代码对于获得答案的价值要高得多。
  • 完成,感谢任何帮助,进一步的建议
  • 如果这是完整的活动类,我不明白为什么它会纯粹基于前进/后退导航重新创建。您是否在设置的开发人员选项中启用了“不保留活动”?但是,您将遇到配置更改问题,这就是onSaveInstanceState()ViewModel 发挥作用的地方。顺便说一句,FWIW,您在这里使用的方法(例如,GridView,活动中的数据库 I/O)有点旧。
  • 尚未启用“不保留活动”,因为所有测试都在模拟器上(目前实际上没有安卓设备(!))。猜猜潜在的“用户”可以启用此功能,所以我需要为该结果编写代码?看来“onSaveInstanceState”是我需要的(同意?)。感谢您的建议:gridview,因为我相信您可以猜到我不是 android 开发人员,只是试图重新创建我的 iOS 应用程序(由于各种原因使用 sqlite)。这些是第一次尝试进入 android 并希望运行“基本版本”,并且一旦舒服就会考虑其他方法。谢谢
  • “我需要为这个结果编码吗?” ——我不会担心的。 “看来,'onSaveInstanceState' 是我需要的(同意?)” - 您需要为配置更改做一些事情,但您对症状的描述不包括配置更改。关于您问题中的问题,请在您的 onCreate() 方法中的某处放置一个断点,并查看当您在查看 PDF 后返回此活动时是否会触发该断点。如果没有,那么该活动没有被重新创建,并且正在发生其他事情。

标签: android gridview oncreate resume


【解决方案1】:

娱乐取决于框架。如果它决定它需要资源,它会破坏之前的副本,无论你是否想要它。你无法阻止它。

您可以做的是实现 onSaveInstanceState 和 onRestoreInstanceState 以保存您需要从该确切状态重新创建的所有数据。

【讨论】:

  • 您可以对保存的内容进行“变体”吗?即我可以根据具体变量将特定变量保存为不同的值吗?
  • 您只需将数据保存到 Bundle 对象。所以是的,您可以根据状态保存不同的数据,您只需要能够了解您在还原中保存的内容。让 Activity 的各个部分(如片段)保存自己的状态并不少见(实际上是很好的做法),并且每个可能的片段将保存不同的数据。请注意,捆绑包确实有最大大小,因此您可能希望存储查询参数之类的内容,而不是数据库查询的完整结果。或者如果必须将其与序列化到磁盘结合使用
  • 谢谢,很有帮助。我实际上只会保存一个字符串“subjectAreas”。请参阅上面对 Amin 问题的编辑
  • 是的,在上面的代码中,您正在检查 onCreate 方法中的 savedInstantState,但您需要同时实现 onSaveInstanceState(在其中使用 subjectAreas 填充该捆绑包)和 onRestoreInstanceState(它将检索 savedInstantState 捆绑包)并使用 subjectAreas 恢复网格的状态。
  • Android 不会重新创建活动,除非屏幕旋转。如果系统内存不足,则会终止整个进程。
【解决方案2】:

首先,应该向给予极大帮助的作者致敬。

我的代码的问题得到了很好的解释,并通过这个线程解决了:Stackoverflow thread

基本上,操作栏中的“主页”按钮会导致重新创建上一个活动。因此我的问题。当我尝试实现 InstanceState 时,我一直为 savedInstanceState 获得一个“null”...然后将我带到我上面链接的线程。

我真的希望这对其他人有所帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-20
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 2011-05-01
    相关资源
    最近更新 更多