Android中活動間通訊總結

不洗碗工作室發表於2018-03-14

作者:不洗碗工作室 - lszr

文章出處:Android中活動間通訊總結

版權歸作者所有,轉載請註明出處

一般傳輸方法

一般來講,在Android中使用intent進行活動間的跳轉,如果要在Activity間進行資料的傳輸,可以使用Intent的putExtra()函式,可以看到,putExtra()函式可以傳遞多種型別的引數

Android中活動間通訊總結

這個函式使用類似雜湊的對應方式,以鍵值對來進行資料的獲取,比如,從Activity1到Activity2傳一個字串可以這樣寫

Intent intent=new Intent(MainActivity.this,TestActivity.class);
intent.putExtra("keyName","testString");
startActivity(intent);
複製程式碼

然後在另一個Activity中呼叫getIntent()方法去接收資料,然後使用getStringExtra方法,傳入鍵值引數,返回對應的資料

Intent intent=getIntent();
String testString=intent.getStringExtra("keyName");
Log.d("lastActivityData",testString);
複製程式碼

log出來以後可以看到接收到了前一個Activity傳過來的資料

Android中活動間通訊總結

或者可以這樣寫,也可以獲得正確的資料

Intent intent=getIntent();
String testString=intent.getExtras().getString("keyName");
Log.d("lastActivityData",testString);
複製程式碼

這種方式和前面的區別就是呼叫了getExtras方法,getExtras方法返回的是Bundle型別的資料,所以需要呼叫getString方法獲得對應的資料,關於getExtras這個方法,後面還會用到

傳遞String型別的資料就可以簡單地這樣呼叫,傳遞其他型別的資料也是這樣的方法,但是在獲取其他型別的資料如int型別的資料的時候,使用getIntExtra方法的時候會有第二個引數defaultValue,這個引數是當沒有從前一個Activity傳遞這個資料或者鍵值對應資料為空的時候返回這個值,而getStringExtra方法已經在內部實現判空的流程。

在《第一行程式碼》中,關於Activity跳轉及其傳遞資料有一種較好的方法,減小了不同的Activity之間的耦合度,就是在Activity1中呼叫Activity2中的靜態方法,直接把需要傳遞的資料作為引數傳遞進去,可以這樣寫:

TestActivity中:

public static void startTestActivity(Context context,String dataString){

    Intent intent =new Intent(context,TestActivity.class);
    intent.putExtra("keyName",dataString);
    context.startActivity(intent);
}
複製程式碼

在前一個Activity中呼叫

TestActivity.startTestActivity(MainActivity.this,"testData");
複製程式碼

這樣的方法和前一個方法的區別在於,在要啟動的Activity中定義要使用的前一個Activity中的資料,以引數的形式傳入對應的資料,這樣做的好處在於在寫兩個Activity間的跳轉時,不需要閱讀第二個Activity的程式碼也可以直接進行跳轉並傳入資料。

以上是普通的傳遞資料的方法,但是在實際開發中,會有各種各樣型別的資料,如果資料的數量比較大的時候,一個一個去傳入引數會很麻煩而且不易於程式碼的閱讀,因此需要用別的方法去傳遞資料。

有一種方法是使用Bundle來傳遞資料,Bundle可以把資料進行類似hash的繫結,以鍵值對的形式來儲存資料到Bundle型別裡面,可以在Intent的putExtra方法中直接傳遞一個Bundle型別的資料,然後在第二個Activity中呼叫getExtras方法獲得對應的Bundle資料,可以這樣寫:

在Activity1中建立Bundle型別資料並且作為引數傳入:

Bundle bundle=new Bundle();
bundle.putString("bundleKeyName","testString");
TestActivity.startTestActivity(MainActivity.this,bundle);
複製程式碼

在Activity2中的啟動Activity靜態方法:

public static void startTestActivity(Context context,Bundle bundle){
    Intent intent =new Intent(context,TestActivity.class);
    intent.putExtra("keyName",bundle);
    context.startActivity(intent);
}
複製程式碼

在Activity2中獲取對應的Bundle型別的資料並列印到日誌上面:

