Android – 啟動另一個Activity

Activity適用來處理使用者介面的相關互動, 往往會有一個以上的畫面呈現, 此時建議採用一個Activity來呼應特定的版面配置, 較為理想, 也較能提供整個專案開發的維護性. 因此, 如何從一個Activity跳到另一個Activity的運作, 就是非常重要的一件事.

實作的基本方式, 就是透過Intent的物件實體來進行.

針對此一議題, 建立一個新的專案, 先處理app -> res -> layout -> activity_main.xml, 編輯如下:

<?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"
    >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="首頁"
        android:textSize="24sp"
        android:gravity="center"
        />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="下一頁"
        android:onClick="gotoPage2"
        />

</LinearLayout>

回到 MainActivity:

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

    public void gotoPage2(View view){
        
    }
}

就先告一段落.

再來新建一個 Page2Activity, 先處理版面activity_page2.xml:

<?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"
    >
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="第二頁"
        android:textSize="24sp"
        android:gravity="center"
        />

</LinearLayout>

再度回到MainActivity.java中, 開始處理跳到第二頁的相關程序, 只需要處理gotoPage2()方法即可, 如下:

public void gotoPage2(View view){
    Intent intent = new Intent(this, Page2Activity.class);
    startActivity(intent);
}

重點如下:

  • 建立Intent物件, 第一個參數為目前的Activtiy物件, 第二個參數為要跳轉的類別.
  • 呼叫startActivity()方法, 傳遞設定好的Intent物件實體.

當使用者觸發之後, 就馬上運行Page2Activity的生命週期, 而原本的MainActivity的生命週期也將同步逐一執行onPause()以及onStop().

而當從Page2Activity按下Back之後, 就會再度回到MainActivity, 此時Page2Activity已經進入執行到onDestroy(), 而MainActivity則從剛剛的onStop()進入到onRestart(), onStart()以及onResume(), 使用者所看的的畫面再度回到MainActivity, 唯一的呈現舞台就再度切回來了.

 

傳遞資料


在上一個單元已經學習到切換Activity的方式, 但是在實際的應用過程中, 往往會從原先的Activityt傳遞資料到另一個Activity中處理及運用, 此時將要探討的是如何傳遞資料. 延續使用上一個單元的專案範例繼續練習即可.

因為切換的動作是透過關鍵的Intent物件實體, 也因此資料的傳遞也將藉由Intent物件實體進行.

先來檢視一下上一個單元的gotoPage2()方法:

public void gotoPage2(View view){
    Intent intent = new Intent(this, Page2Activity.class);
    startActivity(intent);
}

現在, 打算傳遞以下三個資料內容:

  • 使用者名稱為Brad: username: “Brad”,
  • 遊戲目前關卡為第四關: stage : 4,
  • 背景音樂開啟: sound: true

因此, 透過呼叫Intent物件實體的putExtra(自訂名稱字串, 設定值), 增加以下敘述句:

public void gotoPage2(View view){
    Intent intent = new Intent(this, Page2Activity.class);
    intent.putExtra("username", "Brad");
    intent.putExtra("stage", 4);
    intent.putExtra("sound", true);
    startActivity(intent);
}

如此就完成了在MainActivity中的處理事項, 接下來處理Page2Activity如何接收傳遞的資料.

在Page2Activity中, 透過呼叫getIntent()方法, 先取得外部傳遞的Intent物件實體, 就可以從該Intent物件實體取得傳遞的資料. 而getIntent()方法是所有Context物件都具有的方法, Activity 也是Context物件實體(Activity is-a Context).

之後, 呼叫Intent物件實體的getXxxExtra()來取得傳遞資料, Xxx表示資料的型別. 如下:

Intent intent = getIntent();
String username = intent.getStringExtra("username");
int stage = intent.getIntExtra("stage", 0);
boolean sound = intent.getBooleanExtra("sound", false);

Log.d("DEBUG", "Username: " + username);
Log.d("DEBUG", "Stage: " + stage);
Log.d("DEBUG", "Sound: " + (sound?"On":"Off"));

重點如下:

  • Intent物件實體並非new出來的, 而是被傳遞進來的, 所以是透過getIntent()來取得的.
  • 字串型別資料, 直接呼叫getStringExtra(自訂名稱字串), 如果指定了不存在的自訂名稱字串, 則將傳回null.
  • 而基本資料型別的資料, 例如int, 則是getIntExtra(自訂名稱字串, 預設值), 如果指定了不存在的自訂名稱字串, 則將傳回指定的預設值.

 

回傳結果


如果再傳遞過去的Activiy返回結束後, 想要將其處理的狀況回報給原先的Activity, 則處理模式會略有些許不同.

仍然以上一個單元的專案範例進行說明.

在MainActivity.java中, 啟動的方法將從原本的startActivity(), 改為呼叫:

public void gotoPage2(View view){
    Intent intent = new Intent(this, Page2Activity.class);
    intent.putExtra("username", "Brad");
    intent.putExtra("stage", 4);
    intent.putExtra("sound", true);
    startActivityForResult(intent, 123);
}

其中傳遞給startActivityForResult()的第二參數為int型別的requestCode資料, 用來辨識再其回呼回來之後, 知道是哪個請求被回覆回來使用的, 是由開發這自行定義的int數值資料.

並且另外撰寫一個Override方法 onActivityResult(), 此方法將會在另一個Activity結束之後, 被觸發呼叫, 用來處理接收回傳結果使用, 而其結果狀態值為第二個參數resultCode, 回傳資料放在第三個參數資料Intent物件實體中:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
}

再來處理Page2Activity.java.

在結束Page2Activity生命週期之前, 呼叫setResult(int resultCode), 則將該狀態值傳回原先的MainActivity的onActivityResult()的第二個參數處理. 其值將由開發者自行制定, 通常只想表示正常結束, 就回傳RESULT_OK即可, 常用的值如下:

  • RESULT_OK
  • RESULT_CANCELED

但是千萬別被此兩個值給限定, 開發者可以制定特定的傳回結果值.

而想要傳遞更多的參數, 則將透過Intent物件實體的設定, 再以setResult(int resultCode, Intent intent)的第二個參數來進行傳遞, 如下:

Intent intent2 = new Intent();
intent2.putExtra("data", 123);
intent2.putExtra("isPass", true);
setResult(RESULT_OK, intent2);

此時就完成Page2Activity的處理部分. 回到MainActivity中, 就可以順利地處理三個參數:

  1. int requestCode
  2. int resultCode
  3. Intent intent

進而達到回傳資料的目的了.

 

自訂Application


在以上的學習單元上, 都是以個別的Activity與其他的Activity來產生之間的資料傳遞. 但是, 有些時候是以整個專案運作為考量, 會存在部分變數是在整個專案運作中持續的存在及異動, 此時將可以利用自訂Application來進行相關的操作處理.

此一觀念先從AndroidManifest.xml來看, 一個application就是一整個專案的主要項目, 而在其下才包含了一或是多個Activity, Service的不同元件.

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

    <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>

因此, 就從開發一個自訂的Application來下手處理. 在app -> java -> <Package Name> 下新增一個Java Class,

在之後出現的對話框中輸入自訂類別名稱, 以下為MyApp, 並指定android.app.Application為super class.

假設有三個資料項目, String(username), int(stage)及boolean(sound), 將會貫穿整的app的存取使用, 因此將此三個屬性資料項目定義在MyApp類別中, 並開發撰寫getter與setter.

如下編寫以下程式碼:

import android.app.Application;

public class MyApp extends Application {
    private String username;
    private int stage;
    private boolean sound;

    @Override
    public void onCreate() {
        super.onCreate();

        username = "guest";
        stage = 0;
        sound = true;
    }

    public String getUsername() {
        return username;
    }

    public int getStage() {
        return stage;
    }

    public boolean isSound() {
        return sound;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setStage(int stage) {
        this.stage = stage;
    }

    public void setSound(boolean sound) {
        this.sound = sound;
    }
}

在需要存取使用的MainActivity中, 先呼叫getApplication()方法取的Applcation的物件實體, 並將其強制轉型為MyApp, 就可以直接使用getter與setter了.

MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    private MyApp myApp;

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

        myApp = (MyApp)getApplication();

        // 取用 myApp 的屬性資料
        String username = myApp.getUsername();
        int stage = myApp.getStage();
        boolean sound = myApp.isSound();

        // 變更 myApp 的屬性資料
        myApp.setSound(false);
        myApp.setStage(4);
        myApp.setUsername("Brad");

    }
}

如此一來, 就可以輕鬆地在整個專案之間處理共同的屬性變數.

 

 

 

 

本站資源一切隨緣,
不用註冊, 不看廣告
如果對您有所助益,
歡迎功德隨喜, 金額隨意,
請點擊以下...(感謝您)

功德箱/打賞箱

%d bloggers like this: