Activity基础学习

一、Activity是什么

Activity是一种可以包含用户界面的组件,主要用于和用户进行交互。
一个应用可以包含零个或多个Activity。但不包含Activity的应用程序无法被用户看到。

二、Activity的基本用法

1、手动创建Activity

我们可以先创建一个没有Activity的项目,即在创建项目的时候选择“Add No Activity”。
项目名字可以叫做ActivityTest,包名默认为com.example.activitytest。

此时com.example.activitytest这个包是空的,我们需要手动创建一个Activity。
右击这个包 --> New --> Activity --> Empty Activity,我们将其命名为FirstActivity。
在弹出的对话框内有两个选项,勾选Generate Layout File表示自动为FirstActivity创建一个布局文件,勾选Launcher Activity表示会将其设置为当前项目的主Activity。

打开你创建的Activity文件:

class FirstActivity : AppCompatActivity(){
	override fun onCreate(savedInstanceState: Bundle?){
		super.onCreat(savedInstanceState);
	}
}

它已经帮你写好了一个方法,而且这个方法非常简单,就是调用了父类的onCreat方法。

2、创建和加载布局

Android程序设计讲究逻辑和视图分离,最好每一个Activity都对应一个布局。
布局是显示界面内容的,现在手动创建一个布局文件,app/src/main/res目录下先创建一个名为layout的目录,然后在其下建一个Layout resource file的布局文件,命名first_layout,根元素默认选择LinearLayout。

现在first_layout.xml文件中是如下代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
</LinearLayout>

由于创建布局选择了LinerLayout作为根元素,因此现在布局文件中已经有一个LinerLayout元素了,现在添加一个按钮元素:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="按钮"
    />

</LinearLayout>

Button元素中的属性:

  • android:id : 是给当前的元素定义一个唯一 的标识符(@+id是定义一个id的意思,@id是是引用id)
  • android:layout_width : 指定了当前元素的宽度
  • android:layout_height: 指定当前元素的高度
  • android:text :指定了当前元素中显示的文字内容
  • wrap_content :表示让当前元素只要刚好包含里面的内容
  • match_parent :表示让当前元素和父元素一样宽(高)

可以通过右侧Validation(之前版本是Preview)来预览当前布局。

然后在FirstActivity中加载这个布局:

class FirstActivity : AppCompatActivity(){
	override fun onCreate(savedInstanceState: Bundle?){
		super.onCreat(savedInstanceState);
		setContentView(R.layout.first_layout)
	}
}

可以看到,这里调用了setContentView()方法来给当前的Activity加载一个布局,参数是布局文件的id,因为项目中的任何资源都会在R文件中生成一个相应的资源id,所以可以通过R.layout.first_layout来获得first_layout.xml布局的id,填入该方法中。

3、在AndroidManifest文件中注册

所有的Activity都需要在AndroidManifest.xml中注册才能生效,Android Studio会自动帮我们完成注册,下面看AndroidManifest文件中的代码:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Apptheam">
        
        <activity android:name=".FirstActivity">
        </activity>
        
    </application>
</manifest>

在<activity>标签中,android:name来指定具体注册哪个Activity,这里填入的.FirstActivity是com.example.activitytest.FirstActivity,即Activity路径的缩写,因为我们在最外层<manifest>标签通过package属性指定了包名,所以可以省略报名只写.FirstActivity。

如果要想让程序运行,就必须配置主Activity,要想配置主Activity,就在哪个Activity的<activity>标签内加入以下代码,此时的<activity>标签为:

<activity android:name=".FirstActivity"
	android:label="This is FirstActivity">
	<intent-filter>
		<action android:name="android.intent.action.MAIN" />
		<category android:name="android.intent.category.LAUNCHER" />
	</intent-filter>
</activity>

此处的android:label用来指定Activity中标题栏的内容,如果是主Activity,还会成为启动器中应用程序显示的名称。

现在就可以运行程序了。

4、在Activity中使用Toast

