如何正确返回上级活动?


179

我的Android应用程序中有2个活动(A和B),并且使用了从活动A到活动B的意图。启用了parent_activity的使用:

 <activity
        android:name=".B"
        android:label="B" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
  </activity>

我还使用提供UP按钮的主题。

因此,在我调用活动BI之后,BI可以使用UP按钮返回活动A。问题是应用程序似乎再次调用了活动A 的onCreate() -函数,这不是我需要的行为。我需要活动A的外观与调用活动B之前的外观相同。

有没有办法做到这一点?

提前致谢

编辑:

我没有编写任何代码来从活动A开始活动B。我认为它是由Eclipse自动生成的。

B类看起来像:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_b, menu);
    return true;
}


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

发表您的代码,开始从B活动一..
user370305

如果我理解正确,则可以使用startActivityForResult()并返回resultCode或其他内容。
Law Gimenez 2012年

请更新您标记的正确答案!正确的答案来自LorenzCK-不是来自用户……!将其标记为正确会产生误导,并使更多的程序员误解了导航,而不是向后导航!
2014年

哎呀,这里有很多错误的答案,请您帮忙清理一下...?
2014年

@ashiaka-根据您的代码设计的正确答案已更新。
user370305 2014年

Answers:


333

您已launchMode在Android清单中使用标准声明了活动A。根据文档,这意味着:

系统总是在目标任务中创建活动的新实例,并将意图路由到该活动。

因此,onCreate即使正确处理了任务堆栈,系统也被迫重新创建活动A(即调用)。

要解决此问题,您需要更改清单,将以下属性添加到A活动声明中:

android:launchMode="singleTop"

注意:当您完全确定要终止的活动B实例生活在活动A实例的顶部时,调用finish()(如之前的解决方案所示)才有效。在更复杂的工作流程中(例如,从通知启动活动B)情况并非如此,您必须从B正确启动活动A。


11
这是Android文档的解释, “标准”和“ singleTop”模式在一个方面彼此不同:每次有一个新的“标准”活动意图时,都会创建该类的新实例来响应这个意图。每个实例都处理一个意图。类似地,也可以创建“ singleTop”活动的新实例来处理新意图。但是,如果目标任务在其堆栈的顶部已经具有该活动的现有实例,则该实例将接收到新的意图(在onNewIntent()调用中);没有创建新实例。
kpsfoo

需要注意的是,根据该文件 navigateUpFromSameTask(...)应该加入FLAG_ACTIVITY_CLEAR_TOPupIntent(通过navigateUpTo(...)这将导致相同的行为(根据本指南),但该标志永远不会设置-因此,这个答案是有道理的
Anigif

82

更新答案:向上导航设计

您必须声明哪个活动是每个活动的适当父项。这样做可以使系统简化导航模式(例如Up),因为系统可以从清单文件中确定逻辑父活动。

因此,您必须在带有属性的活动标签中声明您的父活动

android:parentActivityName

喜欢,

<!-- The main/home activity (it has no parent activity) -->
    <activity
        android:name="com.example.app_name.A" ...>
        ...
    </activity>
    <!-- A child of the main activity -->
    <activity
        android:name=".B"
        android:label="B"
        android:parentActivityName="com.example.app_name.A" >
        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
    </activity>

以此方式声明了父级活动后,您可以导航至相应的父级,如下所示,

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

因此,当您调用NavUtils.navigateUpFromSameTask(this);此方法时,它会完成当前活动并启动(或恢复)适当的父活动。如果目标父活动位于任务的后退堆栈中,则按定义将其前移FLAG_ACTIVITY_CLEAR_TOP

要显示向上按钮,您必须声明 setDisplayHomeAsUpEnabled():

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

旧答案:(没有向上导航,默认为向后导航)

仅当您从活动B重新开始活动A时,它才会发生。

使用startActivity()

代替从活动A开始,使用startActivityForResult()onActivtyResult()在活动A中覆盖来启动活动B。

现在,在活动B中,只需finish()单击按钮Up。因此,现在您直接转到活动A,onActivityResult()而无需再次创建活动A。


我不知道活动B中的startActivity()在哪里被调用。我已经发布了活动B ...的源代码
ashiaka 2012年

18
代替代码行 NavUtils.navigateUpFromSameTask(this);finish()
user370305'9

4
这就引出了一个问题,Google为何在导航文档(developer.android.com/design/patterns/navigation.html)中没有提及finish()或提及任何内容?startActivityForResult()
有线00年

这听起来像一个费力的解决方法。@LorenzCK的答案似乎要好得多。
carmen_munich 2014年

非常感谢您使用NavUtils.navigateUpFromSameTask(this)。大加!我一直在寻找这样的方法来替换finish(),在某些情况下该方法不会返回到父活动。finish()本质上可以返回到先前的活动,而不必是父活动。

22

我几乎有相同的设置导致了相同的不良行为。对我来说,这可行:在Manifest.xml我的应用的活动A中添加以下属性:

android:launchMode="singleTask"

有关更多说明,请参见本文


1
从我的角度来看,正确解决问题的方法。如果Activity存在于任务堆栈中,则其行为就像您调用finish()一样。如果不是这种情况,将创建并启动它。
约翰

5
这不是正确的方法,因为它每次都会不必要地创建新任务,而应该使用launchMode =“ singleTop”。
kpsfoo

19

虽然一个老问题,这里是另一个(恕我直言最干净,最好的)解决方案为所有以前answeres没有为我工作,因为我deeplinked活动B从一个小部件

public void navigateUp() {
final Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) {
    Log.v(logTag, "Recreate back stack");
        TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities();
  } else {
    NavUtils.navigateUpTo(this, upIntent);
  }
}

