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

Intent的基本使用

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

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.lxweimin.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");  
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容