GVKun编程网logo

Android SingleTask,SingleTop和Home Button

15

在这篇文章中,我们将带领您了解AndroidSingleTask,SingleTop和HomeButton的全貌,同时,我们还将为您介绍有关"standard,singleTop,singleTask

在这篇文章中,我们将带领您了解Android SingleTask,SingleTop和Home Button的全貌,同时,我们还将为您介绍有关"standard,singleTop,singleTask,singleInstance"-Android启动模式、android singleTask onNewIntent、Android singleTask+askAffinity的使用方式、Android SingleTask启动模式与Home键的问题的知识,以帮助您更好地理解这个主题。

本文目录一览:

Android SingleTask,SingleTop和Home Button

Android SingleTask,SingleTop和Home Button

在我的应用程序中,有一种我不理解的行为.我将MainActivity A作为SingleTask.
它调用的活动B也是SingleTask.
当我按下第二个活动中的主页按钮打开另一个应用程序,然后我尝试去我的应用程序mantaining Home按钮按下我总是去主要活动,我想要打开第二个活动维持当时的状态我按下主页按钮.

我已经尝试将第二个活动设置为singletop,但它不起作用.

有帮助吗?

解决方法

当使用singleTask同时定义主要活动时,活动返回堆栈的行为变得很奇怪:

<activity android:name=".MainActivity"
  android:launchMode="singleTask">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>

更糟糕的是官方开发指南中没有关于这个特殊用例的明确解释.与此主题相关的一些部分甚至是自相矛盾的.

尝试在MainActivity A上使用launchMode =“standard”,在Activity B上使用launchMode =“singleTask”,这将给出您描述的期望行为.

"standard,singleTop,singleTask,singleInstance"-Android启动模式

安卓有4种启动模式,下面我们就进行详细的讲解


用栈的思维去理解,就能理解这些启动模式的本质了

先设置两个页面: 
A(为测试对象),B两个页面,两个页面都有跳至对方的按钮


一.标准模式(standard)

(默认的,不用设置)

例一:

A->A->A,然后按返回键三次就会退出所有的A界面,过程:A<-A<-A

例二:

A->B->A->A->B,返回过程:A<-B<-A<-A<-B;

就是栈的特点,逐个放入,返回时从栈顶出栈

结论:标准的进栈,出栈


二.单个顶部模式(singleTop)

(在自己的Activity里声明属性:android:lunchuMode=”singleTop”) 
这里A是设置的,B是标准的

A->B->A->B 那么返回的过程:A<-B<-A<-B

A->A->B->A->B->B:返回结果是:A<-B<-A<-B<-B

A->A->A->:返回结果:<-A,直接退出;

 

逐个放入栈,但是设置顶部模式的不能连续两个一起放.所以:设置的顶部模式的窗口活动只能作为一个,不能叠加

结论:放入栈中的新活动,如果刚刚存放的页面在下方(意为相连),那么此活动将不会被连续添加,除非又隔着一个新的活动


三.单个任务模式(singleTask)

(android:lunchMode=”singleTask”)

A->B->A:返回 <-A,直接退出,因为存在了A又放入了A,那么A就把前面的B给顶掉并仅剩一个自己

A->B->A->B:返回 <-A<-B,到A直接退出,把上方A之间的B给顶掉并仅剩一个自己,然后才再放B

逐个放入栈,设置了单个任务的会压掉其他的,并剩一个自己,相当于栈中自己的上方不会有第二个自己.

结论: 栈中自己的上方不会有第二个自己


四.单个实例模式(singleInstance)

(android:lunchMode=”singleTask”)系统就会为这个实例创建一个单独的栈,并且只能放自己这个类型有且只有一个

单例,所以一个栈只能放一种类型并且设置的单利活动只能放一个,并且新添加的栈排在前面

如下图:左边设置A为标准,B为单一实例;右边A设置为单一实例,B设置为标准 
这里写图片描述
想必大家都看到上面的问题所在了吧,左边是正常的,右边就出现了问题,我上网查了许多的博客和资料,发现全部都是左边的情况(A标准,B单一实例),没有一篇文章是将右边的情况的(A单,B标),我为此了加了8个群,进去问了半天,除了两个人貌似能回答右边的 情况外没人能够讲解,别人说我没必要那么研究每一步,说开发用户不会用到这个,用其它方案解决,但是我觉得既然发现问题就认真去做,起码这是一个编程人员所需要有的严肃对待性精神


