为什么Android AppOps(隐私管理器)在用户更改其隐私设置时发送重复事件?
当用户通过AppOps更改其隐私设置(例如,拒绝应用程序访问电话联系人)时,AppOpsManager会将用户更改的内容(例如程序包名称和操作(例如,读取联系人))发送给任何人 所以我写了一个听众来这样做。但是,我们用户只做了一次更改,我收到了太多重复事件(例如,用户决定拒绝愤怒的小鸟访问他/她的位置的10个事件),然后应用程序崩溃 下面是我为每对包和操作注册listners的代码:为什么Android AppOps(隐私管理器)在用户更改其隐私设置时发送重复事件?,android,listener,Android,Listener,当用户通过AppOps更改其隐私设置(例如,拒绝应用程序访问电话联系人)时,AppOpsManager会将用户更改的内容(例如程序包名称和操作(例如,读取联系人))发送给任何人 所以我写了一个听众来这样做。但是,我们用户只做了一次更改,我收到了太多重复事件(例如,用户决定拒绝愤怒的小鸟访问他/她的位置的10个事件),然后应用程序崩溃 下面是我为每对包和操作注册listners的代码: public void startWatchingOperations(AppOpsManager appOps
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();
}
}
}
她是apppsmanager.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) {
}
}
}
公共类AppOpsManager{
最终哈希映射
=新HashMap();
public void startWatchingMode(int-op、字符串packageName、最终回调){
已同步(MMO脱水器){
IAppOpsCallback cb=mModeWatchers.get(回调);
如果(cb==null){
cb=新的IAppOpsCallback.Stub(){
public void opChanged(int-op,String-packageName){
opChanged(op,packageName);
}
};
mModeWatchers.put(回调,cb);
}
试一试{
mService.startWatchingMode(op、packageName、cb);
}捕获(远程异常){
}
}
}
我仔细检查以确保从未为每对包和操作分配过多个侦听器
我希望得到关于潜在原因的提示
尝试将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();
}
}
public void startWatchingOperations(AppOpsManager appOps,List opsforapps){
更改PrivacySettingsListener OpsListener;
SharedReferences myAppListnerPreferences=GetSharedReferences(应用程序操作首选项,活动模式\私有);
对于(AppOpsManager.PackageOps o:OpsFrapps){
List opEntry=o.getOps();
//如果我已经为这个部分的包和操作分配了一个侦听器,那么跳过
if(myAppListnerPreferences.getBoolean(o.getPackageName(),false)==false){
for(OpEntry条目:OpEntry){
//对于每对包和操作,分配一个新的侦听器
opsListner=newchangePrivacySettingsListener(getApplicationContext());
appOps.startWatchingMode(entry.getOp()、o.getPackageName()、opsListner);
}
myAppListnerPreferences.edit().putBoolean(o.getPackageName(),true.apply();
}
}
}
请告诉我发生了什么事?以防万一,这对某些人(至少是Android Oreo)调用AppsManager会有帮助。startWatchingMode(op,packageName,callback)将导致在更改任何包的
op
的设置时调用回调
(1)和(2)对于任何AppOps设置更改,请使用packageName
。这可以从AppOpsService.java
源代码中看到,尤其是注册回调的AppOpsService.startWatchingMode()
,它在AppOps设置更改时调用回调
例如,如果使用startWatchingMode(appOps1,package1,callback)
和startWatchingMode(appOps2,package1,callback)
注册回调,
当package1
的appOps3
设置发生更改时,回调将被调用两次,因为您已为package1
注册了两次。如果appOps1
为package1
更改,回调将被调用三次,因为您已为appOps1注册了一次代码>,两次用于程序包1
解决方案是使用packageName
参数设置为null
注册您感兴趣的appop集(无重复),或者使用op
参数设置为AppOpsManager.op\u NONE
注册您感兴趣的包集
此外,您还需要确保使用stopWatchingMode
注销所有侦听器(例如,在活动的ondestory
中)。否则,回调项将在活动生命周期内累积(直到应用程序终止)您将开始获得副本。这也意味着您应该保留对创建的所有侦听器的引用。谢谢@BasemAljedai。它解决了一半问题。应用程序不再崩溃。但是,当用户更改其设置时,我仍然会收到副本。我原以为声明的位置并不重要,但显然我错了。
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();
}
}