Toast是Android中的一种非常好的提醒方式,就是你经常在各类app中看到的显示在底部的存在一段时间就自动消失的消息,在程序中它可以将一些短小的消息通知给用户,一段时间后自动消失,不会占任何屏幕空间。

在Activity中使用Toast非常简单,首先定义一个弹出Toast的触发点,之前写的程序中写了一个按钮,将其作为触发点来弹出Toast,如下:

override fun onCreate(savedInstanceState: Bundle?){
	super.onCreat(savedInstanceState);
	setContentView(R.layout.first_layout)
	val button1: Button = findViewById(R.id.button1)//导入插件之后这一行就可以不用了
	button1.setOnClickListener{
		Toast.makeText(this,"你按了按钮",Toast.LENGTH_SHORT).show()
	}
}

注意:

  • ① 在Activity中,你可以通过findViewById()方法来获取在布局文件中定义的元素,其返回对象是一个继承自View的泛型对象,Kotlin无法自动推导它是一个什么控件,因此需要将button1显式地定义成Button类型。
  • ② 在Kotlin中引入kotlin-android-extensions插件之后,它就会根据布局文件中定义控件的id自动生成一个具有相同名称的变量,直接调用使用这个变量即可。
  • ③ 得到按钮的实例之后,通过setOnClickListener()方法为其注册一个监听器,点击即会执行监听器中的onClick()方法,弹出Toast的功能就在onClick()方法中编写的了。
  • ④ Toast的用法:通过静态方法makeTest()创建一个Toast对象,然后调用show()方法将其显示出来即可。makeTest()方法中的三个参数:第一个参数是Context,即Toast的上下文,因Activity本身就是一个Context对象,所以传入this即可;第二参数是Toast显示的文本内容;第三个参数是Toast显示的时长,有两个内置变量可以选择:Toast.LENGTH_SHORT和Toast.LENGTH_LONG。

5、在Activity中使用Menu

手机的屏幕控件非常有限,为了充分利用手机屏幕空间,Android提供了一种很不错的解决方式。

首先在res下新建一个menu文件夹,右键点击New->Menu resource file 新建一个叫“main”的菜单文件,然后添加如下代码:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
	<item
		android:id="@+id/add_item"
		android:title="Add"/>
	<item
		android:id="@+id/remove_item"
		android:title="Remove"/>
</menu>

这里创建了两个菜单项,其中<item>标签用来创建具体的某一个菜单项,然后通过android:id来给这个菜单项指定一个唯一标识符,通过android:title给这个菜单项指定一个名称。

然后回到FirstActivity中来重写onCreateOptionMenu()方法,并且在方法中编写如下代码:

override fun onCreateOptionMenu(menu:Menu?):Boolean{
	menuInflater.inflate(R.menu.main,menu);
	return true;
} 

这里menuInflater使用了Kotlin中的语法糖,实际上是调用了父类的getMenuInflater()方法,获得一个MenuInflater,再调用其inflate()方法,这样即可给Activity创建菜单。
在inflate()方法中接收两个参数:第一个参数用于指定我们通过哪个资源文件来创建菜单;第二个参数用于指定我们的菜单项将添加到哪个Menu对象中.
最后返回true表示允许我们创建的菜单显示出来,若返回了false,创建的菜单将无法显示。

这时候菜单可以显示了,如果我们想使用这个菜单,就要再定义菜单响应事件:在FirstActicity中重写onOptionsItemSelected()方法,如下:

override fun onOptionsItemSelected(item: MenuItem): Boolen{
	when(item.itemId){
		R.id.add_item -> Toast.makeText(this,"你点击了Add",Toast.LENGTH_SHORT).show();
		R.id.remove_item -> Toast.makeText(this,"你点击了Remove",Toast.LENGTH_SHORT).show();
	}
	return true;
}

6、销毁一个 Activity

(1)按一下 Back 键

就按一下返回键就完事了。

(2)通过程序来销毁

调用finish()方法即可:

button1.setOnClickListener{
	finish()
}

这里点一下按钮就销毁Activity了。

三、使用Intent在Activity中穿梭

Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件要执行的动作,还可以在不同组件之间传递数据。

Intent一般可用于启动Activity、启动Service以及发送广播等场景。

Intent大致可分为显示Intent和隐士Intet。

1、使用显式Intent

在上述程序的基础上再创建一个Activity命名为SecondActivity,打开自动生成的second_layout.xml,将里面代码替换成如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="match_parent">

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="另一个按钮"
    />
</LinearLayout>

这里还是定义了一个按钮。
此时这个Activity自动在AndroidManifest.xml中注册了,会多如下代码:

<activity android:name=".SecondActivity">
</activity>

下面来看Intent。

Intent有多个构造函数的重载,其中一个是Intent(Content packageContext, Class<?> cls),这个构造函数接收两个参数:第一个参数Content要求提供一个启动Activity的上下文;第二个参数Class用于指定想要启动的目标Activity。
在Activity类中提供了一个startActivity()方法,专门用于启动Activity,它接收一个Intent参数,我们将构建好的Intent传入即可。

修改FirstActivity中按钮的点击事件:

button1.setOnclickListener{
	val intent = Intent(this, SecondActivity::class.java)
	startActivity(intent)
}

这样点击FirstActivity中的按钮之后就会跳转到SecondActivity,要想返回的话,按一下Back键即可。

2、使用隐式Intent

相较于显示Intent,隐式Intent并不明确指出想要启动哪个Activity,而是更加抽象地指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并找到合适的Activity去启动。

所谓合适的Activity,即可以响应这个Intent的Activity。
通过在<activity>标签下配置<intent-filter>的内容,可指定当前Activity的action和category,打开AndroidManifest.xml,添加代码:

<activity android:name=".SecondActivity">
	<intent-filter>
		<action android:name="com.example.activitytest.ACTION_START" />
		<category android:name="android.intent.category.DEFAULT" />
	</intent-filter>
</activity>

在<action>标签中指定了本Activity可以响应com.example.activitytest.ACTION_START这个action,而<category>标签包含了一些附加信息,更加精确地指明了当前Activity能够响应的Intent可能带有的category。只有当<action>和<category中的内容同时匹配Intent中指定的action和category时,这个Activity才能响应该Intent。

修改First中按钮的点击事件:

button1.setOnClickListener{
	val intent = Intent("com.example.activitytest.ACTION_START")
	startActivity(intent)
}

这里提一点,android.intent.category.DEFAULT是一种默认的category,在调用startActivity()的时候会自动添加到Intent中。

Intent添加category的方法如下:

intent.addCategory("这里添加<category>标签中对应的内容")

3、更多隐式Intent的用法

这里举两个,响应网页和电话。

(1)打开网页与响应网页

例如点击按钮打开百度,修改FirstActivity中按钮的点击事件:

button1.setOnClickListener{
	val intent = Intent(Intent.ACTION_VIEW)
	intent.data = Uri.parse("https://www.baidu.com")
	startActivity(intent)
}

这里首先指定了Intent的action是Intent.ACTION_VIEW,这是一个Android系统内置的动作,其常量值为android.intent.action.VIEW。
然后通过Uri.parse()方法将一个网址字符串解析成一个Uri对象,再调用Intent的setData()方法将这个Uri对象传递进去。

与之对应的,我们还可以再/标签中再配置一个/标签用于指定当前Action能够响应的数据。
<data>标签可以配置以下内容:

  • android:scheme:用于指定数据的写一部分,如上例https部分
  • android:host:用于指定数据的主机名部分,如上例www.baidu.com部分
  • android:port:用于指定数据端口部分,一般紧随在主机名后
  • android:path:用于指定主机名和端口之后的部分,如一段网址中跟在用户名之后的部分
  • android:mimeType:用于指定可以处理的数据类型,允许使用通配符的方式指定

只有当<data>标签中指定的内容和Intent中携带的Data完全一致时,该Activity才会响应该Intent。
不过在<data>标签中一般不会指定过多内容。