Intent intent=getIntent();
Bundle bundle=intent.getBundleExtra("keyName");
Log.d("lastActivityData",bundle.getString("bundleKeyName"));
複製程式碼

通過日誌來看獲取到了對應的資料,以上就是使用Bundle型別在Activity間進行通訊,以上這種方法呼叫的是Intent類的putBundleExtra方法和getBundleExtra方法,然後呼叫Bundle類的getString方法,也可以使用對應的putExtras方法和getExtras方法,可以省去一個key值,此處就不列出具體程式碼了。

我們可以看到使用Bundle型別的資料,可以有效地減少呼叫跳轉靜態方法的時候的對應的引數個數,只傳一個Bundle型別對應的資料就可以了,但是,首先如果想要知道要傳幾個,傳什麼型別的引數就只能去閱讀第二個Activity的程式碼或者對應的開發人員,會變得比較繁瑣,除此之外,對於Bundle型別的繫結也較為麻煩,和使用Intent直接傳值區別不大。

傳輸物件

那麼,對於資料較多,較為繁瑣的時候,我們要怎麼樣去傳遞對應的資料呢?首先,較多和較為繁瑣的資料一般來講可以建立對應的Model類,使用物件去儲存,那麼現在需要解決的就是怎樣使用Intent去傳遞物件,有以下三個方法:

1、使Model型別實現Serializable介面

我們需要把要傳遞的資料進行整理,建立一個對應的類:

public class PersonModel implements Serializable {
    public String personName;
    public String personId;
    public String personGender;

    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }

    public String getPersonId() {
        return personId;
    }

    public void setPersonId(String personId) {
        this.personId = personId;
    }

    public String getPersonGender() {
        return personGender;
    }

    public void setPersonGender(String personGender) {
        this.personGender = personGender;
    }
}
複製程式碼

如上,建立了應該PersonModel類,包含name,id,gender這三個屬性,而且要實現對應的介面。然後在Activity1中建立對應的PersonModel物件,然後設定其對應的資料,即要傳入的資料,然後呼叫Activity2中對應的靜態方法,傳入PersonModel的物件:

PersonModel mpersonModel =new PersonModel();
mpersonModel.setPersonGender("男");
mpersonModel.setPersonName("lszr");
mpersonModel.setPersonId("123456");
TestActivity.startTestActivity(MainActivity.this,mpersonModel);
複製程式碼

然後,在Activity2中的靜態方法裡面,呼叫Intent的putExtra方法傳入對應的物件:

Intent intent =new Intent(context,TestActivity.class);
intent.putExtra("person",personModel);
context.startActivity(intent);
複製程式碼

檢視對應的方法原始碼,可以看到,是呼叫了putSerializable方法來傳入實現Serializable介面的類的物件

public @NonNull Intent putExtra(String name, Serializable value) {
    if (mExtras == null) {
        mExtras = new Bundle();
    }
    mExtras.putSerializable(name, value);
    return this;
}
複製程式碼

說明Intent類在實現的時候過載了各種引數,因此,對應的也會有getSerializableExtra方法來獲得傳遞的物件,具體實現如下:

Intent intent=getIntent();
PersonModel personModel=new PersonModel();
personModel=(PersonModel)intent.getSerializableExtra("person");
Log.d("lastActivityData",personModel.getPersonGender());
Log.d("lastActivityData",personModel.getPersonId());
Log.d("lastActivityData",personModel.getPersonName());
複製程式碼

可以看到日誌中所列印出來的資料,與預期得到的資料相符,證明這種傳遞物件的方法是可以的

Android中活動間通訊總結

2、使Model類實現Parcelable介面

同樣的需要在Model類中實現這個介面,但是有所不同的是,需要在再實現對應的幾個方法,Model的程式碼如下:

public class PersonModel implements Parcelable {
    public String personName;
    public String personId;
    public String personGender;

    public PersonModel(){

    }


