Android學習筆記-Activity的啟動模式

u010186280發表於2020-10-01

Activity的啟動模式——standard

  • standard是Activity預設的啟動模式,在不進行顯式指定的情況下,所有Activity都會自動使用這種啟動模式。

  • 在standard模式下,每當啟動一個新的Activity,它就會在返回棧中入棧,並處於棧頂的位置。

  • 對於使用standard模式的Activity,系統不會在乎這個Activity是否已經在返回棧中存在,每次啟動都會建立一個該Activity的新例項。

在這裡插入圖片描述

程式碼演示,建立一個Activity,在該Activity中啟動一個新的Activity,啟動模式不設定(預設為standard
FirstActivity:

package com.easycol.reactivitylifecycle

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.android.synthetic.main.activity_first.*

class FirstActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_first)

        Log.d("FirstActivity", "FirstActivity onCreate")

        button.setOnClickListener{
            val intent = Intent(this, FirstActivity::class.java)
            startActivity(intent)
        }
    }

    override fun onStart() {
        super.onStart()
        Log.d("FirstActivity", "FirstActivity onStart")
    }

    override fun onResume() {
        super.onResume()
        Log.d("FirstActivity", "FirstActivity onResume")
    }
}

activity_first.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FirstActivity">

    <TextView
        android:id="@+id/text"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="15dp"
        android:textSize="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textAlignment="center"
        android:textColor="@color/colorPrimaryDark"
        android:text="第一個頁面"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/text"
        android:layout_marginTop="15dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textAllCaps="false"
        android:text="啟動一個另一個FirstActivity"
        android:textSize="20dp"
        android:textColor="@color/colorPrimaryDark"/>

</androidx.constraintlayout.widget.ConstraintLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.easycol.reactivitylifecycle">

    <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/AppTheme">
        <activity android:name=".FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

在這裡插入圖片描述

啟動程式:

2020-10-01 17:41:16.917 26751-26751/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onCreate
2020-10-01 17:41:16.927 26751-26751/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onStart
2020-10-01 17:41:16.933 26751-26751/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onResume

刪除列印,點選按鈕:

2020-10-01 17:42:27.036 26751-26751/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onCreate
2020-10-01 17:42:27.046 26751-26751/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onStart
2020-10-01 17:42:27.048 26751-26751/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onResume

說明新建立了一個Activity。

Activity的啟動模式——singleTop

  • 當Activity的啟動模式指定為singleTop,在啟動Activity時如果發現返回棧的棧頂已經是該Activity,則認為可以直接使用它,不會再建立新的Activity例項。
    在這裡插入圖片描述

還是剛才的程式碼,設定FirstActivity的啟動模式為singleTop

<activity android:name=".FirstActivity"
            android:launchMode="singleTop">

啟動程式:

2020-10-01 17:45:53.303 26965-26965/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onCreate
2020-10-01 17:45:53.313 26965-26965/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onStart
2020-10-01 17:45:53.316 26965-26965/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onResume

刪除列印,點選按鈕:

2020-10-01 17:46:27.347 26965-26965/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onResume

說明並沒有建立新的Activity,複用了已經建立的FirstActivity

Activity的啟動模式——singleTask

  • 當Activity的啟動模式指定為singleTask,每次啟動該Activity時,系統首先會在返回棧中檢查是否存在該Activity的例項,如果發現已經存在則直接使用該例項,並把在這個Activity之上的所有其他Activity統統出棧,如果沒有發現就會建立一個新的Activity例項。

在這裡插入圖片描述

程式碼演示:在前面程式碼的基礎上,新建一個Activity(SecondActivity

修改FirstActivity的程式碼,並設定FirstActivity的啟動模式為singleTask,程式碼如下:
FirstActivity

package com.easycol.reactivitylifecycle

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.android.synthetic.main.activity_first.*

class FirstActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_first)

        Log.d("FirstActivity", "FirstActivity onCreate")

        button.setOnClickListener{
            val intent = Intent(this, FirstActivity::class.java)
            startActivity(intent)
        }

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

    override fun onStart() {
        super.onStart()
        Log.d("FirstActivity", "FirstActivity onStart")
    }

    override fun onResume() {
        super.onResume()
        Log.d("FirstActivity", "FirstActivity onResume")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("FirstActivity", "FirstActivity onDestroy")
    }
}

activity_first.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FirstActivity">

    <TextView
        android:id="@+id/text"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="15dp"
        android:textSize="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textAlignment="center"
        android:textColor="@color/colorPrimaryDark"
        android:text="第一個頁面"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/text"
        android:layout_marginTop="15dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textAllCaps="false"
        android:text="啟動另一個FirstActivity"
        android:textSize="20dp"
        android:textColor="@color/colorPrimaryDark"/>

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/button"
        android:layout_marginTop="15dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginStart="15dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:textAllCaps="false"
        android:text="啟動SecondActivity"
        android:textSize="20dp"
        android:textColor="@color/colorPrimaryDark"/>



</androidx.constraintlayout.widget.ConstraintLayout>

SecondActivity

