下面列出了android.os.Parcelable#writeToParcel ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Test all parcels within package to see if they properly implement {@link Parcelable}
*
* @throws Exception
*/
public void testParcel() throws Exception {
Class[] classesToCheck = getClassesToCheck();
for (Class classToCheck : classesToCheck) {
if (ObjectHelper.isParcelable(classToCheck) && !Modifier.isAbstract(classToCheck.getModifiers())) {
/**
* Helps us to not get into infinite loops if we have a structure in our models where something
* like a Person model can have a Person field
*/
ObjectStack objectStack = new ObjectStack();
Parcelable parcelable = (Parcelable) ObjectHelper.getTestObject(objectStack, classToCheck);
Parcel parcel = Parcel.obtain();
parcelable.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
Field creatorField = classToCheck.getField("CREATOR");
Parcelable.Creator creator = (Parcelable.Creator) creatorField.get(null);
Parcelable read = (Parcelable) creator.createFromParcel(parcel);
if (checkingForSuccess()) {
assertTrue(classToCheck.getSimpleName() + " did not equal after parceling", ObjectHelper.checkFieldsEqual(classToCheck.getSimpleName(), parcelable, read, checkingForSuccess()));
} else {
boolean success = ObjectHelper.checkFieldsEqual(classToCheck.getSimpleName(), parcelable, read, checkingForSuccess());
assertFalse("Looks like " + classToCheck.getSimpleName() + " was supposed to have failed, but didn't", success);
}
}
}
}
public static byte[] serialize(Parcelable parceable) {
Parcel parcel = Parcel.obtain();
parceable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
/**
* Convert a {@link Parcelable} into its {@link ByteString} representation.
*
* @param parcelable to convert into a {@link ByteString}
*/
@Override
public ByteString convert(@NonNull Parcelable parcelable) {
Parcel parcel = null;
try {
parcel = Parcel.obtain();
parcelable.writeToParcel(parcel, 0);
return copyFrom(parcel.marshall());
} finally {
if (parcel != null) {
parcel.recycle();
}
}
}
private void writeNullParcelable(Parcelable p, Parcel dest, int flags) {
if (p != null) {
dest.writeInt(1);
p.writeToParcel(dest, flags);
} else {
dest.writeInt(0);
}
}
@NonNull
public static byte[] marshall(@NonNull final Parcelable parcelable) {
final Parcel parcel = Parcel.obtain();
parcelable.writeToParcel(parcel, 0);
final byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
public static byte[] marshall(Parcelable parceable) {
Parcel parcel = Parcel.obtain();
parceable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
private static byte[] parcelable2Bytes(Parcelable parcelable) {
if (parcelable == null) return null;
Parcel parcel = Parcel.obtain();
parcelable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
public static byte[] marshall(Parcelable parcelable) {
Parcel parcel = Parcel.obtain();
parcelable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
public static void putParcelable(Context context, String key, Parcelable parcelable) {
Parcel parcel = Parcel.obtain();
parcelable.writeToParcel(parcel, 0);
getSharedPreferences(context).edit()
.putString(key, Base64.encodeToString(parcel.marshall(), 0))
.apply();
}
public static byte[] marshall(Parcelable parceable) {
Parcel parcel = Parcel.obtain();
parceable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
public static byte[] marshall(Parcelable parceable) {
Parcel parcel = Parcel.obtain();
parceable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle(); // not sure if needed or a good idea
return bytes;
}
public static byte[] serialize(Parcelable parceable) {
Parcel parcel = Parcel.obtain();
parceable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
private static void writeParcelable(LinkedList<Object> parcelData, Parcelable parcelable, Parcel parcel1) {
if (parcelable == null) {
parcelData.add(null);
} else {
parcelable.describeContents();
parcelData.add(parcelable.getClass());
parcelable.writeToParcel(parcel1, 0);
}
}
/**
* Converts the Parcelable object to a byte[]
*
* @param parcelable
* @return
*/
public static byte[] parcelToByte(@NonNull Parcelable parcelable) {
Parcel parcel = Parcel.obtain();
parcelable.writeToParcel(parcel, 0);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
private void testSerialization(ParcelableDescriptor descriptor) throws Exception {
generator.generateParcelable(targetType, descriptor);
ClassLoader classLoader = codeGenerationUtil.build();
Class<Parcelable> parcelableClass = (Class<Parcelable>) classLoader.loadClass(ClassNamer.className(targetType).append(Parcels.IMPL_EXT).build().toString());
Parcelable outputParcelable = parcelableClass.getConstructor(Target.class).newInstance(target);
outputParcelable.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
Parcelable inputParcelable = ((Parcelable.Creator<Parcelable>)parcelableClass.getField("CREATOR").get(null)).createFromParcel(parcel);
Target wrapped = Parcels.unwrap(inputParcelable);
assertEquals(target.getValue(), wrapped.getValue());
}
private static List<String> getText(Notification notification) {
RemoteViews contentView = notification.contentView;
/*if (Build.VERSION.SDK_INT >= 16) {
contentView = notification.bigContentView;
}*/
// Use reflection to examine the m_actions member of the given RemoteViews object.
// It's not pretty, but it works.
List<String> text = new ArrayList<>();
try
{
Field field = contentView.getClass().getDeclaredField("mActions");
field.setAccessible(true);
@SuppressWarnings("unchecked")
ArrayList<Parcelable> actions = (ArrayList<Parcelable>) field.get(contentView);
// Find the setText() and setTime() reflection actions
for (Parcelable p : actions)
{
Parcel parcel = Parcel.obtain();
p.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
// The tag tells which type of action it is (2 is ReflectionAction, from the source)
int tag = parcel.readInt();
if (tag != 2) continue;
// View ID
parcel.readInt();
String methodName = parcel.readString();
//noinspection ConstantConditions
if (methodName == null) continue;
// Save strings
else if (methodName.equals("setText"))
{
// Parameter type (10 = Character Sequence)
parcel.readInt();
// Store the actual string
String t = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel).toString().trim();
if (!text.contains(t)) {
text.add(t);
}
}
// Save times. Comment this section out if the notification time isn't important
/*else if (methodName.equals("setTime"))
{
// Parameter type (5 = Long)
parcel.readInt();
String t = new SimpleDateFormat("h:mm a").format(new Date(parcel.readLong()));
text.add(t);
}*/
parcel.recycle();
}
}
// It's not usually good style to do this, but then again, neither is the use of reflection...
catch (Exception e)
{
Mlog.e("NotificationClassifier", e.toString());
return null;
}
return text;
}
private ProgressInfo getProgressInfo(String id, Notification n) {
if (id == null || n == null) return null;
ProgressInfo pInfo = new ProgressInfo(id, false, 0, 0);
// We have to extract the information from the content view
RemoteViews views = n.bigContentView;
if (views == null) views = n.contentView;
if (views == null) return pInfo;
try {
@SuppressWarnings("unchecked")
List<Parcelable> actions = (List<Parcelable>)
XposedHelpers.getObjectField(views, "mActions");
if (actions == null) return pInfo;
for (Parcelable p : actions) {
Parcel parcel = Parcel.obtain();
p.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
// The tag tells which type of action it is (2 is ReflectionAction)
int tag = parcel.readInt();
if (tag != 2) {
parcel.recycle();
continue;
}
parcel.readInt(); // skip View ID
String methodName = parcel.readString();
if ("setMax".equals(methodName)) {
parcel.readInt(); // skip type value
pInfo.max = parcel.readInt();
if (DEBUG) log("getProgressInfo: total=" + pInfo.max);
} else if ("setProgress".equals(methodName)) {
parcel.readInt(); // skip type value
pInfo.progress = parcel.readInt();
pInfo.hasProgressBar = true;
if (DEBUG) log("getProgressInfo: current=" + pInfo.progress);
}
parcel.recycle();
}
} catch (Throwable t) {
XposedBridge.log(t);
}
return pInfo;
}
@Test
public void testGeneratedParcelable() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchFieldException {
ParcelTarget parcelTarget = new ParcelTarget();
ParcelSecondTarget parcelSecondTarget = new ParcelSecondTarget();
parcelTarget.setDoubleValue(Math.PI);
parcelTarget.setStringValue(TEST_VALUE);
parcelTarget.setSecondTarget(parcelSecondTarget);
parcelSecondTarget.setValue(TEST_VALUE);
Parcelable outputParcelable = parcelableClass.getConstructor(ParcelTarget.class).newInstance(parcelTarget);
outputParcelable.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
Parcelable inputParcelable = ((Parcelable.Creator<Parcelable>)parcelableClass.getField("CREATOR").get(null)).createFromParcel(parcel);
ParcelTarget wrapped = Parcels.unwrap(inputParcelable);
assertEquals(parcelTarget, wrapped);
}
public static Parcel writeToParcel(Parcelable parcelable) {
Parcel parcel = Parcel.obtain();
parcelable.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
return parcel;
}
/**
* 根据Parcelable对象,构造出适合在任何地方使用的Parcel对象
* 该方法可杜绝ClassCastException异常
* <p>
* 注意:
* 用完必须调用p.recycle方法
* <p>
* Before:
* <pre class="prettyprint">\
* // ERROR: Might be "ClassCastException" Error
* XXX x = intent.getParcelableExtra("XXX");
* </pre>
* <p>
* After:
* <pre class="prettyprint">
* Parcelable pa = intent.getParcelableExtra("XXX");
* Parcel p = ParcelUtils.createFromParcelable(pa);
* <p>
* // Create a new XXX object to avoid "ClassCastException"
* XXX x = new XXX(p);
* </pre>
* <p>
* 原因:
* 即使包名、类名完全相同,若ClassLoader对象不同,则仍会抛出类型转换异常
* 因此需要将其“重新”生成一份,等于用不同的ClassLoader生成两个对象,自然避免该问题
* <p>
* 常见于BroadcastReceiver中的Bundle,系统在判断源进程和目标进程一致时,会“透传”Bundle过来,
* 故就算设置了setClassLoader,也不会做unparcel,自然也就会导致ClassCastException了
*
* @param pa 要构造的Parcelable对象
* @return 可被构造函数使用的Parcel对象
*/
public static Parcel createFromParcelable(Parcelable pa) {
if (pa == null) {
return null;
}
Parcel p = Parcel.obtain();
pa.writeToParcel(p, 0);
p.setDataPosition(0);
return p;
}