Android之Activity LaunchMode

背景:

在众多Activity开发中,有可能是自己应用之间的Activity跳转,可能希望跳转到原来某个Activity实例,而不是产生大量重复的Activity实例。

这种需求需要通过配置Activity的LaunchMode来实现。


Activity有四种加载模式:

1.standard(标准模式,此项是默认的加载模式)

在此种模式情况下的Activity会每次都生成新的实例


我们首先定义了A这个Activity,然后它的内容如下:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class A extends Activity implements OnClickListener {

	private TextView textView01;
	private Button btn01;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_a);

		textView01 = (TextView) findViewById(R.id.tv_01);
		btn01 = (Button) findViewById(R.id.button1);
		btn01.setOnClickListener(this);
		
		//获取当前Activity的任务栈ID
		int taskID = A.this.getTaskId();
		//获取当前Activity实例的详细信息
		String objectMsg = A.this.toString();
		//将信息输出到屏幕上
		textView01.setText("当前任务栈ID:" + taskID + "\r\n"  
				+ "当前Activity实例信息:"+ objectMsg);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button1:
			//开始跳转Activity
			Intent intent = new Intent(A.this, A.class);
			startActivity(intent);
			break;

		default:
			break;
		}

	}
}


在程序运行之后,我们点击2次《跳转到A》这个按钮,会发现三个不同的界面:


技术分享   技术分享         技术分享 


观察发现:这三个A同属于一个任务栈,因为栈的ID都相同,但是他们的实例名称都不一样,说明这个任务栈中现在已经存在了三个不同的A实例;如果此时点击手机上的《返回》按键,那么需要连续点击三次才能退出程序。


将以上总结为流程图如下:

技术分享


2.singleTop模式

在此种模式下,

如果A在任务栈顶,那么A跳转到A将不生成新的实例,直接跳转到现在的栈顶A;

如果A不在任务栈顶,那么其他的Activity去跳转到A,将生成新的A实例;


我们在代码中定义两个Activity,分别是A和B,以上是这两个Activity的定义,其中A的launchMode属性被设置为singleTop。

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class A extends Activity implements OnClickListener {

	private TextView textView01;
	private Button btn01;
	private Button btn02;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_a);

		textView01 = (TextView) findViewById(R.id.tv_01);
		btn01 = (Button) findViewById(R.id.button1);
		btn01.setOnClickListener(this);
		btn02 = (Button) findViewById(R.id.button2);
		btn02.setOnClickListener(this);
		
		//获取当前Activity的任务栈ID
		int taskID = A.this.getTaskId();
		//获取当前Activity实例的详细信息
		String objectMsg = A.this.toString();
		//将信息输出到屏幕上
		textView01.setText("当前任务栈ID:" + taskID + "\r\n"  
				+ "当前Activity实例信息:"+ objectMsg);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button1:
			//A--->A
			Intent intent01 = new Intent(A.this, A.class);
			startActivity(intent01);
			break;
		case R.id.button2:
			//A---->B
			Intent intent02 = new Intent(A.this, B.class);
			startActivity(intent02);
			break;
		

		default:
			break;
		}

	}
}


import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class B extends Activity implements OnClickListener {

	private TextView textView01;
	private Button btn01;
	private Button btn02;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_a);

		textView01 = (TextView) findViewById(R.id.tv_01);
		btn01 = (Button) findViewById(R.id.button1);
		btn01.setOnClickListener(this);
		btn02 = (Button) findViewById(R.id.button2);
		btn02.setOnClickListener(this);
		
		//获取当前Activity的任务栈ID
		int taskID = B.this.getTaskId();
		//获取当前Activity实例的详细信息
		String objectMsg = B.this.toString();
		//将信息输出到屏幕上
		textView01.setText("当前任务栈ID:" + taskID + "\r\n"  
				+ "当前Activity实例信息:"+ objectMsg);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button1:
			//B--->A
			Intent intent01 = new Intent(B.this, A.class);
			startActivity(intent01);
			break;
		case R.id.button2:
			//B---->B
			Intent intent02 = new Intent(B.this, B.class);
			startActivity(intent02);
			break;
		

		default:
			break;
		}

	}
}


在程序运行后,我们点击跳转到A,界面不会有任何变化,说明当A在任务栈顶时,你发送跳转到A的Intent,那么这个Intent会发送给栈顶的A实例;

以下三张图片展示的流程是A---->B---->A:

技术分享   技术分享    技术分享


观察发现:这三个Activity实例是不同的实例,但是他们同属一个任务栈,因为他们的任务栈ID相同;我们这里可以很明显的发现,当B在栈顶的时候,跳转到A,会生成新的A实例。


将以上总结为流程图如下:

技术分享


3.singleTask模式

在此种模式,任务栈中只能有一个A实例,不管它在任务栈的什么位置;

这里我们应当注意:当A在栈顶时,直接跳转到A实例;当A不在栈顶时,将会发生的事情是,在A之上的所有Activity实例被弹出任务栈,直至A到达栈顶。


本次仍然沿用上一次的代码,只是在manifest中将A的launchMode配置为singleTask,在B中添加一个Button跳转到C,然后C中只有一个按钮,这个按钮的作用是跳转到A。

以下四张图片展示了A---->B---->C---->A:

技术分享 技术分享 

技术分享 技术分享


观察以上结果我们可以发现:总共有三个实例,A、B、C各一个,当C在栈顶的时候,跳转到A,我们会返现,Intent会直接发送到栈底的A实例,并且将B、C两个实例弹栈。


将以上总结为流程图如下:

技术分享


4.singleInstance模式

此Activity加载模式是为了解决这样一类问题:

在同一App中,当有一个Activity需要被多个Activity共享(即是多个Activity可以跳转到这个Activity),那么我们肯定希望此Activity长期处于Alive状态,并且是同一个实例(这样更能节省手机资源),但是同一app中,所有的Activity实例都在同一个任务栈中,我们会发现,经常性的压栈和弹栈使我们无法确定此Activity会在什么时候被弹栈销毁掉了,这个时候我们可以通过将此Activity的加载模式设置为singleInstance来满足这样的需求,当设置为此模式后,此Activity被单独在一个任务栈中维护,而不受主任务栈中频繁的压栈和弹栈操作的影响。


其实写到这个地方我觉得文字的表现力始终不及图形,首先我们来看一下,将B的launchmode设置为singleInstance,然后再来分析以下的图片结果:

技术分享   技术分享   技术分享

分析以上结果我们会发现:B实例的任务栈ID,与A实例所在的任务栈ID不相同,说明他们处于不同的任务栈中;

并且这只是一种情况,实际这里有好几种情况,我将其总结到下面这张图中,希望能够对读者真的产生帮助;


写这篇文章的时候我想起了古人的一句话,纸上得来终觉浅,绝知此事要躬行,网上流行一篇讲LaunchMode的文章,全是用蓝色的图解,实际上我很受益于这篇文章,但是当我写这篇文章的时候我发现“我认为以前的我完全懂了”是不全面的,我对LauchMode似乎有了新的认识,感谢实践!!!


下面来本篇最后一张我绘的流程图:

技术分享



例行公事,把代码链接放这里:

Android Activity LaunchMode

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。