在Activity之間傳送複雜的內容

當App在Activity A顯示為一個列表時,點擊列表的其中一個項目,會再開啟下一個Activity B顯示詳細內容時,這時候資料可能從網路或資料庫抓取,所以這些將顯示的資料可能已經在Activity A已經全部抓取過,在跳轉到Activity B後,如果再抓取一次,這將會是一個很浪費流量和系統資源的動作。

換言之,如果將Activity A抓取過的內容,經由Bundle傳至ActivityB,就可以省去許多網路頻寬,以及系統資源,但Bundle傳輸的資料有限,將多項資料分成多個Key傳輸,Activity B這邊的程式勢必會很雜亂,因此我想到了兩種方法如下:

  1. 使用HashMap同時帶多項資料
    由於Bundle是可以帶Serializable的,而HashMap實作了Serializable,所以我們可以將多項內容整合至HashMap,並將整包一起從Activity A帶至Activity B,以下我們以傳送一個聯絡人資訊為例:

    • Activity A
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
      
          HashMap<String, Object> hashMap = new HashMap<String, Object>();
          hashMap.put("name", "Ken");
          hashMap.put("phone", "0912345678");
          hashMap.put("age", 30);
          hashMap.put("email", "wmken32@gmail.com");
      
          Intent intent = new Intent(this, ActivityB.class);
          Bundle bundle = new Bundle();
          bundle.putSerializable("HashMap", hashMap);
          intent.putExtras(bundle);
          startActivity(intent);
      }
      
    • Activity B
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
      
          HashMap<String, Object> hashMap = null;
          Bundle bundle = getIntent().getExtras();
          if (bundle != null) {
              hashMap = (HashMap<String, Object>) bundle.getSerializable("HashMap");
              String name = (String) hashMap.get("name");
              String phone = (String) hashMap.get("phone");
              int age = (Integer) hashMap.get("age");
              String email = (String) hashMap.get("email");
          }
      }
      

    由此範例我們可以看到,Bundle只需要傳一個物件,就可以將所有資訊傳到Activity B,其內容包含了String和int,當然也支援各種基本型態。

  2. 使用自定義的物件(Object)並實作Parcelable
    學過Java的人都很清楚Java是走物件導向的概念,因此我們可以把上一個範例的聯絡資訊,全部統整到一個物件,但Bundle並不支援非基本型態的物件,可是Bundle有支援到Android自訂的一個介面(Interface)叫Parcelable,因此我們自定義的物件只要實作Parcelable,就可以讓他經由Bundle做傳輸,這個方法比較複雜,但組織性較強,效能也會比Serializable好,我個人比較推薦。

    • Contact.java物件的作法
      由於Parcel沒有任何key可以做索引,所以寫入順序跟取出的順序一定要相同,寫入順序跟取出的順序一定要相同,寫入順序跟取出的順序一定要相同,很重要所以我說三次

      package com.ks.sendbundlefromobject;
      
      import android.os.Parcel;
      import android.os.Parcelable;
      
      public class Contact implements Parcelable {
          private String mName, mPhone, mEmail;
          private int mAge;
      
          public Contact(String name, String phone, int age, String email) {
          	mName = name;
          	mPhone = phone;
          	mAge = age;
          	mEmail = email;
          }
          
          /* 
           * 將Parcel轉換回物件的函式,需注意取出的順序
           */
          public Contact(Parcel parcel) {
          	mName = parcel.readString();
          	mPhone = parcel.readString();
          	mAge = parcel.readInt();
          	mEmail = parcel.readString();
          }
          
          /* 實作Parcelable.Creator以獲取Parcel */
          public static final Parcelable.Creator<Contact> CREATOR = new Creator<Contact>(){
              @Override
              public Contact createFromParcel(Parcel source) {
                  return new Contact(source);
              }
              @Override
              public Contact[] newArray(int size) {
                  return null;
              }
          };
      
          /* 
           * 將Contact物件轉換為Parcel必須覆寫此函式,需注意寫入順序
           */
          @Override
          public void writeToParcel(Parcel dest, int flag) {
              dest.writeString(mName);
              dest.writeString(mPhone);
              dest.writeInt(mAge);
              dest.writeString(mName);
          }
      
          public String getName() {
          	return mName;
          }
      
          public String getPhone() {
          	return mPhone;
          }
          
          public int getAge() {
          	return mAge;
          }
          
          public String getEmail() {
          	return mEmail;
          }
          
          @Override
          public int describeContents() {
              return 0;
          }
      }
      
    • Activity A
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
      
          Contact contact = new Contact("Ken", "0912345678", 30, "wmken32@gmail.com");
      
          Intent intent = new Intent(this, ActivityB.class);
          Bundle bundle = new Bundle();
          bundle.putParcelable("Parcelable", contact);
          intent.putExtras(bundle);
          startActivity(intent);
      }
      
    • Activity B
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
      
          Bundle bundle = getIntent().getExtras();
          if (bundle != null) {
              Contact contact = bundle.getParcelable("Parcelable");
              String name = contact.getName();
              String phone = contact.getPhone();
              int age = contact.getAge();
              String email = contact.getEmail();
          }
      }
      

    從這個範例可以發現,功大多做在物件裡,兩端的Activity的寫法相當的簡潔,Activity B這邊取得到的是一個組織較完整的物件,取用也較方便,當然這邊的範例都比較簡單,如果用在藏有非常多資料的物件上時,這個方法是非常受用的。

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s