    protected PersonModel(Parcel in) {
        personName = in.readString();
        personId = in.readString();
        personGender = in.readString();
    }

    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }

    public String getPersonId() {
        return personId;
    }

    public void setPersonId(String personId) {
        this.personId = personId;
    }

    public String getPersonGender() {
        return personGender;
    }

    public void setPersonGender(String personGender) {
        this.personGender = personGender;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {

        dest.writeString(personName);
        dest.writeString(personId);
        dest.writeString(personGender);

    }

    public static final Creator<PersonModel> CREATOR = new Creator<PersonModel>() {
        @Override
        public PersonModel createFromParcel(Parcel in) {
            return new PersonModel(in);
        }

        @Override
        public PersonModel[] newArray(int size) {
            return new PersonModel[size];
        }
    };
}
複製程式碼

可以看到,除了正常的get和set方法外,還需要實現對應的describeContents,writeToParcel,createFromParcel,newArray方法,在writeToParcel方法中需要去對對應的資料進行寫入,也就是Parcel型別的writeString等方法,剩下的方法都是對應生成的,不需要改變,這裡還有一點需要注意的是在生成的構造方法中的類成員的賦值的順序需要和writeToParcel方法中Parcel物件的寫入需要把順序進行對應,否則順序會改變,在Activity1中這樣寫:

PersonModel mpersonModel =new PersonModel();
mpersonModel.setPersonGender("男");
mpersonModel.setPersonName("lszr");
mpersonModel.setPersonId("123456");
TestActivity.startTestActivity(MainActivity.this,mpersonModel);
複製程式碼

然後在Activity2,靜態方法中:

Intent intent =new Intent(context,TestActivity.class);
intent.putExtra("person",personModel);
context.startActivity(intent);
複製程式碼

獲取對應的資料:

Intent intent=getIntent();
PersonModel personModel=new PersonModel();
personModel=(PersonModel)intent.getParcelableExtra("person");
Log.d("lastActivityData",personModel.getPersonGender());
Log.d("lastActivityData",personModel.getPersonId());
Log.d("lastActivityData",personModel.getPersonName());
複製程式碼

從網上關於Parcelable和Serializable的效能比較之下,Parcelable的效能和速度是要高於Serializable的,但是實現Parcelable介面寫起來較為繁瑣,如果結合第三方關於Parcelable的庫的話可以大大簡化實現過程,這裡不再贅述。

3、使用Json來傳遞物件

這個方法主要是使用Gson類(需要匯入依賴)的toJson類把物件轉換成對應的Json型別的資料,然後通過Intent進行傳值,程式碼如下:

PersonModel類:

public class PersonModel{
    public String personName;
    public String personId;
    public String personGender;

    public PersonModel(){

    }

    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }

    public String getPersonId() {
        return personId;
    }

    public void setPersonId(String personId) {
        this.personId = personId;
    }

    public String getPersonGender() {
        return personGender;
    }

    public void setPersonGender(String personGender) {
        this.personGender = personGender;
    }
}
複製程式碼

Activity1中:

PersonModel mpersonModel =new PersonModel();
mpersonModel.setPersonGender("男");
mpersonModel.setPersonName("lszr");
mpersonModel.setPersonId("123456");
TestActivity.startTestActivity(MainActivity.this,mpersonModel);
複製程式碼

Activity2中:

靜態方法:

Intent intent =new Intent(context,TestActivity.class);
String jsonData=new Gson().toJson(personModel);
intent.putExtra("keyName",jsonData);
context.startActivity(intent);
複製程式碼

獲取資料:

Intent intent=getIntent();
PersonModel personModel= new Gson().fromJson(intent.getStringExtra("keyName"),PersonModel.class);
Log.d("lastActivityData",personModel.getPersonGender());
Log.d("lastActivityData",personModel.getPersonId());
Log.d("lastActivityData",personModel.getPersonName());
複製程式碼

從程式碼中可以看出,呼叫了Gson類的toJson方法和fromJson方法來進行資料的轉換,這種方法最簡單,但是相較前兩個方法速度和效能都要差一些,關於效能的問題這裡不再贅述。

綜上,這就是基本的關於Android活動間進行資料通訊的幾個方法。

參考:《Android第一行程式碼》

Android中傳遞物件的三種方法

Gson的詳細使用

Android中Intent傳遞物件的3種方式詳解

相關文章