这里再提一点,Android Studio认为所有能够响应ACTION_VIEW的Activity都应该加上BROWSABLE的category,否则就会给出一段警告提醒。加上BROWSABLE的category是为了实现deep link功能,这里没得学到,所以可以直接再<intent-filter>上使用tools:ignore属性将警告忽略,即改成:\<intent-filter tool:ignore="AppLinkUrlError">

(2)调用系统拨号界面

button1.setOnClickListener{
	val intent = Intent(Intent.ACTION_DIAL)
	intent.data = Uri.parse("tel:10086")
	startActivity(intent)
}

首先指定了Intent的action是Intent.ACTION_DIAL,然后再data部分定义了协议是tel,号码是10086。

4、向下一个Activity传递数据

Intent中提供了一系列putExtra()方法的重载,可以将我们想要传递的数据暂存到Intent中,在启动另一个Activity后再从Intent中取出来即可。

例如传递一个字符串:

button1.setOnClickListener{
	val data = "你好哇!";
    val intent = Intent(this,SecondActivity::class.java)
    intent.putExtra("extra_data", data)
    startActivity(intent)
}

然后再在SecondActivity中取出:

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.second_activity)
        val extraData = intent.getStringExtra("extra_data")
        Log.d("SecondActivity", "extra data is $extraData")
}

上述代码中的intent也是调用父类的getIntent()方法获取到Intent。
若传递的是整形数据,则用getIntExtra(),布尔类型则用getBooleanExtra(),以此类推。

5、返回数据给上一个Activity

在Activity类中有一个用于启动Activity的startActivityForResult()方法,它期望Activity销毁的时候能够返回一个结果给上一个Activity。
startActivityForResult()方法接收两个参数:第一个是Intent;第二个是请求码。

例如:

//FirstActivity
button1.setOnClickListener{
     val intent = Intent(this,SecondActivity::class.java)
	startActivityForResult(intent, 1)
}

(1)使用按钮调用finish()方法销毁Activity返回

//SecondActivity
class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.second_activity)
        button2.setOnClickListener{
            val intent = Intent()
            intent.putExtra("data_return", "你也好哇!")
            setResult(RESULT_OK, intent)
            finish()
        }
    }
}

在SecondActivity中的intent仅仅用于传递数据而已,没有“意图”。
将要传递的数据存入Intent中,然后调用setResult()方法向上一个Activity返回数据。
setResult()方法接收两个参数:第一个参数用于向上一个Activity返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED;第二个参数是带有要传递数据的Intent。
最后调用finish()方法销毁当前Activity。

(2)按下Back销毁Activity返回

通过在SecondActivity抽个血onBackPerssed()方法来实现:

override fun onBackPressed() {
    val intent = Intent()
    intent.putExtra("data_return", "你也好哇!")
    setResult(RESULT_OK, intent)
	finish()
}

类似

(3)接收返回值

由于我们是使用startActivityForResult()来启动的SecondActivity,所以在其销毁后会回调上一个Activity的onActivityResult()方法:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
	super.onActivityResult(requestCode, resultCode, data)
    when  (requestCode){
        1 -> if(resultCode == RESULT_OK){
            val returnData = data?.getStringExtra("data_return")
            Log.d("FirstActivity", "returned data is $returnData")
		}
	}
}

onActivityResult()方法带有三个参数:第一个requestCode是我们在启动Actvity时传入的请求码;第二个resultCode是返回数据时传入的处理结果;第三个data是携带着返回值的Intent。

四、Activity的生命周期

1、返回栈

Android中的Activity是可以层叠的,我们每启动一个新的Activity,就会覆盖到原Activity上,然后点击Back键就会销毁最上层的Activity,下面的Activity就会重新显示出来。

Android是通过任务(task)来管理Activity的,一个任务就是一组存放在栈里的Activity的集合,这个栈也被称为返回栈。
栈是一种先进后出的数据结构,新Activity来了就会压栈,系统总会是显示栈顶的Activity给用户看,而当栈顶的Activity销毁后,会被弹出栈,继续显示栈顶的Activity,即销毁的Activity的下一个Activity。

2、Activity状态

每个Activity在其生命周期中最多可能会有四种状态。

