W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
上一節(jié)中我們學(xué)習(xí)了Intent的一些基本使用,知道了Intent的七個屬性,顯式Intent以及 隱式Intent,以及如何自定義隱式Intent,最后還給大家提供了一些常用的系統(tǒng)Intent! 而本節(jié)跟大家講解的是Intent傳遞數(shù)據(jù)的問題~好的,開始本節(jié)內(nèi)容~
還記得我們在Activity那里學(xué)過如何在兩個Activity中互相傳遞簡單數(shù)據(jù)的方法嗎?
就是可以直接通過調(diào)用Intent的putExtra()方法存入數(shù)據(jù),然后在獲得Intent后調(diào)用getXxxExtra獲得 對應(yīng)類型的數(shù)據(jù);傳遞多個的話,可以使用Bundle對象作為容器,通過調(diào)用Bundle的putXxx先將數(shù)據(jù) 存儲到Bundle中,然后調(diào)用Intent的putExtras()方法將Bundle存入Intent中,然后獲得Intent以后, 調(diào)用getExtras()獲得Bundle容器,然后調(diào)用其getXXX獲取對應(yīng)的數(shù)據(jù)! 另外數(shù)據(jù)存儲有點(diǎn)類似于Map的!
嘿嘿,普通類型倒沒問題,但是如果是數(shù)組咧?解決方法如下:
寫入數(shù)組:
bd.putStringArray("StringArray", new String[]{"呵呵","哈哈"});
//可把StringArray換成其他數(shù)據(jù)類型,比如int,float等等...
讀取數(shù)組:
String[] str = bd.getStringArray("StringArray")
嗯,數(shù)組很簡單吧,那我們再來傳下集合~這個就稍微復(fù)雜點(diǎn)了,分情況處理:
寫入集合:
intent.putStringArrayListExtra(name, value)
intent.putIntegerArrayListExtra(name, value)
讀取集合:
intent.getStringArrayListExtra(name)
intent.getIntegerArrayListExtra(name)
將list強(qiáng)轉(zhuǎn)成Serializable類型,然后傳入(可用Bundle做媒介)
寫入集合:
putExtras(key, (Serializable)list)
讀取集合:
(List<Object>) getIntent().getSerializable(key)
PS:Object類需要實(shí)現(xiàn)Serializable接口
解決方法是:外層套個List
//傳遞復(fù)雜些的參數(shù)
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("key1", "value1");
map1.put("key2", "value2");
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
list.add(map1);
Intent intent = new Intent();
intent.setClass(MainActivity.this,ComplexActivity.class);
Bundle bundle = new Bundle();
//須定義一個list用于在budnle中傳遞需要傳遞的ArrayList<Object>,這個是必須要的
ArrayList bundlelist = new ArrayList();
bundlelist.add(list);
bundle.putParcelableArrayList("list",bundlelist);
intent.putExtras(bundle);
startActivity(intent);
傳遞對象的方式有兩種:將對象轉(zhuǎn)換為Json字符串或者通過Serializable,Parcelable序列化 不建議使用Android內(nèi)置的摳腳Json解析器,可使用fastjson或者Gson第三方庫!
Gson解析的例子:
Model:
public class Author{
private int id;
private String name;
//...
}
public class Author{
private int id;
private String name;
//...
}
寫入數(shù)據(jù):
Book book=new Book();
book.setTitle("Java編程思想");
Author author=new Author();
author.setId(1);
author.setName("Bruce Eckel");
book.setAuthor(author);
Intent intent=new Intent(this,SecondActivity.class);
intent.putExtra("book",new Gson().toJson(book));
startActivity(intent);
讀取數(shù)據(jù):
String bookJson=getIntent().getStringExtra("book");
Book book=new Gson().fromJson(bookJson,Book.class);
Log.d(TAG,"book title->"+book.getTitle());
Log.d(TAG,"book author name->"+book.getAuthor().getName());
1.Serializable實(shí)現(xiàn):
①業(yè)務(wù)Bean實(shí)現(xiàn):Serializable接口,寫上getter和setter方法
②Intent通過調(diào)用putExtra(String name, Serializable value)傳入對象實(shí)例 當(dāng)然對象有多個的話多個的話,我們也可以先Bundle.putSerializable(x,x);
③新Activity調(diào)用getSerializableExtra()方法獲得對象實(shí)例: eg:Product pd = (Product) getIntent().getSerializableExtra("Product");
④調(diào)用對象get方法獲得相應(yīng)參數(shù)
2.Parcelable實(shí)現(xiàn):
一般流程:
①業(yè)務(wù)Bean繼承Parcelable接口,重寫writeToParcel方法,將你的對象序列化為一個Parcel對象;
②重寫describeContents方法,內(nèi)容接口描述,默認(rèn)返回0就可以
③實(shí)例化靜態(tài)內(nèi)部對象CREATOR實(shí)現(xiàn)接口Parcelable.Creator
④同樣式通過Intent的putExtra()方法傳入對象實(shí)例,當(dāng)然多個對象的話,我們可以先 放到Bundle里Bundle.putParcelable(x,x),再Intent.putExtras()即可
一些解釋:
通過writeToParcel將你的對象映射成Parcel對象,再通過createFromParcel將Parcel對象映射 成你的對象。也可以將Parcel看成是一個流,通過writeToParcel把對象寫到流里面, 在通過createFromParcel從流里讀取對象,只不過這個過程需要你來實(shí)現(xiàn),因此寫的 順序和讀的順序必須一致。
實(shí)現(xiàn)Parcelable接口的代碼示例:
//Internal Description Interface,You do not need to manage
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags){
parcel.writeString(bookName);
parcel.writeString(author);
parcel.writeInt(publishTime);
}
public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book[] newArray(int size) {
return new Book[size];
}
@Override
public Book createFromParcel(Parcel source) {
Book mBook = new Book();
mBook.bookName = source.readString();
mBook.author = source.readString();
mBook.publishTime = source.readInt();
return mBook;
}
};
Android Studio生成Parcleable插件:
Intellij/Andriod Studio插件android-parcelable-intellij-plugin 只要ALT+Insert,即可直接生成Parcleable接口代碼。
另外:Android中大量用到Parcelable對象,實(shí)現(xiàn)Parcable接口又是非常繁瑣的,可以用到 第三方的開源框架:Parceler,因為Maven的問題,暫時還沒試。
3.兩種序列化方式的比較:
兩者的比較:
3)Parcelable不能使用在要將數(shù)據(jù)存儲在磁盤上的情況,因為Parcelable不能很好的保證數(shù)據(jù)的 持續(xù)性在外界有變化的情況下。盡管Serializable效率低點(diǎn),但此時還是建議使用Serializable。
bitmap默認(rèn)實(shí)現(xiàn)Parcelable接口,直接傳遞即可
實(shí)現(xiàn)代碼:
Bitmap bitmap = null;
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap", bitmap);
intent.putExtra("bundle", bundle);
如果是傳遞簡單的數(shù)據(jù),有這樣的需求,Activity1 -> Activity2 -> Activity3 -> Activity4, 你想在Activity中傳遞某個數(shù)據(jù)到Activity4中,怎么破,一個個頁面?zhèn)髅矗?/p>
顯然不科學(xué)是吧,如果你想某個數(shù)據(jù)可以在任何地方都能獲取到,你就可以考慮使用 Application全局對象了!
Android系統(tǒng)在每個程序運(yùn)行的時候創(chuàng)建一個Application對象,而且只會創(chuàng)建一個,所以Application 是單例(singleton)模式的一個類,而且Application對象的生命周期是整個程序中最長的,他的生命 周期等于這個程序的生命周期。如果想存儲一些比靜態(tài)的值(固定不改變的,也可以變),如果你想使用 Application就需要自定義類實(shí)現(xiàn)Application類,并且告訴系統(tǒng)實(shí)例化的是我們自定義的Application 而非系統(tǒng)默認(rèn)的,而這一步,就是在AndroidManifest.xml中衛(wèi)我們的application標(biāo)簽添加:name屬性!
關(guān)鍵部分代碼:
1)自定義Application類:
class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
2)AndroidManifest.xml中聲明:
<application android:name=".MyApp" android:icon="@drawable/icon"
android:label="@string/app_name">
3)在需要的地方調(diào)用:
class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
高逼格寫法
:在任何位置都能獲取到Application全局對象。
Applicaiton是系統(tǒng)的一個組件,他也有自己的一個生命周期,我們可以在onCraete里獲得這個 Application對象。貼下修改后的代碼吧!
class MyApp extends Application {
private String myState;
private static MyApp instance;
public static MyApp getInstance(){
return instance;
}
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
@Override
public void onCreate(){
onCreate();
instance = this;
}
}
然后在任意地方我們就可以直接調(diào)用:MyApp.getInstance()來獲得Application的全局對象!
注意事項:
Application對象是存在于內(nèi)存中的,也就有它可能會被系統(tǒng)殺死,比如這樣的場景:
我們在Activity1中往application中存儲了用戶賬號,然后在Activity2中獲取到用戶賬號,并且顯示!
如果我們點(diǎn)擊home鍵,然后過了N久候,系統(tǒng)為了回收內(nèi)存kill掉了我們的app。這個時候,我們重新 打開這個app,這個時候很神奇的,回到了Activity2的頁面,但是如果這個時候你再去獲取Application 里的用戶賬號,程序就會報NullPointerException,然后crash掉~
之所以會發(fā)生上述crash,是因為這個Application對象是全新創(chuàng)建的,可能你以為App是重新啟動的, 其實(shí)并不是,僅僅是創(chuàng)建一個新的Application,然后啟動上次用戶離開時的Activity,從而創(chuàng)造App 并沒有被殺死的假象!所以如果是比較重要的數(shù)據(jù)的話,建議你還是進(jìn)行本地化,另外在使用數(shù)據(jù)的時候 要對變量的值進(jìn)行非空檢查!還有一點(diǎn)就是:不止是Application變量會這樣,單例對象以及公共靜態(tài)變量 也會這樣~
上面的Application就是基于單例的,單例模式的特點(diǎn)就是可以保證系統(tǒng)中一個類有且只有一個實(shí)例。 這樣很容易就能實(shí)現(xiàn),在A中設(shè)置參數(shù),在B中直接訪問了。這是幾種方法中效率最高的。
范例代碼:(代碼來自于網(wǎng)上~)
①定義一個單例類:
public class XclSingleton
{
//單例模式實(shí)例
private static XclSingleton instance = null;
//synchronized 用于線程安全,防止多線程同時創(chuàng)建實(shí)例
public synchronized static XclSingleton getInstance(){
if(instance == null){
instance = new XclSingleton();
}
return instance;
}
final HashMap<String, Object> mMap;
private XclSingleton()
{
mMap = new HashMap<String,Object>();
}
public void put(String key,Object value){
mMap.put(key,value);
}
public Object get(String key)
{
return mMap.get(key);
}
}
②設(shè)置參數(shù):
XclSingleton.getInstance().put("key1", "value1");
XclSingleton.getInstance().put("key2", "value2");
好的,關(guān)于Intent復(fù)雜數(shù)據(jù)傳輸就到這里,本節(jié)除了講述使用Intent來傳遞復(fù)雜數(shù)據(jù)外,還教了大家 使用Application和單例模式來傳遞參數(shù)!相信會對大家在數(shù)據(jù)傳遞方面帶來方便,謝謝~
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: