Unable to find app for caller android.app.ApplicationThreadProxy解决方案

在项目中突然碰到一个crash,而且还经常打不出log,logcat 提示Unable to find app for caller android.app.ApplicationThreadProxy,而且在Android 5.0以下的机器常见,在网上搜了搜,stackoverFlow上给了一些解释,但是都没说到点子上,在这里贴出一个测试成功了的解决方案。

触发这个异常是在开启一个新activity的时候,经过分析应该是intent.putExtra(String,Serilizable)中,序列化对象太大了,当时app直接传输了400多个对象,而且每个对象里面又有很多的字段,过大的数据量直接导致activity在发送序列化对象的时候崩溃。

鉴于这个现象我想到了一个解决办法,就是安卓官方推荐使用的Parcelable类,这个类在安卓的定义中就是专门为activity传值而生的,可以自定义那些字段需要序列化,哪些不需要,极大的减少了数据量,然后我就试了试,居然成功了,并且性能也很不错。

那么在这里简单介绍一下Parcelable吧

Intent除了可以用putExtraString,putExtraInt等方法发送基本数据类型以外,还可以发送自己写的类的对象,但是需要进行序列化;把一个类序列化只需要实现Parcelable即可,再在这个类里面声明一个Parcelable.Creator 内部类对象;代码如下

package com.example.parcel_test;

import android.os.Parcel;
import android.os.Parcelable;

public class Person implements Parcelable{
	private String name;
	private int age;
	private boolean gendar;
	
	public Person(String name, int age, boolean gendar) {
		super();
		this.name = name;
		this.age = age;
		this.gendar = gendar;
	}
	public Person(){}
	public Person(Parcel source) {//构造方法,用于传入一个parcel解析成类
		// TODO Auto-generated constructor stub
		//在这里面可以限制哪些成员可以被序列化,哪些不会被序列化
		name = source.readString();
		age = source.readInt();
	}

	@Override
	public int describeContents() {//没搞懂有什么用,反正直接返回0也可以
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {//该方法将类的数据写入外部提供的Parcel中
		// TODO Auto-generated method stub
		//在这里面可以限制哪些成员可以被序列化,哪些不会被序列化
		dest.writeString(name);
		dest.writeInt(age);
	}
	//声明一个内部类的对象
	public static final Parcelable.Creator<Person> CREATOR //必须全为大写CREATOR
		 = new Parcelable.Creator<Person>() {

			@Override
			public Person createFromParcel(Parcel source) {//实现从source中创建出类的实例的功能
				// TODO Auto-generated method stub
				
				return new Person(source);
			}

			@Override
			public Person[] newArray(int size) {//创建一个类型为T,长度为size的数组,仅一句话(return new T[size])即可。估计本方法是供外部类反序列化本类数组使用。
				// TODO Auto-generated method stub
				return new Person[size];
			}
		};

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", gendar=" + gendar
				+ "]";
	}
		
	
}

如果一个Parcelable对象中包含了其他自定义类,那么这个里面的自定义类也要实现Parcelable接口,并且他的写法也稍有不同,并且布尔值的写法也要注意一下,下面是项目里实际应用的一段代码

 @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.id);
        dest.writeString(this.imageUrl);
        dest.writeString(this.title);
        dest.writeString(this.description);
        dest.writeString(this.createTimeStr);
        dest.writeString(this.createTime);
        dest.writeByte(this.isLike ? (byte) 1 : (byte) 0);//boolean的写法
        dest.writeInt(this.likeCount);
        dest.writeInt(this.commentCount);
        dest.writeString(this.creator);
        dest.writeInt(this.type);
        dest.writeParcelable(this.photoCredit, flags);//内置的自定义类,也要实现Parcelable接口
        dest.writeParcelable(this.photoCreditImpl, flags);//内置的自定义类,也要实现Parcelable接口
    }

 protected SVRGLCreditPhotoDishListReturnEntity(Parcel in) {
        this.id = in.readString();
        this.imageUrl = in.readString();
        this.title = in.readString();
        this.description = in.readString();
        this.createTimeStr = in.readString();
        this.createTime = in.readString();
        this.isLike = in.readByte() != 0;//布尔值的写法
        this.likeCount = in.readInt();
        this.commentCount = in.readInt();
        this.creator = in.readString();
        this.type = in.readInt();
        this.photoCredit = in.readParcelable(SVRPhotoCreditReturnEntity.class.getClassLoader());//内置的Parcelable类
        this.photoCreditImpl = in.readParcelable(SVRPhotoCreditReturnEntity.class.getClassLoader());//内置的Parcelable类
    }

一个可以序列化的类生成好了,下面可以发送了

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//用intent向activity发送对象
		Person p = new Person("小王",20,true);
		Intent intent = new Intent(this,SecondActivity.class);
		intent.putExtra("parcel", p);//这样就可以直接把对象发过去了
		startActivity(intent);
		
	}

换一个activity测试一下接收结果

public class SecondActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_second);
		//接受intent发送的对象
		Intent intent = getIntent();
		Person p2 = intent.getParcelableExtra("parcel");//接收parcel对象
		System.out.println(p2);// [name=小王, age=20, gendar=false],因为规定了成员gendar属性不参加序列化,所以打出默认值false
	}
安卓给的Parcelable要比普通的serializable接口执行速度更快,资源占用更少,而且可以规定哪些成员参与序列化,哪些不参与,减少了序列化的数据量,极为推荐使用


PS:如果觉得手写这么多字段很费事而且容易写错的话,推荐一个Android Studio插件Android Parcelable code generator,在需要变成Parcelable的类按Alt+Insert呼出菜单,选择Parcelable就可以用了,我在写这一块的时候就这么用的。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值