[ https://stackoverflow.com/a/31350642/570168 ]

但也请参阅:https//speakerdeck.com/jgilfelt/this-way-up-implementing-effective-navigation-on-android


7

一种更好的方法是使用两件事:调用:

NavUtils.navigateUpFromSameTask(this);

现在,为了使其正常工作,您需要使清单文件状态为活动A有一个父活动B。该父活动不需要任何东西。在版本4及更高版本中,您将获得一个不错的后退箭头,而无需付出额外的努力(这可以在较低版本上完成,也只需编写一些代码,我将其放在下面)。您可以在清单->应用程序标签中设置此数据在GUI中(向下滚动到父活动名称,然后手动放置)

支持节点:

如果您希望支持版本4以下的版本,则还需要包含元数据。右键单击活动,添加->元数据,名称= android.support.PARENT_ACTIVITY和值= your.full.activity.name

在较低版本中也可以得到漂亮的箭头:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

请注意,您将需要支持库版本7才能使所有这些正常工作,但这是值得的!


5

对我有用的是添加:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onBackPressed() {
        finish();
    }

TheRelevantActivity.java现在,它正在按预期工作

是的,别忘了添加:

getSupportActionbar.setDisplayHomeAsUpEnabled(true);onCreate()方法


4

我尝试过android:launchMode="singleTask",但是没有帮助。为我工作android:launchMode="singleInstance"


添加机器人:launchMode =“singleInstance”于母公司活动解决的问题对我来说
埃米尔

4

添加到@LorenCK的答案,更改

NavUtils.navigateUpFromSameTask(this);

如果您的活动可以从其他活动启动,并且可以成为其他应用启动的任务的一部分,则转到下面的代码

Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
    TaskStackBuilder.create(this)
            .addNextIntentWithParentStack(upIntent)
            .startActivities();
} else {
    NavUtils.navigateUpTo(this, upIntent);
}

这将启动一个新任务并启动您活动的父活动,您可以在清单中定义该活动,如下面的Min SDK版本<= 15

<meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.app_name.A" />

或使用parentActivityName> 15


注意:请声明parentActivityNameSDK> 15,否则它会给您带来一些随机崩溃
Sourabh

3

我在使用带有错误父活动名称的android 5.0时遇到了类似的问题

<activity
        android:name=".DisplayMessageActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName=".MainActivity" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>

我从父活动名称中删除了com.example.myfirstapp,它正常运行


2

使用属性添加到活动清单信息

android:launchMode="singleTask"

对我来说很好


1
完成流程就像@Override public boolean onOptionsItemSelected(MenuItem item){switch(item.getItemId()){case android.R.id.home:NavUtils.navigateUpFromSameTask(this); 返回true;} return super.onOptionsItemSelected(item); }
Pravesh Kumar 2014年

添加到清单<activity android:name =“。MainActivity” android:label =“ @ string / title_activity_main”> </ activity> <activity android:name =“。CreateEventActivity” android:label =“ @ string / title_activity_create_event” android :launchMode =“ singleTask” android:parentActivityName =“。MainActivity”> <元数据android:name =“ android.support.PARENT_ACTIVITY” android:value =“。MainActivity” /> </ activity>
Pravesh Kumar

2

在Java类中:

    toolbar = (Toolbar) findViewById(R.id.apptool_bar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setTitle("Snapdeal");

    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

在清单中:

<activity
            android:name=".SubActivity"
            android:label="@string/title_activity_sub"
            android:theme="@style/AppTheme" >
            <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity"></meta-data>
    </activity>

会帮你的


1
    @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);

像背压


1

试试这个:

Intent intent;
@Override
public void onCreate(Bundle savedInstanceState) {
    intent = getIntent();   
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_b, menu);
    return true;
}  

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

0

进入清单并加入android:launchMode="singleTop"活动对我来说很成功。

这特别解决了我的问题,因为在Up单击工具栏上的按钮后,我不希望Android创建上一个活动的新实例-相反,当我向上导航层次结构时,我想使用上一个活动的现有实例。

参考:android:launchMode


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.