Android中的Parcel機制 實現Bundle傳遞對象


Android中的Parcel機制
    實現了Bundle傳遞對象
    使用Bundle傳遞對象,首先要將其序列化,但是,在Android中要使用這種傳遞對象的方式需要用到Android Parcel機制,即,Android實現的輕量級的高效的對象序列化和反序列化機制。

    JAVA中的Serialize機制,譯成串行化、序列化……,其作用是能將數據對象存入字節流當中,在需要時重新生成對象。主要應用是利用外部存儲設備保存對象狀態,以及通過網絡傳輸對象等。
    
    Android中的新的序列化機制
        在Android系統中,定位為針對內存受限的設備,因此對性能要求更高,另外系統中采用了新的IPC(進程間通信)機制,必然要求使用性能更出色的對象傳輸方式。在這樣的環境下,
        Parcel被設計出來,其定位就是輕量級的高效的對象序列化和反序列化機制。
        Android中序列化有以下幾個特征:
        1. 整個讀寫全是在內存中進行,所以效率比JAVA序列化中使用外部存儲器會高很多;
        2. 讀寫時是4字節對齊的
        3. 如果預分配的空間不夠時,會一次多分配50%;
        4. 對於普通數據,使用的是mData內存地址,對於IBinder類型的數據以及FileDescriptor使用的是mObjects內存地址。后者是通過flatten_binder()和unflatten_binder()實現的,目的是反序列化時讀出的對象就是原對象而不用重新new一個新對象。

package com.parcel.main;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MyTestParcelActivity extends Activity {

    public final static int Sub_Main = 1;
    public final static int Sub_2_Main = 2;

    private Button setSubMain;
    private Button setSub2Main;
    private TextView mTextView;

    private Drawable defDrawable;
    private MyParcel mMyParcel = new MyParcel();
    private BinderMyParcel mBinderMyParcel = new BinderMyParcel();

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        initComponent();
    }

    private void initComponent() {
        setSubMain = (Button) findViewById(R.id.btn01);
        if (setSubMain != null) {
            setSubMain.setOnClickListener(setSubMainXML);
        }

        setSub2Main = (Button) findViewById(R.id.btn04);
        if (setSub2Main != null) {
            setSub2Main.setOnClickListener(setSub2MainXML);
        }

        mTextView = (TextView) findViewById(R.id.main_tv);
        defDrawable = mTextView.getBackground();
    }

    private View.OnClickListener setSubMainXML = new OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent mIntent = new Intent();
            if (mMyParcel != null) {
                mMyParcel.setColor(Color.RED);
                mIntent.putExtra("MyColor", mMyParcel);
            }
            mIntent.setClass(MyTestParcelActivity.this,
                    SubMyTestParcelActivity.class);

            mTextView.setBackgroundDrawable(defDrawable);

            startActivityForResult(mIntent, Sub_Main);
        }
    };
    private View.OnClickListener setSub2MainXML = new OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent intent = new Intent();
            if (mBinderMyParcel != null) {
                mBinderMyParcel.setColor(Color.MAGENTA);
                intent.putExtra("BinderMyColor", mBinderMyParcel);
            }
            intent.setClass(MyTestParcelActivity.this,
                    Sub2MyTestParcelActivity.class);

            mTextView.setBackgroundDrawable(defDrawable);

            startActivityForResult(intent, Sub_2_Main);
        }
    };

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            if (requestCode == Sub_Main) {
                if (data.hasExtra("MyColor")) {
                    /**
                     * color=data.getParcelableExtra("MyColor"),
                     * 這說明反序列化后是一個新的MyColor對象
                     * 
                     * 如果數據本身是IBinder類型,那么反序列化的結果就是原對象,而不是新建的對象
                     */
                    mMyParcel = data.getParcelableExtra("MyColor");
                    ((TextView) findViewById(R.id.main_tv))
                            .setTextColor(mMyParcel.getColor());
                }
            } else if (requestCode == Sub_2_Main) {
                if (data.hasExtra("BinderMyColor")) {
                    ((TextView) findViewById(R.id.main_tv))
                            .setBackgroundColor(mBinderMyParcel.getColor());
                }
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

}

使用非binder類型代碼

package com.parcel.main;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class SubMyTestParcelActivity extends Activity implements
        OnClickListener {

    private Button setSub2XML;
    private TextView mTextView;
    private MyParcel myColor;
    
    private Drawable defDrawable;
    

    /** Called when the activity is first created. */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.submain);

        setSub2XML = (Button) findViewById(R.id.btn02);
        setSub2XML.setOnClickListener(this);

        mTextView = (TextView)findViewById(R.id.sub_tv);
        defDrawable = mTextView.getBackground();
        
        Intent intent = getIntent();
        if (intent != null) {
            if (intent.hasExtra("MyColor")) {
                myColor = intent.getParcelableExtra("MyColor");
                mTextView.setBackgroundColor(myColor.getColor());
            }
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onRestart() {
        super.onRestart();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn02:
            Intent mIntent = new Intent(getApplicationContext(),
                    Sub2MyTestParcelActivity.class);
            if (myColor != null) {
                myColor.setColor(Color.GREEN);
                mIntent.putExtra("MyColor", myColor);
            }

            mTextView.setBackgroundDrawable(defDrawable);
            setResult(RESULT_OK, mIntent);
            finish();
            break;

        default:
            break;
        }
    }

}

使用binder類型代碼

package com.parcel.main;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class Sub2MyTestParcelActivity extends Activity implements
        OnClickListener {

    private Button setMainXML;
    private TextView mTextView;
    private BinderMyParcel myColor;

    private Drawable defDrawable;

    /** Called when the activity is first created. */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.sub2main);

        setMainXML = (Button) findViewById(R.id.btn03);
        setMainXML.setOnClickListener(this);

        mTextView = (TextView) findViewById(R.id.sub_tv);
        defDrawable = mTextView.getBackground();

        Intent intent = getIntent();
        if (intent != null) {
            if (intent.hasExtra("BinderMyColor")) {
                myColor = intent.getParcelableExtra("BinderMyColor");
                mTextView.setBackgroundColor(myColor.getColor());
            }
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn03:
            Intent mIntent = new Intent(getApplicationContext(),
                    MyTestParcelActivity.class);
            if (myColor != null) {
                myColor.setColor(Color.WHITE);
                mIntent.putExtra("BinderMyColor", myColor);
            }

            mTextView.setBackgroundDrawable(defDrawable);
            setResult(RESULT_OK, mIntent);
            finish();
            break;

        default:
            break;
        }
    }

}

 非Binder類型的Parcel,實現Parcelable接口即可:

package com.parcel.main;

import android.graphics.Color;
import android.os.Parcel;
import android.os.Parcelable;

public class MyParcel implements Parcelable {
    private int color = Color.BLACK;

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }

    public MyParcel() {
        color = Color.BLACK;
    }

    public MyParcel(Parcel in) {
        color = in.readInt();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(color);
    }

    public static final Parcelable.Creator<MyParcel> CREATOR = new Parcelable.Creator<MyParcel>() {

        public MyParcel createFromParcel(Parcel in) {
            return new MyParcel(in);
        }

        public MyParcel[] newArray(int size) {
            return new MyParcel[size];
        }
    };

}

 對於Binder類型,首先要實現一個Binder接口(其,最主要的區別在於反序列化仍然是原來的對象,而非Binder類型的反序列化並不是原來的對象,所以在MainActivity中的onActivityResult方法中會出現mMyParcel = data.getParcelableExtra("MyColor")的寫法):

package com.parcel.main;

import android.os.Binder;

public class BinderData extends Binder {

    public int color;

}

 其次再實現Parcelable接口:

package com.parcel.main;

import android.graphics.Color;
import android.os.Parcel;
import android.os.Parcelable;

public class BinderMyParcel implements Parcelable {

    private BinderData data = new BinderData();

    public BinderMyParcel() {
        data.color = Color.BLUE;
    }

    public BinderMyParcel(Parcel in) {
        data = (BinderData) in.readValue(BinderData.class.getClassLoader());
    }

    public void setColor(int color) {
        data.color = color;
    }

    public int getColor() {
        return data.color;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeValue(data);
    }

    public static final Parcelable.Creator<BinderMyParcel> CREATOR = new Creator<BinderMyParcel>() {

        @Override
        public BinderMyParcel[] newArray(int size) {
            return new BinderMyParcel[size];
        }

        @Override
        public BinderMyParcel createFromParcel(Parcel source) {
            return new BinderMyParcel(source);
        }
    };
}

三個XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:id="@+id/main_tv" android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/main_activity" />
    <LinearLayout android:orientation="horizontal"
        android:layout_width="wrap_content" android:layout_height="wrap_content">
        <Button android:text="SetSubMainXML" android:id="@+id/btn01"
            android:layout_width="wrap_content" android:layout_height="wrap_content" />
        <Button android:id="@+id/btn04" android:layout_height="wrap_content"
            android:layout_width="wrap_content" android:text="SetSub2MainXML" />
    </LinearLayout>

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:id="@+id/sub_tv" android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/sub_activity" />
    <Button android:text="setMainXML" android:id="@+id/btn02"
        android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:id="@+id/sub_tv" android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/sub2_activity" />
    <Button android:text="setMainXML" android:id="@+id/btn03"
        android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>

 


免責聲明!

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



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