Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android技術基礎 >> 4.5.2 Intent之復雜數據的傳遞

4.5.2 Intent之復雜數據的傳遞

編輯:Android技術基礎

本節引言:

上一節中我們學習了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傳遞數組

嘿嘿,普通類型倒沒問題,但是如果是數組咧?解決方法如下:

寫入數組

bd.putStringArray("StringArray", new String[]{"呵呵","哈哈"});
//可把StringArray換成其他數據類型,比如int,float等等...

讀取數組

String[] str = bd.getStringArray("StringArray")

3.Intent傳遞集合

嗯,數組很簡單吧,那我們再來傳下集合~這個就稍微復雜點了,分情況處理:


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); 

4.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序列化對象


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接口的代碼示例:

//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對象,實現Parcable接口又是非常繁瑣的,可以用到 第三方的開源框架:Parceler,因為Maven的問題,暫時還沒試。

參考地址:[Android的Parcelable自動生成]

3.兩種序列化方式的比較:

兩者的比較:

  • 1)在使用內存的時候,Parcelable比Serializable性能高,所以推薦使用Parcelable。
  • 2)Serializable在序列化的時候會產生大量的臨時變量,從而引起頻繁的GC。
  • 3)Parcelable不能使用在要將數據存儲在磁盤上的情況,因為Parcelable不能很好的保證數據的 持續性在外界有變化的情況下。盡管Serializable效率低點,但此時還是建議使用Serializable。

5.Intent傳遞Bitmap

bitmap默認實現Parcelable接口,直接傳遞即可

實現代碼:

Bitmap bitmap = null;
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap", 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類:

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)在需要的地方調用:

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變量會這樣,單例對象以及公共靜態變量 也會這樣~


7.單例模式傳參

上面的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");  

本節小結:

好的,關於Intent復雜數據傳輸就到這裡,本節除了講述使用Intent來傳遞復雜數據外,還教了大家 使用Application和單例模式來傳遞參數!相信會對大家在數據傳遞方面帶來方便,謝謝~

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved