当用户通过AppOps更改他/她的隐私设置时(例如,拒绝应用程序访问电话联系人),AppOpsManager会向听取用户更改内容的任何人发送(即包名称和操作(例如,阅读联系人))
所以我写了一个听众来这样做。但是,我们用户只进行了一次更改,我收到了太多重复事件(例如,用户决定拒绝愤怒的Bird访问他/她的位置的10个事件),然后应用程序崩溃。
这是我的代码,为每对包&注册列表器。操作:
public void startWatchingOperations(AppOpsManager appOps, List<AppOpsManager.PackageOps> opsforapps) {
SharedPreferences myAppListnerPreferences = getSharedPreferences(APP_OPS_PREFERENCES, Activity.MODE_PRIVATE);
for (AppOpsManager.PackageOps o:opsforapps) {
List<OpEntry> opEntry = o.getOps();
//if I already assigned a listener to this pari of package & operation, then skip
if (myAppListnerPreferences.getBoolean(o.getPackageName(), false)==false) {
for (OpEntry entry:opEntry) {
//for each pair of package & operation, assign a new listener
ChangePrivacySettingsListener opsListner = new ChangePrivacySettingsListener(getApplicationContext());
appOps.startWatchingMode(entry.getOp(),o.getPackageName(),opsListner);
}
myAppListnerPreferences.edit().putBoolean(o.getPackageName(), true).apply();
}
}
}
以下是听众的片段
public class ChangePrivacySettingsListener implements AppOpsManager.Callback {
public void opChanged(int op, String packageName) {
AppOpsManager appOps= (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
PackageManager pkg = context.getPackageManager();
try {
//this is an object to store the event: package name,
// the operation that has been changed, & time stamp
PrivacySetting privacySetting = new PrivacySetting();
privacySetting.setPackageName(packageName);
privacySetting.setOperation(OPERATIONS_STRINGS[op]);
privacySetting.setDecisionTime(Calendar.getInstance(TimeZone.getDefault()).getTimeInMillis());
privacySetting.setUserId(userId);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
她是AppOpsManager.java的一部分,可以让我听取用户的更改。
public class AppOpsManager {
final HashMap<Callback, IAppOpsCallback> mModeWatchers
= new HashMap<Callback, IAppOpsCallback>();
public void startWatchingMode(int op, String packageName, final Callback callback) {
synchronized (mModeWatchers) {
IAppOpsCallback cb = mModeWatchers.get(callback);
if (cb == null) {
cb = new IAppOpsCallback.Stub() {
public void opChanged(int op, String packageName) {
callback.opChanged(op, packageName);
}
};
mModeWatchers.put(callback, cb);
}
try {
mService.startWatchingMode(op, packageName, cb);
} catch (RemoteException e) {
}
}
}
我仔细检查以确保我从未为每对包装分配过多个监听器&amp;操作。
我很欣赏有关潜在原因的提示。
答案 0 :(得分:0)
尝试将ChangePrivacySettingsListener opsListner的减速度移到for块的外边:
public void startWatchingOperations(AppOpsManager appOps, List<AppOpsManager.PackageOps> opsforapps) {
ChangePrivacySettingsListener opsListner;
SharedPreferences myAppListnerPreferences = getSharedPreferences(APP_OPS_PREFERENCES, Activity.MODE_PRIVATE);
for (AppOpsManager.PackageOps o:opsforapps) {
List<OpEntry> opEntry = o.getOps();
//if I already assigned a listener to this pari of package & operation, then skip
if (myAppListnerPreferences.getBoolean(o.getPackageName(), false)==false) {
for (OpEntry entry:opEntry) {
//for each pair of package & operation, assign a new listener
opsListner = new ChangePrivacySettingsListener(getApplicationContext());
appOps.startWatchingMode(entry.getOp(),o.getPackageName(),opsListner);
}
myAppListnerPreferences.edit().putBoolean(o.getPackageName(), true).apply();
}
}
}
请告诉我发生了什么?
答案 1 :(得分:0)
如果这对某人有帮助,至少是Android Oreo,调用AppOpsManager.startWatchingMode(op, packageName, callback)
会在callback
的设置更改(1)时调用op
对于任何包, AND (2),任何AppOps设置都会更改packageName
。这可以从AppOpsService.java
来源看到,特别是AppOpsService.startWatchingMode()
注册回调,AppOpsService.setMode()
在AppOps设置更改时调用回调。
例如,如果您使用startWatchingMode(appOps1, package1, callback)
和startWatchingMode(appOps2, package1, callback)
注册回调,
当appOps3
package1
的设置发生变化时,由于您已注册package1
两次,因此将回调两次回调。如果appOps1
的{{1}}发生了变化,则回调将被调用3次,因为您已为package1
注册了一次,而appOps1
则注册了两次。
解决方案是注册您感兴趣的AppOps(没有重复),package1
参数设置为packageName
,或者注册您感兴趣的一组包,null
参数设置为op
。
此外,您需要使用AppOpsManager.OP_NONE
确保所有侦听器都未注册(例如,在您的onDestroy
活动中)。否则,回调条目将在活动生命周期中累积(直到应用程序终止),您将开始获取重复项。这也意味着您应该保留对所有已创建的侦听器的引用。