原文地址:https://www.jianshu.com/p/1169dba99261
intent傳遞數據
為什么要和intent單獨拿出來講,因為Intent傳遞數據也是非常重要的
一、簡單的傳遞數據

二、傳遞數組
bd.putStringArray("StringArray", new String[]{"呵呵","哈哈"}); //可把StringArray換成其他數據類型,比如int,float等等..
讀取數組:
String[] str = bd.getStringArray("StringArray")
三、傳遞集合
1)List<基本數據類型或String>
intent.putStringArrayListExtra(name, value)
intent.putIntegerArrayListExtra(name, value)
讀取集合:
intent.getStringArrayListExtra(name)
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 = 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);
四、Intent傳遞對象
傳遞對象的方式有兩種:將對象轉換為Json字符串或者通過Serializable,Parcelable序列化 不建議使用Android內置的摳腳Json解析器,可使用fastjson或者Gson第三方庫!
1)將對象轉換為Json字符串
Gson解析的例子:
Model:
public class Book{ private int id; private String title; //... } public class Author{ private int id; private String name; //... }
寫入數據:
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);
讀取數據:
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());
2)使用Serializable,Parcelable序列化對象
但是不知道你有沒有發現,putExtra()方法中所支持的數據類型是有限的,雖然常用的一些數據類型它都會支持,但是當你想去傳遞一些自定義對象的時候就會發現無從下手。不用擔心,下面我們就學習一下使用Intent 來傳遞對象的技巧。
方式一:Serializable 方式
Serializable 是序列化的意思,表示將一個對象轉換成可存儲或可傳輸的狀態。序列化后的對象可以在網絡上進行傳輸,也可以存儲到本地。至於序列化的方法也很簡單,只需要讓一個類去實現Serializable 這個接口就可以了。
比如說有一個Person 類,其中包含了name 和age 這兩個字段,想要將它序列化就可以這樣寫:
public class Person implements Serializable{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
其中get、set 方法都是用於賦值和讀取字段數據的,最重要的部分是在第一行。這里讓Person 類去實現了Serializable 接口,這樣所有的Person 對象就都是可序列化的了。
接下來在FirstActivity 中的寫法非常簡單:
Person person = new Person(); person.setName("Tom"); person.setAge(20); Intent intent = new Intent(FirstActivity.this, SecondActivity.class); intent.putExtra("person_data", person); startActivity(intent);
可以看到,這里我們創建了一個Person 的實例,然后就直接將它傳入到putExtra()方法中了。由於Person 類實現了Serializable 接口,所以才可以這樣寫。
接下來在SecondActivity 中獲取這個對象也很簡單,寫法如下:
Person person = (Person) getIntent().getSerializableExtra("person_data");
方式二:Parcelable
除了Serializable 之外,使用Parcelable 也可以實現相同的效果,不過不同於將對象進行序列化,Parcelable 方式的實現原理是將一個完整的對象進行分解,而分解后的每一部分都是Intent 所支持的數據類型,這樣也就實現傳遞對象的功能了。
下面我們來看一下Parcelable 的實現方式,修改Person 中的代碼,如下所示:
public class Person implements Parcelable { private String name; private int age; @Override public int describeContents() { // TODO Auto-generated method stub return 0; } @Override public void writeToParcel(Parcel dest, int flags) { // TODO Auto-generated method stub dest.writeString(name); dest.writeInt(age); } public static final Parcelable.Creator<Person> CREATOR=new Parcelable.Creator<Person>() { @Override public Person createFromParcel(Parcel source) { // TODO Auto-generated method stub Person person=new Person(); person.name=source.readString(); person.age=source.readInt(); return person; } @Override public Person[] newArray(int size) { // TODO Auto-generated method stub return new Person[size]; } }; }
Parcelable 的實現方式要稍微復雜一些。可以看到,首先我們讓Person 類去實現了Parcelable 接口,這樣就必須重寫describeContents()和writeToParcel()這兩個方法。其中describeContents()方法直接返回0 就可以了,而writeToParcel()方法中我們需要調用Parcel的writeXxx()方法將Person 類中的字段一一寫出。注意字符串型數據就調用writeString()方法,整型數據就調用writeInt()方法,以此類推。
除此之外,我們還必須在Person 類中提供一個名為CREATOR 的常量,這里創建了Parcelable.Creator 接口的一個實現,並將泛型指定為Person。接着需要重寫createFromParcel()和newArray()這兩個方法,在createFromParcel()方法中我們要去讀取剛才寫出的name 和age字段,並創建一個Person 對象進行返回,其中name 和age 都是調用Parcel 的readXxx()方法讀取到的,注意這里讀取的順序一定要和剛才寫出的順序完全相同。而newArray()方法中的實現就簡單多了,只需要new 出一個Person 數組,並使用方法中傳入的size 作為數組大小就可以了。
接下來在FirstActivity 中我們仍然可以使用相同的代碼來傳遞Person 對象,只不過在SecondActivity 中獲取對象的時候需要稍加改動,如下所示:
Person person = (Person) getIntent().getParcelableExtra("person_data");
注意這里不再是調用getSerializableExtra()方法,而是調用getParcelableExtra()方法來獲取傳遞過來的對象了,其他的地方都完全相同。這樣我們就把使用Intent 來傳遞對象的兩種實現方式都學習完了,對比一下,Serializable的方式較為簡單,在這里強調一下,網上很多博客很多文章都說Parcelable要比Serializable效率要高,其實不然,在讀取速度方面Serializable其實他要比Parcelable更快,具體我們可以看一下這篇文章
http://www.jianshu.com/p/fcc59fb523b6
五、Intent傳遞Bitmap
bitmap默認實現Parcelable接口,直接傳遞即可
Bitmap bitmap = null; Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putParcelable("bitmap", bitmap); intent.putExtra("bundle", bundle);
六、定義全局數據,傳遞數據
如果是傳遞簡單的數據,有這樣的需求,Activity1 -> Activity2 -> Activity3 -> Activity4, 你想在Activity中傳遞某個數據到Activity4中,怎么破,一個個頁面傳么?
顯然不科學是吧,如果你想某個數據可以在任何地方都能獲取到,你就可以考慮使用 Application全局對象了!
關鍵部分代碼:
第一步自定義Application類:
class MyApp extends Application { private String myState; public String getState(){ return myState; } public void setState(String s){ myState = s; } }
第二步AndroidManifest.xml中聲明:
<application android:name=".MyApp" android:icon="@drawable/icon" android:label="@string/app_name">
第三步在需要的地方調用:
class Blah extends Activity { @Override public void onCreate(Bundle b){ ... MyApp appState = ((MyApp)getApplicationContext()); String state = appState.getState(); ... } }
高逼格寫法
:在任何位置都能獲取到Application全局對象。
Applicaiton是系統的一個組件,他也有自己的一個生命周期,我們可以在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; } }
然后在任意地方我們就可以直接調用:MyApp.getInstance()來獲得Application的全局對象!
注意事項:
Application對象是存在於內存中的,也就有它可能會被系統殺死,比如這樣的場景:
我們在Activity1中往application中存儲了用戶賬號,然后在Activity2中獲取到用戶賬號,並且顯示!如果我們點擊home鍵,然后過了N久候,系統為了回收內存kill掉了我們的app。這個時候,我們重新 打開這個app,這個時候很神奇的,回到了Activity2的頁面,但是如果這個時候你再去獲取Application 里的用戶賬號,程序就會報NullPointerException,然后crash掉~
之所以會發生上述crash,是因為這個Application對象是全新創建的,可能你以為App是重新啟動的, 其實並不是,僅僅是創建一個新的Application,然后啟動上次用戶離開時的Activity,從而創造App 並沒有被殺死的假象!所以如果是比較重要的數據的話,建議你還是進行本地化,另外在使用數據的時候 要對變量的值進行非空檢查!還有一點就是:不止是Application變量會這樣,單例對象以及公共靜態變量 也會這樣~
七、單例模式傳參
上面的Application就是基於單例的,單例模式的特點就是可以保證系統中一個類有且只有一個實例。 這樣很容易就能實現,在A中設置參數,在B中直接訪問了。這是幾種方法中效率最高的。
范例代碼:(代碼來自於網上~)
①定義一個單例類:
public class XclSingleton { //單例模式實例 private static XclSingleton instance = null; //synchronized 用於線程安全,防止多線程同時創建實例 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); } }
②設置參數:
XclSingleton.getInstance().put("key1", "value1"); XclSingleton.getInstance().put("key2", "value2");