【轉】Android 之最新最全的Intent傳遞數據方法


原文地址: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"); 



作者:侯蛋蛋_
鏈接:https://www.jianshu.com/p/1169dba99261
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM