【问题标题】:Dynamically set parent activity动态设置父活动
【发布时间】:2013-10-04 14:44:53
【问题描述】:

所以目前我有一个可以从两个不同的活动访问的活动,问题是我只能将一个活动设置为清单 XML 文件中的父活动。显然这是糟糕的 UX/UI 设计,因为该活动可能会将用户返回到他们之前所在的错误活动,因此我试图动态设置哪个活动是父活动。

问题是我不太确定如何解决这个问题,无论是在代码还是 XML 中,所以任何指针都值得赞赏。 :)

【问题讨论】:

  • 父活动用于向上导航(例如操作栏中的向上箭头)。后退导航不使用父活动,它使用后退堆栈。在您的情况下,您应该可以使用 startActivity(ForResult)finish 来管理后台堆栈。
  • 我想使用操作栏中的向上箭头,所以我想我真正想要的是一种动态设置向上导航应该在触摸时引用的活动的方法。
  • 另一个相关问题 - 也没有真正的答案:How do I set the parent activity of an activity at runtime?

标签: android


【解决方案1】:

对于未来的读者,这里有一个示例,说明如何根据developer guides 实际实施官方/适当的解决方案(滚动到以 开头的段落“这适用于 父活动可能不同的情况。 ..)。

请注意,此解决方案假定您正在使用 Support Library 来实现您的 ActionBar,并且您至少可以在清单 XML 文件中设置一个“默认”父 Activity,以便在您退出的 Activity 时回退处于不属于您的应用的“任务”中(请阅读链接的文档进行说明)。

// Override BOTH getSupportParentActivityIntent() AND getParentActivityIntent() because
// if your device is running on API 11+ it will call the native
// getParentActivityIntent() method instead of the support version.
// The docs do **NOT** make this part clear and it is important!

@Override
public Intent getSupportParentActivityIntent() {
    return getParentActivityIntentImpl();
}

@Override
public Intent getParentActivityIntent() {
    return getParentActivityIntentImpl();
}

private Intent getParentActivityIntentImpl() {
    Intent i = null;

    // Here you need to do some logic to determine from which Activity you came.
    // example: you could pass a variable through your Intent extras and check that.
    if (parentIsActivityA) {
        i = new Intent(this, ActivityA.class);
        // set any flags or extras that you need.
        // If you are reusing the previous Activity (i.e. bringing it to the top
        // without re-creating a new instance) set these flags:
        i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        // if you are re-using the parent Activity you may not need to set any extras
        i.putExtra("someExtra", "whateverYouNeed");
    } else {
        i = new Intent(this, ActivityB.class);
        // same comments as above
        i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        i.putExtra("someExtra", "whateverYouNeed");
    }

    return i;
}

注意:如果您没有在清单 XML 文件中设置默认父 Activity,那么您还需要实现 onCreateSupportNavigateUpTaskStack(),因为系统将不知道如何为您的任务生成回栈。这部分我没有提供任何示例。

我对@9​​87654327@ 类型解决方案的看法

在寻找解决此问题的方法时,我遇到了一些提倡覆盖onOptionsItemSelected() 并拦截android.R.id.home 按钮的策略的答案,这样他们就可以简单地finish() 当前的Activity 返回到上一屏。

在许多情况下,这将实现所需的行为,但我只想指出,这绝对与正确的 UP 导航相同。如果您通过其中一个父 Activity 导航到子 Activity,那么是的 finish() 会将您返回到正确的上一个屏幕,但是如果您通过通知输入子 Activity 怎么办?在这种情况下,finish()ing 通过点击 UP 按钮会将您直接返回到主屏幕或您在点击通知之前正在查看的任何应用程序,而它应该将您发送到您应用程序中的适当父 Activity。

【讨论】:

  • 感谢您提供如何完成此操作的示例 - Android 指南中确实缺少这一点。
  • getSupportParentActivityIntent 在 API 15 设备中没有为我触发...有什么想法吗?
  • @worked 它确实基于 getSupportParentActivityIntent() 应该只在运行
  • 如果你想更新你的答案,android x 的新链接是developer.android.com/reference/androidx/appcompat/app/…
【解决方案2】:

像这样你可以动态导航到你的父活动:

getActionBar().setDisplayHomeAsUpEnabled(true);

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    // Respond to the action bar's Up/Home button
    case android.R.id.home:
        finish();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

注意:它会将您重定向到您来自的活动或片段,无论它是否是父项。单击操作栏的向上/主页按钮将完成当前活动。

【讨论】:

  • 它不完全是父活动,但效果很好。
  • 对于那些阅读,虽然finish() 在许多情况下确实实现了所需的行为,但在某些情况下它并不总是会导致正确的向上导航。请看我的回答和想法explaining this
  • 返回true是一个很重要的方面。我完成了,但没有回报。现在工作。谢谢
  • finish() 和 NavUtils.navigateUpFromSameTask 的区别是什么
  • @nuttynibbles finish 关闭当前活动。这不是使用向上导航的正确方法。
【解决方案3】:

这里有两个概念“上”和“后”。 “返回”是显而易见的:带我回到我来这里之前的位置。通常你不需要关心'Back',因为系统会很好地处理它。 “向上”并不那么明显——它类似于缩小——从元素到集合,从细节到更广阔的画面。

其中哪一个适合您的用例?


根据下面的评论:向上按钮从 android 清单中拉出目的地,但它可以是 customized programmatically

