AndroidのParcelとParcelable
まとめ:Parcelクラスは1つのコンテナであり、様々なタイプのデータを入れることができ、C/CPPの下位層で伝送することができる. ParcelはBinderドライバで異なるプロセスのためにデータインタラクションを実現できるが、なぜこのような役割を果たすことができるのか.システム設計が可能である.異なるプロセスはJava層では互いに独立しており、異なるメモリ空間を持っているが、下位層にはbinderドライバ(binder.cpp)がそれらを統一して相互接続を実現しているが、Parcelは3層コード(Java-JNI-Native、もちろんBinderも)を実現しているため、javaでC層を操作することができる.したがって,Parcelを用いてデータをロードし,ツールクラスbinderドライバ(binder.cpp)で処理した結果,Native層を介してJava層にコールバックするという操作の組み合わせが最適である.
Parcelに比べて、私たちはParcelableによく接触しています.2つの単語は似ていますが、違いはありますか?同じ点:両方ともAndroid専用のシステムクラス. Parcelは、プロセス間通信、データ転送のためのエンティティークラスです. Parcelableは、Androidの高性能シーケンス化に使用されるインターフェース(詳細はアクセスしてください)
Parcelableとは何かを知ってから、Parcelクラスを知ってみましょう.
AIDLによって自動的に生成されるファイルには、次のコードの例があります.
Parcelクラス
Parcelは、もともと「包む、包む」という意味で、Androidでは、主にシーケンス化されたデータを格納し、Binderを介してプロセス間でデータを転送するコンテナです.転送データ型は次のとおりです.元データ型(writeInt()やwriteFloat()など、様々な対応方法で書き込む) Parcelableオブジェクト(例:writeParcelable()、writeParcelableCreator()等) IBinderオブジェクトの参照(例:writeStrongBinder()) 検索コードで発見(Andoridソースをダウンロードする必要がある)、AndroidはJava-Jni-CにParcelクラスがあり、Java層:/frameworks/base/core/java/android/os/parcel.java JNI レイヤ:/frameworks/base/core/jni/android_os_Parcel.cpp C++層:/frameworks/native/libs/binder/Parcel.cpp Javaレイヤコードはパッケージエージェントにすぎず、C++レイヤで実装されていることがわかります.
呼び出しプロシージャ取得 データの格納と読み出し:通過 データのシーケンス化と逆シーケンス化: 回収資源:通過
1、Parcelオブジェクトの取得方法
2、データの書き込み
3、データの読み出し
4、どのようにしてParcelオブジェクトを回収しますか?
Parcelに比べて、私たちはParcelableによく接触しています.2つの単語は似ていますが、違いはありますか?
public final class Parcel {.....}
public interface Parcelable {.....}
Parcelableとは何かを知ってから、Parcelクラスを知ってみましょう.
AIDLによって自動的に生成されるファイルには、次のコードの例があります.
//
@Override
public void addBook(com.test.aidl_demo.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0); // Book , Parcelable
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
Parcelクラス
Parcelは、もともと「包む、包む」という意味で、Androidでは、主にシーケンス化されたデータを格納し、Binderを介してプロセス間でデータを転送するコンテナです.転送データ型は次のとおりです.
呼び出しプロシージャ
Parcel :
通過obtain()
静的方法writeXXX()
和 readXXX()
実現、marshall()
と unmarshall()
, recycle()
1、Parcelオブジェクトの取得方法
Parcel.java :
// Parcel , , Parcel ,
// Parcel
private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
public static Parcel obtain() {
final Parcel[] pool = sOwnedPool;
synchronized (pool) {
Parcel p;
for (int i=0; i(parcel);
}
Native (Parcel.cpp):
Parcel::Parcel()
{
initState();
}
//
void Parcel::initState()
{
mError = NO_ERROR; //
mData = 0; // 1, ,
mDataSize = 0; //
mDataCapacity = 0; // ( ) ,
mDataPos = 0; //
ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
mObjects = NULL; // 2, Binder
mObjectsSize = 0;
mObjectsCapacity = 0;
mNextObjectHint = 0;
mHasFds = false;
mFdsKnown = true;
mAllowFds = true;
mOwner = NULL;
}
Parcel , mData mObjects,mData ,mObjects Binder 。
mData parcel ,
mDataCapacity parcel ( ),
mDataPos parcel , parcel 。
= + ,
reinterpret_cast c++ ,
2、データの書き込み
---
Java (Parcel.java)
public final void writeInt(int val) {
nativeWriteInt(mNativePtr, val);
}
private static native void nativeWriteInt(long nativePtr, int val);
JNI :
static const JNINativeMethod gParcelMethods[] = {
......
{"nativeWriteInt", "(JI)V", (void*)android_os_Parcel_writeInt},
{"nativeWriteLong", "(JJ)V", (void*)android_os_Parcel_writeLong},
......
};
static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
Parcel* parcel = reinterpret_cast(nativePtr); //
const status_t err = parcel->writeInt32(val);
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
Native :
status_t Parcel::writeInt32(int32_t val) // 32 4
{
return writeAligned(val); //
}
template
status_t Parcel::writeAligned(T val) {
//
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
// ,
if ((mDataPos+sizeof(val)) <= mDataCapacity) { // ,
// goto
restart_write:
// , , 。
*reinterpret_cast(mData+mDataPos) = val; // *p = value
return finishWrite(sizeof(val)); // ,
}
// ,
status_t err = growData(sizeof(val));
if (err == NO_ERROR) goto restart_write; // goto ,
return err;
}
status_t Parcel::finishWrite(size_t len)
{
mDataPos += len;
ALOGV("finishWrite Setting data pos of %p to %zu", this, mDataPos);
if (mDataPos > mDataSize) {
// mDataSize: mData
// mDataPos , , 。
mDataSize = mDataPos;
ALOGV("finishWrite Setting data size of %p to %zu", this, mDataSize);
}
return NO_ERROR;
}
status_t Parcel::growData(size_t len)
{
size_t newSize = ((mDataSize+len)*3)/2; // ( + )* 1.5
return (newSize <= mDataSize)
? (status_t) NO_MEMORY
: continueWrite(newSize);
}
3、データの読み出し
Java :
// , Parcel
private long mNativePtr; // used by native code
public final int readInt() {
return nativeReadInt(mNativePtr);
}
private static native int nativeReadInt(long nativePtr);
JNI :
static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast(nativePtr);
if (parcel != NULL) {
return parcel->readInt32();
}
return 0;
}
Native :
int32_t Parcel::readInt32() const
{
return readAligned();
}
// int32_t:int_t , type/typedef ,
int32_t : typedef signed int;
uint32_t : typedef unsigned int;
// typedef , 。 , ,
// typedef 。
template
status_t Parcel::readAligned(T *pArg) const {
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
if ((mDataPos+sizeof(T)) <= mDataSize) { //
const void* data = mData+mDataPos;
mDataPos += sizeof(T); //
*pArg = *reinterpret_cast(data);
return NO_ERROR;
} else {
return NOT_ENOUGH_DATA;
}
}
: ,
1、 parcel (mData) + parcel (mDataPos), ,
2、 , parcel + ,
3、
mData+mDataPos , T (T ), val 。
4、どのようにしてParcelオブジェクトを回収しますか?
Java (Parcel.java):
public final void recycle() {
if (DEBUG_RECYCLE) mStack = null;
freeBuffer();
final Parcel[] pool;
if (mOwnsNativeParcelObject) {
pool = sOwnedPool;
} else {
mNativePtr = 0;
pool = sHolderPool;
}
synchronized (pool) {
// , , parcel ,
// , ,
for (int i=0; i(nativePtr);
if (parcel != NULL) {
parcel->freeData();
}
}
Native :
void Parcel::freeData()
{
freeDataNoInit(); //
initState(); //
}
void Parcel::freeDataNoInit()
{
if (mOwner) {
//ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
} else {
releaseObjects();
if (mData) free(mData);
if (mObjects) free(mObjects);
}
}
void Parcel::initState()
{
mError = NO_ERROR;
mData = 0;
mDataSize = 0;
mDataCapacity = 0;
mDataPos = 0;
ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
mObjects = NULL;
mObjectsSize = 0;
mObjectsCapacity = 0;
mNextObjectHint = 0;
mHasFds = false;
mFdsKnown = true;
mAllowFds = true;
mOwner = NULL;
}
void Parcel::releaseObjects()
{
const sp proc(ProcessState::self());
size_t i = mObjectsSize;
uint8_t* const data = mData;
binder_size_t* const objects = mObjects;
while (i > 0) {
i--;
const flat_binder_object* flat
= reinterpret_cast(data+objects[i]);
release_object(proc, *flat, this);
}
}
void release_object(const sp& proc,
const flat_binder_object& obj, const void* who)
{
switch (obj.type) {
case BINDER_TYPE_BINDER:
if (obj.binder) {
LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
reinterpret_cast(obj.cookie)->decStrong(who);
}
return;
case BINDER_TYPE_WEAK_BINDER:
if (obj.binder)
reinterpret_cast<:weakref_type>(obj.binder)->decWeak(who);
return;
case BINDER_TYPE_HANDLE: {
const sp b = proc->getStrongProxyForHandle(obj.handle);
if (b != NULL) {
LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());
b->decStrong(who);
}
return;
}
case BINDER_TYPE_WEAK_HANDLE: {
const wp b = proc->getWeakProxyForHandle(obj.handle);
if (b != NULL) b.get_refs()->decWeak(who);
return;
}
case BINDER_TYPE_FD: {
if (obj.cookie != 0) close(obj.handle);
return;
}
}
ALOGE("Invalid object type 0x%08x", obj.type);
}