질문이 있나요? StackOverflow에 물어보세요.
문제를 발견하셨나요? 신고해주세요.
Android에서 Parcelable은 컨텍스트 간에 Java 객체를 직렬화하는 좋은 방법입니다. 기존 직렬화와 비교하여 Parcelable은 직렬화 및 역직렬화에 10배 정도 더 적은 시간을 소요합니다. 그러나 Parcelable에는 큰 결함이 있습니다. Parcelable에는 수많은 상용구 코드가 포함되어 있습니다. Parcelable을 구현하려면 동일한 순서로 Parcel을 읽고 쓰도록 writeToParcel()
및 createFromParcel()
메서드를 미러링해야 합니다. 또한 Android 인프라가 직렬화 코드를 활용할 수 있도록 Parcelable은 public static final Parcelable.Creator CREATOR
정의해야 합니다.
Parceler는 Android Parcelable 상용구 소스 코드를 생성하는 코드 생성 라이브러리입니다. 더 이상 Parcelable 인터페이스, writeToParcel()
, createFromParcel()
또는 public static final CREATOR
구현할 필요가 없습니다. @Parcel
사용하여 POJO에 주석을 달면 Parceler가 나머지 작업을 수행합니다. Parceler는 Java JSR-269 Annotation Processor를 사용하므로 Parcelable 코드를 생성하기 위해 도구를 수동으로 실행할 필요가 없습니다. Java Bean에 주석을 달고 컴파일하면 완료됩니다. 기본적으로 Parceler는 인스턴스의 필드를 직접 직렬화합니다.
@ Parcel
public class Example {
String name ;
int age ;
public Example () {}
public Example ( int age , String name ) {
this . age = age ;
this . name = name ;
}
public String getName () { return name ; }
public int getAge () { return age ; }
}
기본 필드 직렬화 전략을 사용할 때는 리플렉션으로 인해 성능 저하가 발생하므로 프라이빗 필드를 사용하지 않도록 주의하세요.
생성된 코드를 사용하려면 생성된 클래스를 직접 참조하거나 Parcels
유틸리티 클래스를 통해 참조할 수 있습니다.
Parcelable wrapped = Parcels . wrap ( new Example ( "Andy" , 42 ));
@Parcel
을 역참조하려면 Parcels.unwrap()
메서드를 호출하면 됩니다.
Example example = Parcels . unwrap ( wrapped );
example . getName (); // Andy
example . getAge (); // 42
물론 래핑된 Parcelable
Android 번들에 추가하여 활동에서 활동으로 전송할 수 있습니다.
Bundle bundle = new Bundle ();
bundle . putParcelable ( "example" , Parcels . wrap ( example ));
그리고 onCreate()
메서드에서 역참조되었습니다.
Example example = Parcels . unwrap ( getIntent (). getParcelableExtra ( "example" ));
이 래핑 및 언래핑 기술은 Intent Factory 패턴과 잘 어울립니다. 또한 Parceler는 다음 라이브러리에서 지원됩니다.
Transfuse - @Parcel
주석이 달린 Bean을 @Extra
주입과 함께 사용할 수 있습니다.
FragmentArgs - ParcelerArgsBundler
어댑터를 사용하여 @Parcel
주석이 달린 Bean을 조각 매개변수로 래핑 및 언래핑합니다.
Dart - @Parcel
주석이 달린 빈을 자동 감지하고 @InjectExtra
사용할 때 자동으로 언래핑합니다.
AndroidAnnotations - @Parcel
주석이 달린 Bean을 자동 감지하고 @Extra
, @FragmentArg
, @InstanceState
및 기타 Bundle
관련 주석을 사용할 때 자동으로 래핑/래핑 해제합니다.
ActivityStarter - 기본적으로 Parceler 개체를 활동, 조각, 서비스 등에 대한 인수로 지원합니다.
Remoter - @Remoter 인터페이스의 인수로 기본적으로 Parceler 개체를 지원합니다.
선택된 유형 수만 @Parcel
클래스의 속성으로 사용될 수 있습니다. 다음 목록에는 매핑된 유형이 포함되어 있습니다.
byte
double
float
int
long
char
boolean
String
IBinder
Bundle
매핑된 유형의 SparseArray
*
SparseBooleanArray
ObservableField
매핑된 유형의 List
, ArrayList
및 LinkedList
*
매핑된 유형 중 하나의 Map
, HashMap
, LinkedHashMap
, SortedMap
및 TreeMap
*
매핑된 유형 중 하나의 Set
, HashSet
, SortedSet
, TreeSet
, LinkedHashSet
*
Parcelable
Serializable
매핑된 유형의 배열
@Parcel
로 주석이 달린 다른 클래스
*일반 매개변수가 매핑되지 않으면 소포에 오류가 발생합니다.
Parceler는 위의 유형을 직접 지원합니다. 이는 @Parcel
주석이 달린 클래스 컬렉션을 처리할 때 특히 유용합니다.
Parcelable listParcelable = Parcels . wrap ( new ArrayList < Example >());
Parcelable mapParcelable = Parcels . wrap ( new HashMap < String , Example >());
Parceler는 상속 계층을 언래핑하지 않으므로 모든 다형성 필드는 기본 클래스의 인스턴스로 언래핑됩니다. 이는 Parceler가 모든 데이터 조각에 대해 .getClass()
확인하는 대신 성능을 선택하기 때문입니다.
@ Parcel
public class Example {
public Parent p ;
@ ParcelConstructor Example ( Parent p ) { this . p = p ; }
}
@ Parcel public class Parent {}
@ Parcel public class Child extends Parent {}
Example example = new Example ( new Child ());
System . out . println ( "%b" , example . p instanceof Child ); // true
example = Parcels . unwrap ( Parcels . wrap ( example ));
System . out . println ( "%b" , example . p instanceof Child ); // false
다형성 필드 작업의 예는 사용자 정의 직렬화 섹션을 참조하세요.
Parceler는 위에 표시된 필드 기반 직렬화 외에도 객체를 직렬화 및 역직렬화하는 방법에 대한 여러 가지 선택 사항을 제공합니다.
Parceler는 getter 및 setter 메서드와 비어 있지 않은 생성자를 사용하여 직렬화하도록 구성할 수 있습니다. 또한 @ParcelProperty
주석을 사용하여 필드, 메소드 및 생성자 매개변수를 연결할 수 있습니다. 이는 불변성과 전통적인 getter/setter bean을 포함한 다양한 bean 전략을 지원합니다.
기본 메소드 직렬화를 구성하려면 Serialization.BEAN
을 사용하여 @Parcel
주석을 구성하면 됩니다.
@ Parcel ( Serialization . BEAN )
public class Example {
private String name ;
private int age ;
private boolean enabled ;
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 ; }
public boolean isEnabled () { return enabled ; }
public void setEnabled ( boolean enabled ) { this . enabled = enabled ; }
}
직렬화와 함께 생성자를 사용하려면 원하는 생성자에 @ParcelConstructor
주석을 추가하세요.
@ Parcel ( Serialization . BEAN )
public class Example {
private final String name ;
private final int age ;
private boolean enabled ;
@ ParcelConstructor
public Example ( int age , String name , boolean enabled ) {
this . age = age ;
this . name = name ;
this . enabled = enabled ;
}
public String getName () { return name ; }
public int getAge () { return age ; }
public boolean isEnabled () { return enabled ; }
}
빈 생성자가 있는 경우 Parceler는 다른 생성자가 주석을 달지 않는 한 해당 생성자를 사용합니다.
@ParcelProperty
주석을 사용하여 직렬화 기술을 혼합하고 일치시킬 수도 있습니다. 다음 예제에서 firstName
및 lastName
생성자를 사용하여 bean에 기록되고 firstName
은 필드를 사용하여 bean에서 읽고 lastName
getLastName()
메서드를 사용하여 읽습니다. 매개변수 firstName
및 lastName
매개변수 이름 "first"
및 "last"
에 따라 각각 조정됩니다.
@ Parcel
public class Example {
@ ParcelProperty ( "first" )
String firstName ;
String lastName ;
@ ParcelConstructor
public Example ( @ ParcelProperty ( "first" ) String firstName , @ ParcelProperty ( "last" ) String lastName ){
this . firstName = firstName ;
this . lastName = lastName ;
}
public String getFirstName () { return firstName ; }
@ ParcelProperty ( "last" )
public String getLastName () { return lastName ; }
}
Parceler로 직렬화해서는 안 되는 속성의 경우 속성 필드, getter 또는 setter에 @Transient
주석을 달 수 있습니다.
Parceler는 POJO를 중심으로 다양한 스타일을 지원합니다. 이를 통해 @Parcel
주석이 달린 클래스를 다음을 포함하여 다른 POJO 기반 라이브러리와 함께 사용할 수 있습니다.
GSON
왕국
찬장
간단한 XML
DB흐름
생성자를 직접 사용하는 대신 Parceler는 주석이 달린 정적 팩토리를 사용하여 지정된 클래스의 인스턴스를 빌드하도록 지원합니다. 이 스타일은 불변 빈 생성을 위한 Google의 AutoValue 주석 프로세서/코드 생성 라이브러리를 지원합니다. Parceler는 정적 팩터리 메서드를 주석이 달린 @Parcel
직렬화에 매핑하는 @ParcelFactory
주석을 통해 AutoValue와 인터페이스합니다.
@ AutoValue
@ Parcel
public abstract class AutoValueParcel {
@ ParcelProperty ( "value" ) public abstract String value ();
@ ParcelFactory
public static AutoValueParcel create ( String value ) {
return new AutoValue_AutoValueParcel ( value );
}
}
AutoValue는 주석이 달린 @Parcel
과 다른 클래스를 생성하므로 Parcels
유틸리티 클래스에서 Parceler가 빌드해야 하는 클래스를 지정해야 합니다.
Parcelable wrappedAutoValue = Parcels . wrap ( AutoValueParcel . class , AutoValueParcel . create ( "example" ));
그리고 역직렬화하려면:
AutoValueParcel autoValueParcel = Parcels . unwrap ( wrappedAutoValue );
@Parcel
에는 특수 직렬화가 필요한 경우를 위해 수동 직렬 변환기 ParcelConverter
포함하는 선택적 매개 변수가 포함되어 있습니다. 이는 Parcelable 클래스를 직접 구현하는 것보다 훨씬 더 깔끔한 옵션을 제공합니다.
다음 코드는 역직렬화 중에 상속 계층 구조를 풀기 위해 ParcelConverter
를 사용하는 방법을 보여줍니다.
@ Parcel
public class Item {
@ ParcelPropertyConverter ( ItemListParcelConverter . class )
public List < Item > itemList ;
}
@ Parcel public class SubItem1 extends Item {}
@ Parcel public class SubItem2 extends Item {}
public class ItemListParcelConverter implements ParcelConverter < List < Item >> {
@ Override
public void toParcel ( List < Item > input , Parcel parcel ) {
if ( input == null ) {
parcel . writeInt (- 1 );
}
else {
parcel . writeInt ( input . size ());
for ( Item item : input ) {
parcel . writeParcelable ( Parcels . wrap ( item ), 0 );
}
}
}
@ Override
public List < Item > fromParcel ( Parcel parcel ) {
int size = parcel . readInt ();
if ( size < 0 ) return null ;
List < Item > items = new ArrayList < Item >();
for ( int i = 0 ; i < size ; ++ i ) {
items . add (( Item ) Parcels . unwrap ( parcel . readParcelable ( Item . class . getClassLoader ())));
}
return items ;
}
}
Parceler는 API의 org.parceler.converter
패키지 아래에 위치하여 컬렉션 변환을 더 쉽게 만들기 위해 일련의 기본 클래스와 함께 패키지되어 있습니다. 이러한 기본 클래스는 null 검사 및 수집 반복을 포함하여 컬렉션을 다루는 다양한 어렵거나 장황한 작업을 처리합니다. 예를 들어 위의 ParcelConverter
`ArrayListParcelConverter'를 사용하여 작성할 수 있습니다.
public class ItemListParcelConverter extends ArrayListParcelConverter < Item > {
@ Override
public void itemToParcel ( Item item , Parcel parcel ) {
parcel . writeParcelable ( Parcels . wrap ( item ), 0 );
}
@ Override
public Item itemFromParcel ( Parcel parcel ) {
return Parcels . unwrap ( parcel . readParcelable ( Item . class . getClassLoader ()));
}
}
해당 Java 소스를 사용할 수 없는 클래스의 경우 @ParcelClass
주석을 사용하여 클래스를 Parcel로 포함할 수 있습니다. 이 주석은 컴파일된 소스의 편리한 위치 어디에서나 선언될 수 있습니다. 예를 들어 Android 애플리케이션과 함께 @ParcelClass
를 포함할 수 있습니다.
@ ParcelClass ( LibraryParcel . class )
public class AndroidApplication extends Application {
//...
}
@ParcelClasses
주석을 사용하여 여러 @ParcelClass
주석을 선언할 수 있습니다.
또한 @ParcelClass
가 참조하는 클래스는 @Parcel
주석을 사용하여 구성할 수 있습니다. 이를 통해 분석할 직렬화 기술이나 클래스를 포함하여 @Parcel
주석에서 사용 가능한 모든 매개변수를 통해 직렬화 구성을 수행할 수 있습니다.
유용한 기술 중 하나는 유형에 대한 전역 사용자 정의 변환기를 정의하는 기능입니다.
@ ParcelClass (
value = LibraryParcel . class ,
annotation = @ Parcel ( converter = LibraryParcelConverter . class ))
class SomeClass {}
이를 통해 직접 수정할 수 없는 클래스를 세밀하게 제어할 수 있습니다.
일부 라이브러리에서는 기본 클래스를 확장하기 위해 Bean을 요구하는 것이 일반적인 관행입니다. 가장 최적의 경우는 아니지만 Parceler는 analyze 매개변수를 통해 상속 계층 구조의 어떤 클래스를 분석할지 구성할 수 있도록 허용하여 이 방식을 지원합니다.
@ Parcel ( analyze = { One . class , Three . class })
class One extends Two {}
class Two extends Three {}
class Three extends BaseClass {}
이 예에서는 BaseClass
및 Two
클래스 매개변수를 모두 피하고 One
및 Three
클래스의 필드만 직렬화됩니다.
Parcels 유틸리티 클래스는 클래스별로 래핑하기 위해 지정된 클래스를 조회합니다. 성능상의 이유로 이는 상위 클래스와 기본 클래스 모두 상속을 무시합니다. 이 문제에 대한 두 가지 해결책이 있습니다. 먼저, implementations
매개변수를 통해 주어진 유형에 연결할 추가 유형을 지정할 수 있습니다.
class ExampleProxy extends Example {}
@ Parcel ( implementations = { ExampleProxy . class })
class Example {}
ExampleProxy proxy = new ExampleProxy ();
Parcels . wrap ( proxy ); // ExampleProxy will be serialized as a Example
둘째, Parcels.wrap()
메서드를 사용할 때 클래스 유형을 지정할 수도 있습니다.
ExampleProxy proxy = new ExampleProxy ();
Parcels . wrap ( Example . class , proxy );
Proguard를 구성하려면 proguard 구성 파일에 다음 줄을 추가하세요. 이는 Parcels
유틸리티 클래스 및 Parcelable
CREATOR
인스턴스와 관련된 파일을 유지합니다: er
# 파셀러 라이브러리 - 인터페이스 org.parceler.Parcel 유지 -keep @org.parceler.Parcel 클래스 * { *; } -유지 클래스 **$$Parcelable { *; }
Parceler를 Maven 종속성으로 다운로드할 수 있습니다.
< dependency >
< groupId >org.parceler</ groupId >
< artifactId >parceler</ artifactId >
< version >1.1.12</ version >
< scope >provided</ scope >
</ dependency >
< dependency >
< groupId >org.parceler</ groupId >
< artifactId >parceler-api</ artifactId >
< version >1.1.12</ version >
</ dependency >
또는 Gradle:
implementation ' org.parceler:parceler-api:1.1.12 '
annotationProcessor ' org.parceler:parceler:1.1.12 '
또는 Maven Central에서.
저작권 2011-2015 존 에릭슨 Apache 라이센스 버전 2.0("라이센스")에 따라 라이센스가 부여되었습니다. 라이센스를 준수하는 경우를 제외하고는 이 파일을 사용할 수 없습니다. 다음에서 라이센스 사본을 얻을 수 있습니다. http://www.apache.org/licenses/LICENSE-2.0 해당 법률에서 요구하거나 서면으로 동의하지 않는 한, 소프트웨어 라이선스에 따라 배포되는 것은 "있는 그대로" 기반으로 배포됩니다. 명시적이든 묵시적이든 어떠한 종류의 보증이나 조건도 제공하지 않습니다. 권한 및 권한을 관리하는 특정 언어는 라이센스를 참조하세요. 라이센스에 따른 제한.