package com.easycol.reactivitylifecycle

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.android.synthetic.main.activity_first.*

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)

        Log.d("SecondActivity", "SecondActivity onCreate")

        button.setOnClickListener{
            val intent = Intent(this, FirstActivity::class.java)
            startActivity(intent)
        }
    }

    override fun onStart() {
        super.onStart()
        Log.d("SecondActivity", "SecondActivity onStart")
    }

    override fun onResume() {
        super.onResume()
        Log.d("SecondActivity", "SecondActivity onResume")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("SecondActivity", "SecondActivity onDestroy")
    }
}

activity_second.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SecondActivity">

    <TextView
        android:id="@+id/text"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="15dp"
        android:textSize="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textAlignment="center"
        android:textColor="@color/colorPrimaryDark"
        android:text="第二個頁面"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/text"
        android:layout_marginTop="15dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textAllCaps="false"
        android:text="啟動FirstActivity"
        android:textSize="20dp"
        android:textColor="@color/colorPrimaryDark"/>


</androidx.constraintlayout.widget.ConstraintLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.easycol.reactivitylifecycle">

    <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/AppTheme">
        <activity android:name=".SecondActivity"
            android:launchMode="standard"></activity>
        <activity
            android:name=".FirstActivity"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

啟動程式,點選啟動SecondActivity按鈕

在這裡插入圖片描述

跳轉到SecondActivity
在這裡插入圖片描述

然後點選啟動FirstActivity按鈕,檢視列印結果:
針對FirstActivity:

2020-10-01 21:31:02.598 29467-29467/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onCreate
2020-10-01 21:31:02.617 29467-29467/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onStart
2020-10-01 21:31:02.626 29467-29467/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onResume
2020-10-01 21:31:08.089 29467-29467/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onStart
2020-10-01 21:31:08.091 29467-29467/com.easycol.reactivitylifecycle D/FirstActivity: FirstActivity onResume

針對SecondActivity

2020-10-01 21:34:12.367 29568-29568/com.easycol.reactivitylifecycle D/SecondActivity: SecondActivity onCreate
2020-10-01 21:34:12.377 29568-29568/com.easycol.reactivitylifecycle D/SecondActivity: SecondActivity onStart
2020-10-01 21:34:12.379 29568-29568/com.easycol.reactivitylifecycle D/SecondActivity: SecondActivity onResume
2020-10-01 21:34:14.751 29568-29568/com.easycol.reactivitylifecycle D/SecondActivity: SecondActivity onDestroy
  • SecondActivity啟動FirstActivity時,並沒有建立新的Activity,而是複用了已經建立的FirstActivity,當點選系統返回按鈕時,程式直接退出。

Activity的啟動模式——singleInstance

  • 當Activity的啟動模式指定為singleInstance,會啟用一個新的返回棧來管理這個Activity。

  • 假設我們的程式中有一個Activity是允許其他程式呼叫的,如果想實現其他程式和我們的程式可以共享這個Activity的例項,就可以使用singleInstance模式。

  • 在這種模式下,會有一個單獨的返回棧來管理這個Activity,不管是哪個應用程式來訪問這個Activity,都共用的同一個返回棧,也就解決了共享Activity例項的問題。

在這裡插入圖片描述

Kotlin課堂

標準函式with、run和apply

with函式接收兩個引數:第一個引數可以是一個任意型別的物件,第二個引數是一個Lambda表示式。with函式會在Lambda表示式中提供第一個引數物件的上下文,並使用Lambda表示式中的最後一行程式碼作為返回值返回。

示例程式碼如下:

val result = with(obj) {
      // 這裡是obj的上下文
      "value" // with函式的返回值
}

run函式的用法和使用場景其實和with函式是非常類似的,只是稍微做了一些語法改動而已。首先run函式是不能直接呼叫的,而是一定要呼叫某個物件的run函式才行;其次run函式只接收一個Lambda引數,並且會在Lambda表示式中提供呼叫物件的上下文。其他方面和with函式是一樣的,包括也會使用Lambda表示式中的最後一行程式碼作為返回值返回。

示例程式碼如下:

val result = obj.run {
      // 這裡是obj的上下文
      "value" // run函式的返回值
}

apply函式和run函式也是極其類似的,都是要在某個物件上呼叫,並且只接收一個Lambda引數,也會在Lambda表示式中提供呼叫物件的上下文,但是apply函式無法指定返回值,而是會自動返回撥用物件本身。

示例程式碼如下:

val result = obj.apply {
      // 這裡是obj的上下文
}
// result == obj

定義靜態方法

Kotlin沒有直接定義靜態方法的關鍵字,但是提供了一些語法特性來支援類似於靜態方法呼叫的寫法,如單例類,companion object等,這些語法特性基本可以滿足我們平時的開發需求了。

然而如果你確確實實需要定義真正的靜態方法, Kotlin仍然提供了兩種實現方式:註解和頂層方法。

@JvmStatic註解

class Util {

    companion object {
        @JvmStatic
        fun doAction() {
            println("do action2")
        }
    }

}

頂層方法

fun doSomething() {
    println("do something")
}

相關文章