Intent之複雜資料的傳遞
本節引言:
上一節中我們學習了Intent的一些基本使用,知道了Intent的七個屬性,顯式Intent以及 隱式Intent,以及如何自訂隱式Intent,最後也提供了一些常用的系統Intent給大家! 而本節跟大家講解的是Intent傳遞資料的問題~好的,開始本節內容~
1.Intent傳遞簡單資料
還記得我們在Activity那裡學過如何在兩個Activity中互相傳遞簡單資料的方法嗎?
就是可以直接透過呼叫Intent的putExtra()方法存入數據,然後在取得Intent後呼叫getXxxExtra來獲得 對應類型的資料;傳遞多個的話,可以使用Bundle物件作為容器,透過呼叫Bundle的putXxx先將數據 儲存到Bundle中,然後呼叫Intent的putExtras()方法將Bundle存入Intent中,然後得到Intent以後, 呼叫getExtras()取得Bundle容器,然後呼叫其getXXX來取得對應的資料! 另外資料儲存有點類似Map的<鍵,值>!
2.Intent傳遞陣列
嘿嘿,普通型別倒沒問題,但是如果是陣列咧嘴?解決方法如下:
寫入陣列:
//可把StringArray換成其他資料型別,例如int,float等等...
讀取陣列:
3.Intent傳遞集合
嗯,陣列很簡單吧,那我們再來傳下集合~這個就稍微複雜點了,分情況處理:
#1)List<基本資料型別或String>
寫入集合:
intent.putIntegerArrayListExtra(name, value)
讀取集合:
intent.getIntegerArrayListExtra(name)
##2)List< Object>
將list強轉成Serializable類型,然後傳入(可用Bundle做媒介)
#寫入集合:
##putExtras(key, ( Serializable)list)(List<Object>) getIntent().getSerializable(key)
PS:Object類別需要實作Serializable介面
3)Map<String, Object>,或更複雜的
解決方法是:外層套個List
Map<String, Object> map1 = new HashMap<String, Object>();
# map1.put("key1", "value1");
map1.put("key2", "value2");
List<Map<String, Object>> list =1new , Object>>();
list.add(map1);
Intent intent = new Intent();
#intent.setClass(MainActivity.this,ComActivity.class);#Com遠.class);# #Bundle bundle = new Bundle();
//必須定義一個list用於在budnle中傳遞需要傳遞的ArrayList<Object>,這個是必須要的
ArrayList bundlelist ;
bundlelist.add(list);
bundle.putParcelableArrayList("list",bundlelist);
#intent.putExtras(bundle);
##4.Intent傳遞物件
1)將物件轉換為Json字串
Gson解析的範例:Model:
public class Author{ private int id; private String name;
//...//...
}
寫入數據:
Book book=new Book();
author.setId(1);author. setName("Bruce Eckel");book.setAuthor(author);
Intent intent=new Intent(this,SecondActivity.class);#
讀取資料:
Book book=new Gson().fromJson(bookJson ,Book.class);
Log.d(TAG,"書名->"+book.getTitle());
Log.d(TAG,"書名->"+book. getAuthor() .getName());
2)使用Serializable,Parcelable序列化物件
1.Serializable實作:
①業務Bean實作:Serializable介面,寫上getter和setter方法
②Intent透過呼叫putExtra(String name, Serializable value)傳入物件實例 當然物件有多個的話多個的話,我們也可以先Bundle.putSerializable(x,x);
③新Activity呼叫getSerializableExtra()方法取得物件實例: eg:Product pd = (Product) getIntent().getSerializableExtra("Product");
④呼叫物件get方法取得對應參數
#2.Parcelable實作:
一般流程:
①業務Bean繼承Parcelable介面,重寫writeToParcel方法,將你的物件序列化為一個Parcel物件;
②重寫describeContents方法,內容介面描述,預設回傳0就可以
③實例化靜態內部物件CREATOR實作介面Parcelable.Creator
④同樣式透過Intent的putExtra()方法傳入物件實例,當然多個對象的話,我們可以先 放到Bundle裡Bundle.putParcelable(x,x),再Intent.putExtras()即可
一些解釋:
透過writeToParcel將你的對象映射成Parcel對象,再透過createFromParcel將Parcel對象映射 成你的對象。也可以將Parcel看成是一個流,透過writeToParcel把物件寫到流裡面, 在透過createFromParcel從流裡讀取對象,只不過這個過程需要你來實現,因此寫的 順序和讀的順序必須一致。
實作Parcelable介面的程式碼範例:
@Override
public int describeContents(){
return 0;
}
#
##
@Override
public void writeToParcel
parcel.writeString(作者);
parcel.writeInt(publishTime);
}
public static final Parcelable.Creator
@Override
public Book[] newArray()
}
@Override
public Book Book();
mBook.bookName = source.readString();
mBook.author = source.readString();
mBook.publishTime = source.readInt();
則返回mBook;
}
};
Android Studio產生Parcleable外掛:
Intellij/Andriod Studio外掛程式android-parcelable-intellij-plugin 只要ALT+Insert,即可直接產生Parcleable介面程式碼。
另外:Android中大量用到Parcelable對象,實作Parcable接口又是非常繁瑣的,可以用到 第三方的開源框架:Parceler,因為Maven的問題,暫時還沒試。
#3.兩種序列化方式的比較:
#兩者的比較:
- 1)在使用記憶體的時候,Parcelable比Serializable效能高,所以建議使用Parcelable。
- 2)Serializable在序列化的時候會產生大量的臨時變量,從而引起頻繁的GC。
- 3)Parcelable不能使用在要將資料儲存在磁碟上的情況,因為Parcelable不能很好的保證資料的 持續性在外界有變化的情況下。儘管Serializable效率低點,但此時還是建議使用Serializable。
5.Intent傳遞Bitmap
bitmap預設實作Parcelable介面,直接傳遞即可
##實作程式碼:
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap"#); #intent.putExtra("bundle", bundle);
6.傳來傳去不方便,直接定義全域資料
如果是傳遞簡單的數據,有這樣的需求,Activity1 -> Activity2 -> Activity3 - > Activity4, 你想在Activity中傳遞某個資料到Activity4中,怎麼破,一個個頁面傳麼?
顯然不科學是吧,如果你想某個資料可以在任何地方都能取得到,你就可以考慮使用Application全域物件了!
Android系統在每個程式運行的時候創建一個Application對象,而且只會創建一個,所以Application 是單例(singleton)模式的一個類,而Application物件的生命週期是整個程式中最長的,他的生命 週期等於這個程式的生命週期。如果想儲存一些比靜態的值(固定不改變的,也可以變),如果你想使用 Application就需要自訂類別實作Application類,並且告訴系統實例化的是我們自訂的Application 而非系統預設的,而這一步,就是在AndroidManifest.xml中衛我們的application標籤添加:name屬性!
關鍵部分程式碼:
1)自訂Application類別:
private String myState;
public String getState(){
return myState = s;
}
}
<application android:name=".MyApp" android:icon ="@drawable/icon"
android:label="@string/app_name">class Blah extends Activity {
# @OverrideString state = appState.getState();
...
}
}
高逼格寫法
:在任何位置都能取得到Application全域物件。Applicaiton是系統的一個元件,他也有自己的一個生命週期,我們可以在onCraete裡得到這個 Application物件。貼下修改後的程式碼吧!
# private String myState;
private static MyApp return instance;
}
public String getState(){
myState = s;
}
@Override
public void onCreate(){
onCreate ##}
然後在任意地方我們就可以直接呼叫:MyApp.getInstance()來取得Application的全域物件!
注意事項:
Application物件是存在於記憶體中的,也就有它可能會被系統殺死,例如這樣的場景:
我們在Activity1中往application中儲存了使用者帳號,然後在Activity2中取得到使用者帳號,並且顯示!
如果我們點擊home鍵,然後過了N久候,系統為了回收記憶體kill掉了我們的app。這個時候,我們重新 打開這個app,這個時候很神奇的,回到了Activity2的頁面,但是如果這個時候你再去獲取Application 裡的用戶帳號,程式就會報NullPointerException,然後crash掉~
之所以會發生上述crash,是因為這個Application物件是全新創建的,可能你以為App是重新啟動的, 其實並不是,只是創建一個新的Application,然後啟動上次用戶離開時的Activity,從而創造App 並沒有被殺死的假象!所以如果是比較重要的數據的話,建議你還是在進行在地化,另外在使用數據的時候 要對變數的值進行非空檢查!還有一點就是:不只Application變數會這樣,單例物件以及公共靜態變數 也會這樣~
7.單例模式傳參
上面的Application就是基於單例的,單例模式的特點就是可以保證系統中一個類別有且只有一個實例。 這樣很容易就能實現,在A中設定參數,在B中直接存取了。這是幾種方法中效率最高的。
範例程式碼:(程式碼來自於網路~)
#①定義一個單例類別:
{
//單例模式實例
private static Xcl ronized 用於執行緒安全,防止多執行緒同時建立實例
public synchronized static XclSingleton getInstance(){
XclSingleton();
}
return #
final HashMap<String, Object> mMap;
private Xcl因 HashMap<String,Object>();
}
public void put(String key,Object value){
# mMap.put(key,value);
} {
return mMap.get (key);
}
}
②設定參數:
#XclSingleton.get#②設定參數:
#本節小結:
好的,關於Intent複雜資料傳輸就到這裡,本節除了講述使用Intent來傳遞複雜資料外,還教了大家 使用Application和單例模式來傳遞參數!相信會對大家在資料傳遞上帶來方便,謝謝~