(1)运行状态

当一个Activity位于返回栈的栈顶时,Activity就会处于运行状态。
系统最不愿意回收的就是运行状态的Activity,因为这会带来非常差的用户体验。

(2)暂停状态

当一个Activity不再处于栈顶位置,但仍然可见时就进入了暂停状态,例如弹出的只占用屏幕中间的对话框形式Activity。
处于暂停状态的Activity仍然是完全存活着的,系统也不愿意回收这类Activity,只有在内存极低的情况下才会去考虑回收这类Activity。

(3)停止状态

当一个Activity不处于栈顶位置且完全不可见的时候,就进入了停止状态。
系统仍然会为这种Activity保存相应的状态和成员变量,但这并不是完全可靠的,当其他地方需要内存时,处于停止状态的Activity就可能被系统回收。

(4)销毁状态

一个Activity从返回栈移除后就变成了销毁状态。
系统最倾向于回收处于这种状态的Activity,以保证手机内存的充足。

3、Activity的生存期

Activity类中定义了7个回调方法覆盖了Activity生命周期中的每个环节。

  • onCreat():我们在每个Activity中都重写了这个方法,它会在Activity第一次被创建的时候调用。应该在这个方法中完成Activity的初始化操作,比如加载布局、绑定事件等。
  • onStart():这个方法在Activity由不可见变为可见的时候调用。
  • onResume():这个方法在Activity准备好和用户进行交互的时候调用,此时的Activity一定位于返回栈的栈顶,并且处于运行状态。
  • onPause():这个方法在系统准备去启动或恢复另一个Activity的时候调用。通常在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法执行一定要快,不然会影响到新的栈顶Activity的使用。
  • onStop():这个发给发在Activity完全不可见的时候调用。它和onPause()的区别在于:若启动的新Activity是对话框形式的Activity,那么onPause()会执行,onStop不会执行。
  • onDestory():这个方法在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。
  • onRestart():这个方法在Activity由停止状态变为运行状态之前调用,也就是Activity被重新启动了。

以上七个方法除了onRestart()方法,其他都是两两相对的,从而又可以将Activity分为以下三种生存期:

  • 完整生存期:Activity在onCreat()方法和onDestory()方法之间经历的就是完整生存期。一般情况下,一个Activity会在onCreat()方法中完成各种初始化操作,在onDestory()方法中完成释放内存的操作。
  • 可见生存期:Activity在onStart()方法和onStop()方法之间精力的就是可见生存期。在可见生存期内,Activity对用户总是可见的,即便有可能无法和用户进行交互。可以通过这两个方法合理地管理那些对用户可见的资源。比如在onStart()方法中对资源进行加载,在onStop()方法中对资源进行释放,从而保证处于停止状态的Activity不会占用过多内存。
  • 前台生存期:Activity在onResume()方法和onPause()方法之间所经历的就是前台生存期。在前台生存期内,Activity总是运行状态,此时的Activity是可以和用户进行交互的,我们平时看到的和接触最多的就是这个状态下的Activity。
将Activity设置成对话框式

只需要修改AndroidManifest.xml中的<activity>标签即可。

<activity android:name=".DialogActivity"
	android:theme="@style/Theme.AppCompat.Dialog">
</activity>

4、Activity被回收了怎么办

当一个Activity进入了停止状态,是有可能被系统回收的。

假如有这么一个场景:应用中有一个Actvity A(这里简称A),在A的基础上启动了Activity B(这里简称B),A就进入了停止状态,这个时候系统内存不足所以将A回收了,接下来用户按下Back键返回A,那么会发生什么问题?
其实还是能够回到A的,但是这个A并不会执行onRestart()方法,而是会执行A的onCreate()方法,因为此时的A会被重新创建一次。但是这里又一个问题,你在A中存储的数据就会不见了,因为A重新创建了。

要想解决这个问题,保存数据,就需要用到Activity中提供的onSaveInstanceState()回调方法。
onSaveInstanceState()方法会携带一个Budle类型的参数,Budle提供了一系列的方法用于保存数据,如使用putString()方法并保存字符串,使用putInt()方法保存整形数据,以此类推。每个保存方法需要传入两个参数,第一个参数是键,用于后面从Bundle中取值,第二个是要保存的内容。