然后希望又来了大家,请看下面的情况,多添加一个页面,又发现正常了 
这里写图片描述
我们设置A是单一实例,B是默认,C是默认,但为什么出现左边的那个问题,有个人说是推出栈,但是我再问他解释的时候他没回答.所以大家,这个小问题想放在这,我下次得到答案后回来这里更新,我们只需要记住不变的原理就行(单一实例,一个单独栈只放一个自己).

下面给出代码方便大家观看

A界面代码:

public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void gotoA(View view) { startActivity(new Intent(this, MainActivity.class)); } public void gotoB(View view) { startActivity(new Intent(this,MainActivityB.class)); } public void gotoC(View view) { startActivity(new Intent(this,MainActivityC.class)); } }

 

B界面代码:

//内容同上,只把A改成B
public class MainActivityB extends AppCompatActivity { 

 

C界面代码

//内容同上,只把B改成C
public class MainActivityC extends AppCompatActivity { 

 


布局:

A界面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#df4848"> <TextView android:textSize="20sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Page A"/> <Button android:layout_width="match_parent" android:onClick="gotoA" android:text="gotoA" android:layout_height="wrap_content"/> <Button android:text="gotoB" android:layout_width="match_parent" android:onClick="gotoB" android:layout_height="wrap_content"/> <Button android:text="gotoC" android:layout_width="match_parent" android:onClick="gotoC" android:layout_height="wrap_content"/> </LinearLayout>

 

A界面布局:

改背景颜色和本页文本即可

android:background="#487adf"

    <TextView
        android:textSize="20sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Page B"/>

 

C界面布局:

同样改背景颜色和本页文本即可

    android:background="#86bf89"

    <TextView
        android:textSize="20sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Page C"/>

 

清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="goodjobtome.com.lunchmode" xmlns:android="http://schemas.android.com/apk/res/android"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:launchMode="singleInstance"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".MainActivityB" /> <activity android:name=".MainActivityC" /> </application> </manifest>

 

效果: 
这里写图片描述 
这里写图片描述 
这里写图片描述

 

android singleTask onNewIntent

android singleTask onNewIntent

在 Android 应用程序开发的时候,从一个 Activity 启动另一个 Activity 并传递一些数据到新的 Activity 上非常简单,但是当您需要让后台运行的 Activity 回到前台并传递一些数据可能就会存在一点点小问题。

首先,在默认情况下,当您通过 Intent 启到一个 Activity 的时候,就算已经存在一个相同的正在运行的 Activity, 系统都会创建一个新的 Activity 实例并显示出来。为了不让 Activity 实例化多次,我们需要通过在 AndroidManifest.xml 配置 activity 的加载方式(launchMode)以实现单任务模式,如下所示:

 

<activity android:label="@string/app_name" android:launchmode="singleTask"android:name="Activity1"></activity>

 

launchMode 为 singleTask 的时候,通过 Intent 启到一个 Activity, 如果系统已经存在一个实例,系统就会将请求发送到这个实例上,但这个时候,系统就不会再调用通常情况下我们处理请求数据的 onCreate 方法,而是调用 onNewIntent 方法,如下所示:

复制代码

 protected void onNewIntent(Intent intent) {

   super.onNewIntent(intent);

   setIntent(intent);//must store the new intent unless getIntent() will return the old one

   processExtraData();

 }


Android singleTask+askAffinity的使用方式

Android singleTask+askAffinity的使用方式

任务栈与startActivityForResult
android 5.0之前,singleinstance和singletask不能作为ResultActivity, android 5.0之后可以,startActivityForResult之后,ResultActiviy如果是singleTask和singleInstance自动转为standard,并且从singleInstance ResultActivity启动的Activity,将会自动起一个新的Task,Activity将会被放在新栈中。

Android创建模式

在四种创建模式中最长用的应该是默认方式 standard,下来是singleTop,其次是singleTask,最后是singleInstance

这几种创建模式中,往往影响的是Activity的BackStack(回退栈)。

1.标准(standard)模式基本上是后进先出,每次都会重新创建Activity,这点不多说。
2.singleInstance是最少使用的,因为这个Activity的生命周期和应用程序的生命周期是相同的,
销毁也是个问题。在MVC中,Activity类似于Controller,但我们知道基于Servlet的单例效果并不好,
比如出现信息泄露,同步等问题,才出现了后来的SpringMVC,Struts2等使用多例模式。
3.SingleTop, 如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶
(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。
4.singleTask  如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,
会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。

二、SingleTask模式

再来说说SingleTask的使用方式

singleTask保证了在栈中Activity的唯一性,如果被SingleTask标记的Activity处于栈底,站定的Activity发送Intent返回到栈底时,栈中间的Activity会被清除,这个时候被标记过SingleTask的生命周期会响应的做出调整。

onNewIntent->onStart->onResume->.....

这次不会调用OnCreate,但是这里有一个问题,OnNewIntent是被调用了,但是Intent中所保存的数据却仍然还是旧数据,因此需要进一步重写

PS:来一个例子,方便大家理解吧

创建一个一个MainActivity,在Manifest中设置

 <activity
            android:launchMode="singleTask"
            android:name="com.simple.launchmode.MainActivity"
            android:screenOrientation="portrait" />

MainActivity.java

/***
	 * 将activity 的创建模式设置为singletask, 
	 * 使用这个方法可以再其他activity想这个activity发送Intent时,这个Intent能够及时更新
	 */
	@Override
	protected void onNewIntent(Intent intent)
	{
		  super.onNewIntent(intent);
		  setIntent(intent); //这一句必须的,否则Intent无法获得最新的数据
	}

 

基本就是这样了,下面我们来说说SingleTask的优化搭配

  <activity
            android:launchMode="singleTask"
            android:taskAffinity="com.hongkong.stationcontrol.MainActivity"
            android:name="com.hongkong.stationcontrol.MainActivity"
            android:screenOrientation="portrait" />

是的,你看见了一个

android:taskAffinity="com.hongkong.stationcontrol.MainActivity"

android:taskAffinity相当于一个标签,这个标签是任务名称,SingleTask从字面意思理解是单任务,这里是任务的名称,前面所说的而保持Activity的唯一性只是这个单任务的一个子集,默认情况下任务都是同一个(按照packageName)来设置的,这样他的优势并没有完全发挥,因此要使用

android:taskAffinity="com.hongkong.stationcontrol.MainActivity"

重新创建一个任务,这样实现了Activity的唯一性的同时,也实现了单任务。

android 5.0之前,singleinstance和singletask不能作为ResultActivity,onActivityResult会提前返回, android 5.0之后可以,startActivityForResult之后,ResultActiviy如果是singleTask和singleInstance自动转为standard,并且从singleInstance ResultActivity启动的Activity,将会自动起一个新的Task,Activity将会被放在新栈中。

 

try do it!

Android SingleTask启动模式与Home键的问题

Android SingleTask启动模式与Home键的问题

我们知道SingleTask模式对于Activity的影响如下:

例如我们将Activity A设置为SingleTask模式,其他的Acitivity设置为Standard模式,则有以下效果:

A -> B -> C -> D 我们将Activity A一直跳转到Activity D,如果此时D -> A,则会发生Activity B,C,D都会被pop出栈中Activity A则会显示到栈顶。

我利用这个特性时,处理单端登录:将将Activity A设置成SingleTask模式,并设置成启动的Acitivity,

如果后台告知账号在其他地方登录了,则此时直接将跳转Activity A即可,其他的Acitivity都会被pop出去。

现在问题就来了,我们将App的启动的MainActivity设置为SingleTask模式时,如果我们在App跳转到Activity B时,按下Home键,此时点击App Icon,

此时不是显示Activity B,还是直接会显示Activity A,即是把A上面的Activity都会被pop出去,Activity A显示到栈顶,但这不是我想要的。

问题描述:

My main activity A has as set android:launchMode="singleTask" in the manifest. Now,whenever I start another activity from there,e.g. B and press the HOME BUTTON on the phone to return to the home screen and then again go back to my app,either via pressing the app‘s button or pressing the HOME BUTTONlong to show my most recent apps it doesn‘t preserve my activity stack and returns straight to A instead of the expected activity B.

Here the two behaviors:

Expected: A > B > HOME > B
Actual: A > B > HOME > A (bad!)

如何处理呢:

Just remove the launchMode="singleTask" and set FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP flag whenever call an intent to A

 

链接:https://stackoverflow.com/questions/2417468/android-bug-in-launchmode-singletask-activity-stack-not-preserved

关于Android SingleTask,SingleTop和Home Button的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于"standard,singleTop,singleTask,singleInstance"-Android启动模式、android singleTask onNewIntent、Android singleTask+askAffinity的使用方式、Android SingleTask启动模式与Home键的问题等相关内容,可以在本站寻找。

本文标签: