iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 7
1

Activity 除了可以跟使用者互動以外,也可以跟其他的 Activity 互動。我們今天就來介紹一下 Activity 之間如何呼叫。

AndroidManifest.xml

還記得我們在 Hello world 之專案結構 的時候,有特別提到 AndroidManifest.xml 會是一個很重要的檔案嗎?我們打開後會看到以下的 xml 結構。

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

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

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

</manifest>

裡面包含著很多關於 app 的重要資訊,包含 package name、app icon、app name 等。

AndroidManifest.xml 也支援按著 ⌘ 點擊可以跳到目標檔案,無論是 @mipmap/ic_launcher@string/app_name@style/AppTheme 或是 .MainActivity 大家都可以試試看。

除此之外我們也發現我們的 Activity 也被記錄在這個檔案裡。我們單獨來看這個區塊:

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

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
  • android:name:
    透過 name 連結到我們專案的實際 Activity,由 . 開頭的名稱其實是省略了 package name 後的縮寫。完整的路徑就是 com.example.myapplication.MainActivity 也就是我們專案目前唯一的 Activity
  • intent-filter:
    intent-filter 是我們跟系統註明我們的 Activity 可以接收哪些 Intent 的一種方式。
    這裡我們有二個參數 <action android:name="android.intent.action.MAIN" /> 指的是這是我們主要進入點,而 <category android:name="android.intent.category.LAUNCHER" /> 代表我們這個 app 會出現在 LAUNCHER 列表裡。

Intent

Intent 是 Android 的一個 class,用來啟動 ActivityService 等的 components。作為一個一般化的介面,提供了諸如 setActionsetTypesetClass 等參數的設定來表示呼叫 component 的種類,系統會依據我們所附帶參數來匹配適合的對象。依據你提供的參數匹配的對象可能不只一個或是根本沒有結果,而如果有多個 Activity 可以接收這個 Intent 則會跳出一個列表讓使用者自行選擇。
使用方式如下:

val intent = Intent(this, AnotherActivity::class.java)
startActivity(intent)

我們這邊是直接指定接收的 class,所以只有 AnotherActivity 可以接收,這種方式叫做 explicit intent。由於我們必須拿的到對方 class 的 reference,基本上這種呼叫要在同個 app 內才能使用。

但 Android 也支援(並且鼓勵)跨 app 間 Activity 的合作,我們並不確定具體有哪些 Activity 會接收到我們的 Intent ,但其實我們也只關心所要完成的任務是否有被良好的解決。

舉例來說如果我們 app 有個功能希望可以把一段文字分享出去,我們並不清楚使用者手機上有多少種可以分享訊息的 app,但我們還是可以使用標準的方式把 Intent 拋出來讓使用者選擇他們想要用什麼方式做分享。以下就是分享文字的範例:

val sendIntent = Intent(ACTION_SEND)
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
val shareIntent = Intent.createChooser(sendIntent, null)
startActivity(shareIntent)

Example

原理介紹完了,我們一起把 helloworld 改成二個 Activity 吧,首先建立一個新的 SecondActivity 在我們的 com.example.myapplication 目錄下。

可以在 package 上按右鍵會有清單可以選,New -> Kotlin File/Class 然後輸入 file name 即可。

你也可以使用內建的 template New -> Activity 會有一系列可以使用的範例,如果很常重複這個動作的話也可以建立你自己的 template。

檔案內容如下:

package com.example.myapplication

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity


class SecondActivity : AppCompatActivity() {

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

還有二個地方要修改,一個是我們並沒有 activity_second 這個 layout,ㄧ樣可以在 layout 這個 folder 按右鍵選,New -> Layout resource file,輸入 file name 跟 Root element(有自動完成)即可,加上一個 TextView 設定不同的內容來識別:

<?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=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="It's second page"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

我們也必須把 SecondActivity 加到 AndroidManifest.xmlapplication tag 裡,系統才知道我們有一個新的 Activity 可以使用,修改內容如下:

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

最後回到 MainActivityOnClickListeneronClick 裡加上呼叫 SecondActivity 的 code 如下:

myTextView.setOnClickListener {
    startActivity(Intent(this, SecondActivity::class.java))
}

這樣就大功告成囉,記得跑在手機或模擬器試試看,如果大家有遇到什麼問題也歡迎留言囉,明天見。


上一篇
[Android 十全大補] User Interaction
下一篇
[Android 十全大補] ConstraintLayout
系列文
Android 十全大補30

尚未有邦友留言

立即登入留言