例如添加如下代码,首先是保存数据:

override fun onSaveInstanceState(outState: Bundle){
	super.onSaveInstanceState(outState)
	val tempData = "这里是一条数据"
	outState.putString("key",tempData)
}

获取数据:

override fun onCreate(saveInstanceState: Bundle?){
	super.onCreat(saveInstanceState)
	Log.d(tag, "onCreate")
	setContentView(R.layout.activity_main)
	if(saveInstanceState != null){
		val tempData = saveInstanceState.getString("key")
		Log.d(tag,tempData)
	}
}

Intent还可以结合Bundle来一起传递数据,首先将数据存到Bundle对象中,再把Bundle对象存入Intent中即可,到了目标Activity之后,先从Intent中取出Bundle,然后再从Bundle中取出数据。

五、Activity的启动模式

在实际项目中我们应该根据特定的需求为每个Activity指定恰当的启动模式。

启动模式一共四种,分别是standard、singleTop、singleTask、singleInstance,可以在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。

1、standard

standard是Activity默认的启动模式,在不进行显示指定的情况下,所有Activity都会自动使用这种启动模式。
Android是使用返回栈来管理Activity的,在standard模式下,每当启动一个新的Activity,他就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的Activity,系统并不在乎这个Activity是否已经在返回栈中存在,每次启动都会创建一个该Activity的新实例。

测试standard模式:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    Log.d("FirstActivity",this.toString())
    setContentView(R.layout.first_layout)
    button1.setOnClickListener{
        val intent = Intent(this,FirstActivity::class.java)
        startActivity(intent)
    }
}

代码是在FirstActivity(简称A)的基础上启动A,从逻辑上来讲,确实没什么意义,但如果你点击两次这个按钮,你会发现控制台上,每当你点击一次按钮,就会创建出一个新的A,此时返回栈中会有三个A实例,也就意味着需要连续按三次Back键才能退出程序。

2、singleTop

当Activity的启动模式指定为singleTop,在启动Activity时如果发现返回栈的栈顶已经是该Activity,则认为可以直接使用它,不会再创建新的Activity实例。

测试singleTop模式,首先修改启动模式:

<activity
            android:name=".FirstActivity"
            android:launchMode="singleTop"
            android:label="FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

重新运行程序后,不管你点多少次按钮,控制台都不会再有新的打印信息出现了,因为目前A已经处于返回栈的栈顶,每当想要启动一个Activity时,都会直接使用栈顶的Activity,因此A只有一个实例,仅按一次Back键即可退出程序。

不过需要注意一点,当A未处于栈顶的情况下,再启动FirstActvity还是会创建新的实例。

3、singleTask

使用singleTop可以很好地解决重复创建栈顶Activity的问题,但是如果Activity不在栈顶,还是可能会创建多个Activity实例。

借助singleTask就可以实现让某个Activity在整个应用程序的上下文只有一个实例。当Activity的启动模式指定为singleTask,每次启动该Activity,系统首先会在返回栈中检查是否存在该Activity的实例,如果发现已经存在则直接使用该实例,并把在这个Actvity之上的所有其他Activity全部出栈,如果没有发现就会创建一个新的实例。

4、singleInstance

singleInstance模式应该算是四种启动模式中最特殊也最复杂的一个了,不同于其他三种启动模式,指定为singleInstance模式的Activity会启用一个新的返回栈来管理这个Activity(若singleTask指定了不同的taskAffinity,也会启动一个新的返回栈)。
假设我们有一个Activity是允许其他Activity调用的,如果想实现其他程序和我们的程序可以共享这个Activity的实例,就可以使用singleInstance模式来实现,在这种模式下,会有一个单独的返回栈来管理这个Activity,不管哪个应用程序来访问这个Activity,都共用同一个Activity,也就解决了共享Activity实例的问题。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浅梦曾倾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值