所以目前我有一个可以从两个不同的活动中访问的活动,问题是我只能在清单 XML 文件中将一个活动设置为父活动。显然这是糟糕的 UX/UI 设计,因为该活动可能会将用户发送回他们之前所在的错误活动,因此我试图动态设置哪个活动是父活动。
问题是我不太确定如何解决这个问题,无论是在代码还是 XML 中,所以任何指针都值得赞赏。:)
所以目前我有一个可以从两个不同的活动中访问的活动,问题是我只能在清单 XML 文件中将一个活动设置为父活动。显然这是糟糕的 UX/UI 设计,因为该活动可能会将用户发送回他们之前所在的错误活动,因此我试图动态设置哪个活动是父活动。
问题是我不太确定如何解决这个问题,无论是在代码还是 XML 中,所以任何指针都值得赞赏。:)
对于未来的读者,这里有一个示例,说明如何根据开发人员指南实际实施官方/适当的解决方案(滚动到以“当父活动可能不同时这是合适的...... ”开头的段落)。
请注意,此解决方案假定您正在使用支持库来实现您的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(),因为系统将不知道如何为您的任务生成 backstack。我没有为此部分提供任何示例。
finish()
类型解决方案的看法在我寻找这个问题的解决方案时,我遇到了一些提倡覆盖onOptionsItemSelected()
和拦截android.R.id.home
按钮的策略的答案,这样他们就可以简单finish()
地Activity
返回到前一个屏幕。
在许多情况下,这将实现所需的行为,但我只想指出,这绝对与正确的 UP 导航不同。如果您通过其中一个父活动导航到子活动,那么“是finish()
”会将您返回到正确的上一个屏幕,但是如果您通过通知进入子活动怎么办?在这种情况下finish()
,点击 UP 按钮会让您立即回到主屏幕或您在点击通知之前正在查看的任何应用程序,而它应该已将您发送到应用程序中的正确父 Activity。
像这样,您可以动态导航到您的父活动:
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);
}
注意:它会将您重定向到您来自的活动或片段,无论它是否是父母。单击操作栏的向上/主页按钮将完成当前活动。
这里有两个概念“上”和“后”。“返回”是显而易见的:带我回到我来这里之前的位置。通常你不需要关心“返回”,因为系统会很好地处理它。“向上”并不那么明显——它类似于缩小——从一个元素到集合,从一个细节到更广泛的画面。
其中哪一个适合您的用例?
根据下面的评论:向上按钮从 android 清单中提取目标,但可以通过编程方式对其进行自定义。
要覆盖的方法是 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);
要了解如何正确使用向上导航,请参阅此 Android 开发指南。
请注意,上述 Android 开发指南中有一个很大的缺陷,因为 NavUtils 函数在 ICS(及更低版本)和 JellyBean(及更高版本)中的工作方式不同。NavUtils 中的这个缺陷在这里得到了很好的解释。
通常,如果“详细”类型的活动具有嵌套/相关内容,则必须提供“向上”导航。“返回”导航由系统处理,因此您真的不必担心。
现在为了支持“向上”导航的额外努力,有几种方法可以做到:
具有在 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
(更简单和推荐)带有 Fragment 和 Fragment back-stack 的活动:
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 的宿主。
希望这可以帮助。
您可以覆盖 Up 按钮,使其类似于后退按钮,如下所示:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
您将需要跟踪父活动。一种方法是将其作为额外的存储在您创建的意图中以启动子活动)。例如,如果活动 A 启动活动 B,则将 A 的意图存储在为 B 创建的意图中。然后在 BonOptionsItemSelected
中处理向上导航的位置,检索 A 的意图并使用所需的意图标志启动它。
以下帖子有一个更复杂的用例,其中包含一系列子活动。它解释了如何导航到父级的相同或新实例并在此过程中完成中间活动。
科特林 2020
我的活动从不同的活动启动,因此 AndroidManifest 仅适用于 1 个父活动。
您可以像这样返回上一个活动:
supportActionBar?.setDisplayHomeAsUpEnabled(true)
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when(item!!.itemId){
android.R.id.home -> {
finish()
return true
}
}
return super.onOptionsItemSelected(item)
}