【讨论】:

  • 我对处理后退行为更感兴趣,但根据您的描述,系统应该自动处理这个吗?操作栏中的“向上”按钮怎么样?这是从 XML 父集中提取其目的地还是简单地链接回它来自的上一个活动?
  • 是的,向上按钮从 android manifest 中拉取目的地,但它可以是 customized programmatically
  • 如果你对你的应用很认真,也请阅读navigation design guide - 保持流畅真的会让应用感觉自然。不要以为你需要全心全意地知道,只是要知道有一种方法可以完成。
  • 为什么这个答案在没有 cmets 的情况下被选为 -2?发帖人应该添加一个示例而不是链接,但该链接指向正确的手册页。 +1
  • 这个答案可能应该包含一个很好的例子,而不仅仅是将来可能会死的链接。但是我给这个 +1 分是为了让分数恢复到它所属的位置,因为它确实让我找到了一个真正合适的解决方案,这与给出的其他一些答案不同。
【解决方案4】:

要覆盖的方法是getParentActivityIntent。

这是我的代码,运行良好。

@Override
public Intent getParentActivityIntent() {
    Intent parentIntent= getIntent();
    String className = parentIntent.getStringExtra("ParentClassSource"); 

    Intent newIntent=null;
    try {
        //you need to define the class with package name
        newIntent = new Intent(OnMap.this, Class.forName(className));

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return newIntent;
}

来自父活动;

Intent i = new Intent(DataDetailsItem.this, OnMap.class);
i.putExtra("ParentClassSource", "com.package.example.YourParentActivity");
startActivity(i);

【讨论】:

    【解决方案5】:

    要了解如何正确使用向上导航,请参阅this Android Dev Guide.

    请注意,上述 Android 开发指南中有一个很大的缺陷,因为 NavUtils 函数在 ICS(及更低版本)和 JellyBean(及更高版本)中的工作方式不同。 NavUtils 中的这个缺陷解释得很漂亮here.

    【讨论】:

      【解决方案6】:

      通常,如果“详细”类型的活动具有嵌套/相关内容,则必须提供“向上”导航。 “返回”导航由系统处理,因此您真的不必担心。

      现在,为了支持“向上”导航,有以下几种方法:

      1. 在 AndroidManifest 中定义了父 Activity 的 Activity。

        Your Android Manifest
        ---------------------
        
        <activity
            android:name="com.example.app.DetailActivity"
            android:parentActivityName="com.example.app.MainActivity" >
            <meta-data 
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.example.app.MainActivity" />
        </activity>
        
        Your Detail Activity
        --------------------
        
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
        
            switch (item.getItemId()) {
                case android.R.id.home:
                    NavUtils.navigateUpFromSameTask(this);
                    return true;
            }
            return super.onOptionsItemSelected(item);
        }
        

        如果只有一个父活动意味着(DetailActivity)总是从(MainActivity)启动,这很有效。否则,如果 (DetailActivity) 从不同的地方启动,此解决方案将不起作用。 更多内容:http://developer.android.com/training/implementing-navigation/ancestral.html

      2. (更简单且推荐的)带有 Fragment 和 Fragment back-stack 的 Activity:

        Your Detail Activity
        --------------------
        
        protected void replaceFragment(Bundle fragmentArguments, boolean addToBackStack) {
        
            DetailFragment fragment = new DetailFragment();
            fragment.setArguments(fragmentArguments);
        
            // get your fragment manager, native/support
            FragmentTransaction tr = fragmentManager.beginTransaction();
            tr.replace(containerResId, fragment);
            if (addToBackStack) {
                tr.addToBackStack(null);
            }
            tr.commit();
        }
        
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
        
            switch (item.getItemId()) {
                case android.R.id.home:
                    finish();
                    return true;
            }
            return super.onOptionsItemSelected(item);
        }
        

        在此解决方案中,如果用户按下“返回”,该片段将从片段返回堆栈中弹出,并且用户将被带回前一个片段,同时仍保留在同一活动中。如果用户按下“向上”,则活动关闭并且用户被引导回到前一个活动(作为父活动)。这里的关键是使用 Fragment 作为你的 UI 和 Activity 作为 Fragment 的宿主。

      希望这会有所帮助。

      【讨论】:

        【解决方案7】:

        您可以覆盖向上按钮,使其类似于后退按钮,如下所示:

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
                case android.R.id.home:
                    onBackPressed();
                    return true;
            }
            return super.onOptionsItemSelected(item);
        }
        

        【讨论】:

          【解决方案8】:

          您需要跟踪父活动。一种方法是将其作为额外的存储在您创建的意图中以启动子活动)。例如,如果 Activity A 启动 Activity B,则将 A 的 Intent 存储在为 B 创建的 Intent 中。然后在 B 的 onOptionsItemSelected 中处理向上导航,检索 A 的 Intent 并使用所需的 Intent 标志启动它。

          以下帖子有一个更复杂的用例,其中包含一系列子活动。它解释了如何导航到父级的相同或新实例并在此过程中完成中间活动。

          Android up navigation for an Activity with multiple parents

          【讨论】:

            【解决方案9】:

            Kotlin 2020

            我的 Activity 从不同的 Activity 启动,因此 AndroidManifest 仅适用于 1 个父 Activity。

            您可以像这样返回上一个活动:

            
            supportActionBar?.setDisplayHomeAsUpEnabled(true)
            
            override fun onOptionsItemSelected(item: MenuItem?): Boolean {
                    when(item!!.itemId){
                        android.R.id.home -> {
                            finish()
                            return true
                        }
                    }
                    return super.onOptionsItemSelected(item)
                }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-12-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-01-19
              • 1970-01-01
              • 2021-09-23
              相关资源
              最近更新 更多