今天在修改以前的项目的时候,碰到了两个坑,一个是动态权限申请的时候,发现相机的权限老是申请不下来,其他权限都可以正常申请,就是相机的权限有问题,后面发现其实不只是相机,第二个是关于ExpandableListView和BaseExpandableListAdapter的使用,**特别是在BaseExpandableListAdapter的view中含有checkbox的时候**,需要注意很多问题。
先来说第一个,关于动态权限申请的问题,这个问题其实很简单,但是为什么会出现相机的权限老是申请不下来呢,是因为我只是在需要这个权限的时候去动态申请的,但是我并没有在AndroidManifest.xml中去注册这个权限,所以导致每次动态申请的时候都会直接返回-1,也就是用户不同意授权,以下是我在动态权限申请的时候使用的代码,先记录下来,后面也可以直接使用:
首先判断是否需要动态申请权限,Android6.0以上的系统需要动态申请权限,同时,有的权限可能用户之前已经授予了,也要判断一下
private void checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String[] permissions = {Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};
for (int i = 0; i < permissions.length; i++) {
int allow = ContextCompat.checkSelfPermission(this, permissions[i]);
if (allow != PackageManager.PERMISSION_GRANTED) {
showToast("应用需要您的相机和存储权限以更新您的头像");
startRequestPermission(permissions);
return;
}
}
showChooseCamera();
}else{
showChooseCamera();
}
}
当判断到需要动态申请权限的时候去请求权限
private void startRequestPermission(String[] permissions) {
ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_CODE);
}
申请权限之后会回调onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)这个方法,在这个方法里面判断用户是否授予了权限
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION_CODE) {
for (int i = 0; i < grantResults.length; i++) {
Log.i("TAG", "获取权限的回调是:" +permissions[i]+":" +grantResults[i]+",授予权限是:"+PackageManager.PERMISSION_GRANTED);
}
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
if (!shouldShowRequestPermissionRationale(permissions[0])) {
showToast("请手动到设置界面授予权限");
} else {
finish();
}
} else {
showChooseCamera();
showToast("获取权限成功");
}
}
}
上面就是我动态申请权限的代码,在此记录一下,方便后面使用。需要注意的是:**动态权限也是要在AndroidManifest.xml文件中注册的,如果不注册的话,在系统设置里面是找不到这个权限的,同时动态申请的时候会直接返回-1,告诉你用户拒绝授予权限**。
关于第二个问题,也就是ExpandableListView和BaseExpandableListAdapter,这个是在做类似于淘宝中的购物车页面的时候遇到了一些问题,主要是checkbox的问题,在此先记录下问题以及解决方案,后面会专门针对购物车这一块写一篇博客。
(1)首先来说ExpandableListView适用的场景,因为一般的购物车都包括商铺信息和商品信息,也就是一个商铺信息下面有很多商品信息,而商铺信息也是很多的,之前想过使用ExpandableListView的方式来做,但是感觉比较麻烦,后来就使用在一个ListView里面嵌套另一个ListView来做,但是界面比较卡顿,而且比如像勾选了店铺之后,该店铺下面的所有的商品也要自动勾选上,当一个店铺下面所有的商品都已经勾选的时候,这个商铺要自动勾选上等,这些需要都比较难实现,所以最后还是选择使用ExpandableListView来做这一块,做完之后发现ExpandableListView真的挺好用的,最起码界面滑动等不卡顿了,各种信息也能清楚的展示。
(2)具体来说问题,第一个问题就是:ExpandableListView需要默认处于打开状态,而且点击父view的时候不能关闭,同时去掉父view前面的箭头,这些问题都是在网上找到的解决方案,感谢广大网友:
private void openAllExpandView(){
shopBagExpandAdapter.setData(model);
shopBagExpandAdapter.notifyDataSetChanged();
for(int i = 0; i < mContent.getCount(); i++) {
mContent.expandGroup(i);
}
mContent.setGroupIndicator(null);
mContent.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) {
return true;
}
});
}
(3)第二个问题就是在我的父view和子view中都出现了checkbox,由于ListView的优化和复用机制,导致当一部分checkbox滑出屏幕的时候,如果这些checkbox处于选中的状态,再次滑回来会回到没有选中的状态,导致数据出现混乱。对于这个问题的解决方案是在填充ExpandableListView的数据集中,加一个参数,用来指定当前的item是否处于选中的状态,每次根据这个值来对ExpandableListView的状态进行判断,不管是父view还是子view都可以通过这种方式实现。
(4)第三个问题在于checkbox的状态监听,不能使用OnCheckedChangeListener这个接口去监听checkbox的状态,使用这个接口监听还是会造成数据混乱。但是checkbox还是要切换状态,这里有两种方式,第一种就是对checkbox添加点击事件的监听,第二个方法是对checkbox所在的布局添加点击事件的监听,这两种方法还是有一点区别的,因为一般使用checkbox.setChecked(true/false)来设置checkbox的选中状态,那在设置之前就要知道当前的checkbox是选中还是没选中,可以通过checkbox.isChecked()来获取当前checkbox的选中状态,第一种方式是点击之后checkbox已经改变了,直接使用isChecked()获取到的值即可,第二种方式由于不是在checkbox上点击,所以获取到的是还没有改变的值,需要取反。也就是:第一种方式不需要setChecked()来设置选中状态,要设置的话就是用checkbox.setChecked(checkbox.isChecked()),第二种方式需要手动设置checkbox的选中状态,checkbox.setChecked(!checkbox.isChecked())
(5)第四个问题在于界面更新,其实简单的使用notifyDataSetChanged()就可以更新界面了,网上很多人说的打开关闭一次父view个人感觉并不靠谱,因为前面设置了父view永远处于打开状态,所以导致使用这种方式的话会出现getChildCount()下标越界异常,因为父view处于选中状态的时候子view也要跟着改变,所以一般来说,如果设置没有问题的话,父view选中状态后,使用notifyDataSetChanged()可以直接更新界面,没有任何问题,同理,子view改变父view要更新界面也是一样,使用notifyDataSetChanged()完全可以了。
(6)后面项目中还遇到了一些其他问题,不过都是一些逻辑上的问题,还有一些记不起来了,暂时就到这里,关于购物车页面我会在下一篇博客更新。