利用反射函数实现一键清除缓存,并获取清除的缓存数目。调用反射函数类出错java.lang.NoSuchMethodException: getPackageSizeInfo.

在实现一键清除缓存功能时,通过反射调用IPackageStatsObserver.class 出现java.lang.NoSuchMethodException: getPackageSizeInfo。错误源于使用了错误的方法获取类的构造器或方法。经过排查,问题出在getMethod()与getDeclaredMethod()的误用上。getDeclaredMethod()用于获取类自身声明的所有方法,而getMethod()则获取类的所有共有方法,包括继承和接口实现的public方法。正确使用方法解决了问题。

在开发一键清缓存的功能时,缓存清除成功,当使用反射调用IPackageStatsObserver.class 这个类时,系统提示错误:

java.lang.NoSuchMethodException: getPackageSizeInfo [class java.lang.String, interface android.content.pm.IPackageStatsObserver]
W/System.err(12295):    at java.lang.Class.getConstructorOrMethod(Class.java:460)
W/System.err(12295):    at java.lang.Class.getDeclaredMethod(Class.java:685)


字面意思很简单没有找到该方法,但是查看我的源码,包导入正常,

只能查看自己的代码,找到出错的位置

	/**
	 * 取得指定包名的程序的缓存大小
	 */
	private void queryPkgCacheSize(String pkgName) throws Exception {
		if (!TextUtils.isEmpty(pkgName)) {// pkgName不能为空
			// 使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo
			if (mPackageManager == null) {
				mPackageManager = getContext().getPackageManager();// 得到被反射调用函数所在的类对象
			}
			try {
				// the requested method's name.
				String strGetPackageSizeInfo = "getPackageSizeInfo";
				// 通过反射机制获得该隐藏函数
				Method getPackageSizeInfo = mPackageManager.getClass()
						.getDeclaredMethod(strGetPackageSizeInfo, String.class,// getPackageSizeInfo方法的参数类型
								IPackageStatsObserver.class);// getPackageSizeInfo方法的参数类型
				// 调用该函数,并且给其分配参数 ,待调用流程完成后会回调PkgSizeObserver类的函数
				getPackageSizeInfo.invoke(mPackageManager,// 方法所在的类
						pkgName, mStatsObserver);// 方法使用的参数

			} catch (Exception ex) {
				Log.wtf("tag", "queryPkgSize()-->NoSuchMethodException");
				ex.printStackTrace();
				throw ex; // 抛出异常
			}
		}
	}
.getDeclaredMethod()
方法报错的。

经查看,我调用反射类IPackageDataObserver.class;却没有报错,调用方法为

	/**
	 * 执行清除缓存操作
	 */
	private void clearCache() {
		totalCacheSize = 0l;// 初始化
		queryToatalCache();// 给cacheSize赋值
		try {
			if (mPackageManager == null) {
				mPackageManager = getContext().getPackageManager();// 得到被反射调用函数所在的类对象
			}
			String methodName = "freeStorageAndNotify";// 想通过反射机制调用的方法名
			Class<?> parameterType1 = Long.TYPE;// 被反射的方法的第一个参数的类型
			Class<?> parameterType2 = IPackageDataObserver.class;// 被反射的方法的第二个参数的类型
			Method freeStorageAndNotify = mPackageManager.getClass().getMethod(
					methodName, parameterType1, parameterType2);
			/*
			 * freeStorageSize : The number of bytes of storage to be freed by
			 * the system. Say if freeStorageSize is XX, and the current free
			 * storage is YY, if XX is less than YY, just return. if not free
			 * XX-YY number of bytes if possible.
			 */
			Long freeStorageSize = Long.valueOf(getDataDirectorySize());

			freeStorageAndNotify.invoke(mPackageManager, freeStorageSize,
					new IPackageDataObserver.Stub() {
						@Override
						public void onRemoveCompleted(String packageName,
								boolean succeeded) throws RemoteException {
						}
					});
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

获取方法时用的是:
getMethod()

果断试试换种写法:

	/**
	 * 取得指定包名的程序的缓存大小
	 */
	private void queryPkgCacheSize(String pkgName) throws Exception {
		if (!TextUtils.isEmpty(pkgName)) {// pkgName不能为空
			// 使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo
			if (mPackageManager == null) {
				mPackageManager = getBaseContext().getPackageManager();// 得到被反射调用函数所在的类对象
			}
			try {
				String methodName = "getPackageSizeInfo";// 想通过反射机制调用的方法名
				Class<?> parameterType1 = String.class;// 被反射的方法的第一个参数的类型
				Class<?> parameterType2 = IPackageStatsObserver.class;// 被反射的方法的第二个参数的类型
				Method getPackageSizeInfo = mPackageManager.getClass().getMethod(
						methodName, parameterType1, parameterType2);
				getPackageSizeInfo.invoke(mPackageManager,// 方法所在的类
				pkgName, mStatsObserver);// 方法使用的参数

			} catch (Exception ex) {
				Log.wtf("tag", "queryPkgSize()-->NoSuchMethodException");
				ex.printStackTrace();
				throw ex; // 抛出异常
			}
		}
	}
	
	/**
	 * 使用Android系统中的AIDL文件,获得指定程序的大小。AIDL文件形成的Binder机制
	 */
	private IPackageStatsObserver.Stub mStatsObserver = new IPackageStatsObserver.Stub() {
		@Override
		public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
				throws RemoteException {
			long tmp = totalCacheSize;
			totalCacheSize += pStats.cacheSize;// 累加
			if (tmp != totalCacheSize) {// 总缓存大小有变化
				mHandler.sendEmptyMessage(MSG_UPDATE_TOAST_TEXT);
			}
		}
	};

果然,
totalCacheSize
就能获取到相对应的数值。

问题解决。不过,我也没发现这个

getMethod()
getDeclaredMethod()
差异性在哪里?

getDeclaredMethod*()获取的是类自身声明的所有方法,包含public、protected和private方法。

getMethod*()获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。

 

平常没留心,这时候很容易出错。这两个不是可以随意更换的。


上源码:http://download.csdn.net/detail/yql44137228/7676871




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值