IPC 메커니즘 2: Serialzable, Parcelable 및 Binder
21584 단어 ParcelableipcBinderSerialzabl
간단한 소개
IPC 메커니즘에는 주로 세 가지 측면의 내용을 포함하는데 그것이 바로 Serialzable,Parcelable와 Binder이다. 그 중에서 Seialzable와Parcelable 인터페이스는 대상의 서열화 과정을 완성할 수 있고 Intent와Binder를 통해 데이터를 전송해야 할 때Seialzable나Parcelable를 사용해야 한다.때때로 우리는 대상을 저장 장치로 영구화하거나 네트워크를 통해 다른 클라이언트에게 전송해야 하며, 이때도serialzable를 사용하여 대상의 영구화를 완성해야 한다.
. .
Serialzable 인터페이스
Serialzable는 자바에서 제공하는 서열화 인터페이스입니다. 빈 인터페이스로 대상에게 표준적인 서열화와 반서열화 작업을 제공합니다.사용하기가 매우 간단합니다. 클래스가 Serialzable 인터페이스를 실현하기만 하면 됩니다.특히 SerialVersionUID의 개인 정적 구성원 변수가 있습니다.
private static final long serialVersionUID = 1L;
서열화된 데이터 중의 serialVersionUID는 현재 클래스의 serialVersionUID와 같을 때만 정상적으로 반서열화됩니다.(작업 메커니즘: 서열화할 때 시스템은 현재 클래스의serialVersionUID를 서열화된 파일에 쓴다. 반서열화할 때 시스템은 파일의 serialVersionUID가 현재 클래스의serialVersionUID와 일치하는지 검사한다. 서열화에 실패하면 현재 클래스와 서열화된 클래스에 비해 어떤 변화가 생겼음을 의미한다. 예를 들어 구성원 변수의 데이터, 유형이 바뀌었을 수 있다.회보 는 아래와 같이 틀렸다
java.io.InvalidClassException:Main; local class incompatible: stream
classdesc serialVersionUID = 8711368828010083044, local class serial
VersionUID = 8711368828010083043.
사실 이 SerialVersionUID를 성명하든 안 하든 서열화할 수 있다.그러나 serialVersionUID를 지정하지 않으면 역서열화 과정에서 문제가 발생할 수 있습니다.지정하지 않으면 Eclipse는 현재 클래스 구조에 따라 자동으로 그 해시 값을 생성하고, 현재 클래스의 구조가 바뀌면 그 해시 값이 바뀌어 서열화된 serialVersion UID와 일치하지 않기 때문이다.대상의 서열화와 반서열화를 완성하려면 Object OutputStream과 ObjectInputStream만 사용하면 된다.다음과 같습니다.
User user = new User("tom",13,true);
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(getExternalCacheDir()+"/cache.txt"));
outputStream.writeObject(user);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(getExternalCacheDir()+"/cache.txt"));
User user = (User) inputStream.readObject();
inputStream.close();
주의: 상기 반서열화로 얻은 대상은 이전의 대상 데이터와 완전히 같지만 같은 대상이 아닙니다.정적 구성원 변수는 클래스에 속하고 대상에 속하지 않기 때문에 서열화 과정에 참여하지 않는다.transient로 표시된 구성원 변수도 서열화 과정에 참여하지 않습니다..
Parcelable 커넥터
Parcelable 인터페이스는 안드로이드가 제공하는 새로운 서열화 방식입니다.우리는 이 인터페이스를 실현하기만 하면 서열화를 실현하고 Intent나 Binder를 통해 전달할 수 있다.
주의: 서열화된 대상에서 원시 대상을 만들 때, 그 안에 포함된 또 다른 서열화된 대상은 현재 라인의 상하문 클래스 로더를 전달해야 합니다. 그렇지 않으면 이 클래스를 찾을 수 없는 오류를 보고할 수 있습니다.
시스템은 우리에게Parcelable 인터페이스를 실현한 많은 종류를 제공했다. 그들은 모두 직접 서열화할 수 있다. 예를 들어 Intent, Bundle, Bitmap 등이다. 이 동시에List와Map도 서열화할 수 있다. 전제는 그들 안의 모든 요소가 서열화될 수 있다는 것이다.
둘 다 어떻게 선택하는가:
우선serialzable와Parcelable는 서열화를 실현할 수 있고 Intent 간의 데이터 전달에 사용할 수 있다. 그러나serialzable는 자바가 제공하는 서열화 인터페이스로 사용하기는 간단하지만 비용이 많이 든다. 서열화와 반서열화는 모두 대량의 I/O 작업을 해야 한다.Parcelable는 안드로이드의 서열화 방식이기 때문에 안드로이드 플랫폼에 더욱 적합하다. 그 단점은 사용하기가 번거롭지만 효율이 높다는 것이다.우리는 메모리 서열화에 주로 사용되는Parcelable를 선택합니다. 메모리 장치에 서열화되거나 네트워크를 통해 전송될 수 있지만 이 과정은 매우 번거롭습니다.그래서 만약 상술한 두 가지 상황이라면 Serialzable를 사용하세요..
Binder
Binder는 Ibinder 인터페이스에서 구현되는 Android의 클래스입니다.Binder는 IPC 관점에서 프로세스 간에 통신하는 방식입니다.안드로이드 응용층에서 볼 때 Binder는 클라이언트와 서비스 측이 통신하는 다리로서bind 서비스를 통해 서비스 측은 서비스 측의 업무 호출을 포함하는 Binder 대상을 되돌려준다. 이 Binder 대상을 통해 클라이언트는 서비스 측이 제공하는 서비스나 데이터를 얻을 수 있다.여기에는 일반 서비스와 AIDL 기반 서비스가 포함됩니다.Android 개발에서 Binder는 주로 Service에 적용됩니다.다음은 AIDL을 통해 Binder의 작업 메커니즘을 분석합니다. 먼저 세 개의 파일 Book을 만듭니다.java、Book.aidl、IBookManager.aidl //Book.java
public class Book implements Parcelable{
public int bookId;
public int bookName;
public Book(int bookId, int bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
protected Book(Parcel in) {
bookId = in.readInt();
bookName = in.readInt();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeInt(bookName);
}
}
//Book.aidl
package com.example.ipcdemo1binder.aidl;
parcelable Book;
주의: AIDL에서 Pacelable 인터페이스를 실현한 클래스는 상기와 같은 방식으로 해당하는 AIDL 파일을 만들고 그 클래스가 Pacelable라고 성명해야 합니다.
//IBookManager.aidl
package com.example.ipcdemo1binder.aidl;
import com.example.ipcdemo1binder.aidl.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
주의: AIDL에서 기본 데이터 형식을 제외하고 다른 종류의 매개 변수는 위 방향을 표시해야 합니다: in, out 또는 inout.Book 클래스는 이미 IBook Manager와 동일한 패키지에 있지만 AIDL의 특수한 부분인 Book 클래스를 가져와야 합니다.
gen 디렉토리에서 IBookManager가 자동으로 생성됩니다.java 클래스, 코드는 다음과 같습니다.
/* * This file is auto-generated. DO NOT MODIFY. * Original file: C:\\THHWork\\Developer\\EclipseWorkspace\\Temp1\\IPCDemo1Binder\\src\\com\\example\\ipcdemo1binder\\aidl\\IBookManager.aidl */
package com.example.ipcdemo1binder.aidl;
public interface IBookManager extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.ipcdemo1binder.aidl.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.example.ipcdemo1binder.aidl.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/** * Cast an IBinder object into an * com.example.ipcdemo1binder.aidl.IBookManager interface, generating a * proxy if needed. */
public static com.example.ipcdemo1binder.aidl.IBookManager asInterface(
android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.ipcdemo1binder.aidl.IBookManager))) {
return ((com.example.ipcdemo1binder.aidl.IBookManager) iin);
}
return new com.example.ipcdemo1binder.aidl.IBookManager.Stub.Proxy(
obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.ipcdemo1binder.aidl.Book> _result = this
.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.example.ipcdemo1binder.aidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.ipcdemo1binder.aidl.Book.CREATOR
.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.ipcdemo1binder.aidl.IBookManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public java.util.List<com.example.ipcdemo1binder.aidl.Book> getBookList()
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.ipcdemo1binder.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data,
_reply, 0);
_reply.readException();
_result = _reply
.createTypedArrayList(com.example.ipcdemo1binder.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.example.ipcdemo1binder.aidl.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);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.example.ipcdemo1binder.aidl.Book> getBookList()
throws android.os.RemoteException;
public void addBook(com.example.ipcdemo1binder.aidl.Book book)
throws android.os.RemoteException;
}
IBook Manager 인터페이스는 IInterface 인터페이스에서 상속되며, 두 가지 방법인 getBookList와addBook을 설명합니다.이어서 내부 클래스 Stub을 설명했습니다. 이 Stub는 Binder 클래스입니다. 클라이언트와 서버가 같은 프로세스에 있을 때, 방법 호출은 크로스 프로세스transact 프로세스를 걷지 않고, 둘이 같은 프로세스에 있을 때, 방법 호출은 크로스 프로세스transact 프로세스를 걷습니다. 이 논리는 Stub의 내부 프록시 클래스 Proxy에서 완성됩니다.
DESCRIPTOR Binder의 고유한 ID로, 일반적으로 현재 Binder의 클래스 이름으로 표시됩니다.
asInterface는 서버의 Binder 객체를 클라이언트에 필요한 AIDL 인터페이스 유형 객체로 변환하는 데 사용됩니다.이런 전환은 프로세스를 구분하는 것이다. 같은 프로세스라면 서버의 스틸 대상 자체를 되돌려주고, 같은 프로세스가 아니면 시스템이 봉인된 스틸을 되돌려준다.proxy 객체
asBinder 객체 반환
onTransact가 크로스 프로세스 요청일 때 이 방법을 사용합니다.매개 변수 코드는 클라이언트가 요청한 목표 방법이 무엇인지 확인하고 데이터에서 목표 방법에 필요한 매개 변수를 추출한 다음에 목표 방법을 실행합니다.실행이 끝나면 리플리에 반환 값을 기록합니다.주의해야 할 것은: 이 방법이false로 되돌아오면 클라이언트 요청이 실패할 것입니다.이 기능을 이용하여 권한 검증을 할 수 있습니다. 저희는 어떠한 프로세스든 저희 서비스를 원격으로 호출하기를 원하지 않습니다.
Proxy#getBookList 이 방법은 클라이언트에서 실행되며 클라이언트가 이 방법을 호출할 때 내부 구현이 이렇습니다. 먼저 이 방법에 필요한 입력형 Parcel 대상을 만듭니다데이터, 출력형 Parcel 객체reply 및 반환값 객체 List;그리고 이 방법의 매개 변수 정보를 에 쓰기데이터 (파라미터가 있으면) RPC (원격 프로세스 호출) 요청을 통해 현재 라인을 끊고 서비스 측의 onTransact 방법이 호출됩니다. RPC 프로세스가 되돌아올 때까지 현재 라인이 계속 실행되고reply에서 RPC 프로세스의 반환 결과를 추출하고 마지막에 반환reply의 데이터입니다.
Proxy#addBook 이 메서드는 getBookList와 동일한 방식으로 수행됩니다.
주의: 클라이언트가 원격 요청을 할 때 현재 스레드가 서버 프로세스가 데이터를 되돌릴 때까지 끊기기 때문에 원격 방법이 시간이 걸리면 UI 스레드에서 원격 요청을 할 수 없습니다.그 다음으로 서버 측의 Binder 방법은 Binder 스레드 탱크에서 실행되기 때문에 Binder 방법은 시간이 걸리든 안 걸리든 동기화하는 방식으로 실현해야 한다. 왜냐하면 이것은 이미 한 스레드에서 실행되었기 때문이다.
Binder에는 linkToDeath와 unlinkToDeath 두 가지 중요한 방법이 있습니다.만약 서버 프로세스가 어떤 원인으로 인해 이상하게 종료된다면, 이 때 서버 Binder에 대한 연결이 끊어져서 원격 호출에 실패할 수 있습니다.더 중요한 것은 Binder의 연결이 끊어지면 클라이언트의 기능이 영향을 받을 수 있다는 것을 모른다는 것이다.링크ToDeath를 통해 Binder에 사망 에이전트를 설정할 수 있습니다. Binder가 사망할 때 우리는 통과를 받아 연결 요청을 다시 시작할 수 있습니다.
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (bookManager == null)
return;
bookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
bookManager = null;
// Service
bindService();
}
};
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = BookManagerImpl.asInterface(service);
try {
service.linkToDeath(mDeathRecipient, 0);
List<Book> bookList = bookManager.getBookList();
} catch (RemoteException e) {
e.printStackTrace();
}
}
. . 우리도 하나의 Binder 클래스를 사용자 정의할 수 있다. 시스템이 자동으로 생성하는 클래스와 대체적으로 같지만 구조적으로 약간의 조정이 있을 뿐이다.구현 코드:https://github.com/huivs12/IPCDemo2
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Intent에서 객체를 전달하는 두 가지 방법 중 하나인 Parcelable 정보안드로이드 개발자의 예시를 먼저 보십시오: 이 몇 가지 방법은 반드시 실현해야 한다. 이 예시에서 단지 하나의 유형, 즉 int만 있다. 복잡한 유형은 어떻게 처리합니까? boolean 유형인 경우 다음과 같이 작성...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.