填坑与求解惑来的.
一, Android 危险权限, 来自官方文档的坑???
Android 开发者都知道, Android 6.0 之前, 权限申请只需要在 AndroidManifest.xml 文件中声明就可以. Android 6.0 开始, 权限申请发生了变化, 危险权限需要在应用中动态申请, 之前写过一篇 Android 动态申请危险权限的笔记, 详情参考: Android 6.0 动态申请危险权限.
先截个图, 看看 Android 官方的说明:
再看危险权限的分组情况:
意思是, 对危险权限进行了分组, 同一组中, 只要有有一个权限被授权了, 同组中其它权限也就默认授权了. 比如, 我授权应用有读存储卡的权限之后, 应用也就有了写存储卡的权限, 事实上也确实如此.
然而问题来了, 利用 GPS 获取位置信息的代码:
- LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
- if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
- if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
- (MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION)
- != PackageManager.PERMISSION_GRANTED){
- // request permissions
- // ...
- // ...
- }else{
- Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER;
- if(location != null){
- double latitude = location.getLatitude();
- double longitude = location.getLongitude();
- }
- }
- }
通过官方的危险权限组, 我们也能看到: Location 权限组里包含:
ACCESS_FINE_LOCATION
和
ACCESS_COARSE_LOCATION
两个权限, 按照上面的说明, 两个权限只要有一个申请授权成功, 即可成功获取经纬度.-- 然鹅, 当成功申请了
ACCESS_COARSE_LOCATION
权限后, 程序依然会崩, 错误信息提示, 需要获得
ACCESS_FINE_LOCATION
权限 .
二, Spinner 的 setSelection() 方法, 源于自己想当然的坑!!!
Android 中的下拉列表控件 spinner 有一个方法 setSelection(int position) , 显示第几项. 此方法可能没有效果??? 总是显示第一项???
------------------------------------ 分割线 ----------------------------------
当在做两个 spinner 联动时, spinner2 依据 spinner1 的选择填充数据, 然后使用 setSeletion(2) 来设置默认项. 结果发现: spinner2 显示的总是第一项, 但是实际选择的确实已经是 position 2 的位置 .
解决方法:
旧代码:
- spinner.setAdapter(adapter);
- spinner.setSelection(2);
解决方案有二:
- (1)
- spinner.setAdapter(adapter);
- spinner.setSelection(2,true); //spinner 会重新 layout
(2) 推荐
- spinner.setAdapter(adapter);![](https://images2018.cnblogs.com/blog/758949/201807/758949-20180726224508174-131546620.jpg)
- adapter.notifyDataSetChanged(); // 通知 spinner 刷新数据
- spinner.setSelection(2);
那么, 这到底是什么原因造成的? 我认为这是一个 bug . 这种情况通常发生在重新填充数据之后, 除此之外, 使用 setSelection(int position) 都能得到正确的显示.
setSelection(int position, boolean animate) 和 setSelection(int position) 实现机制有较大区别, 当调用前者时重新 layout, 立即触发 onItemSelected 函数, 作用相当于用手直接点击. 而后者设置了下次选择位置: setNextSelectedPositionInt(position); 然后请求 Layout;, 而 requestLayout 并非立即执行, 仅仅是一个 schedule. 但是后者可能在重新装载数据然后 Layout 时丢失了某些状态.
以上分割线中内容系转载: 原文链接: https://www.xuebuyuan.com/672724.html
------------------------------------- 分割线 ------------------------------------------
然鹅, 我要说的坑不是这样, 我没有两个 Spinner 联动, 我出现的问题是这样的, 上代码
布局文件:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="com.example.sharpcj.helloworld.MainActivity">
- <Spinner
- android:id="@+id/sp_test"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true">
- </Spinner>
- </RelativeLayout>
java 代码:
- package com.example.sharpcj.helloworld;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.widget.ArrayAdapter;
- import android.widget.Spinner;
- import java.util.Arrays;
- public class MainActivity extends AppCompatActivity {
- private Spinner mSpTest;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- String[] strs = new String[20];
- for (int i = 0; i <strs.length; i++) {
- strs[i] = "第" + i + "项";
- }
- mSpTest = findViewById(R.id.sp_test);
- mSpTest.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, strs));
- int index = Arrays.binarySearch(strs, "第 11 项");
- mSpTest.setSelection(index);
- }
- }
运行结果:
what???
为什么会这样呢? spinner 表示这个锅它不背, 其实这个坑怪我自己想当然了, 原因在于错误地使用了
Arrays.binarySearch(Object[] a , Object key)
这个方法, 想当然地认为了返回值为查找到数组的 index. 代码中, index 的实际值是 -2 .
网上找了一下资料:
binarySearch(int[] a, int key)
此方法的规则是这样的:
1, 如果找到关键字, 则返回值为关键字在数组中的位置索引, 且索引从 0 开始
2, 如果没有找到关键字, 返回值为负的插入点值, 所谓插入点值就是第一个比关键字大的元素在数组中的位置索引, 而且这个位置索引从 1 开始.
而
binarySearch(Object[] a, Object key)
最终调用方法的源码如下:
- // Like public version, but without range checks.
- private static int binarySearch0(Object[] a, int fromIndex, int toIndex,
- Object key) {
- int low = fromIndex;
- int high = toIndex - 1;
- while (low <= high) {
- int mid = (low + high)>>> 1;
- @SuppressWarnings("rawtypes")
- Comparable midVal = (Comparable)a[mid];
- @SuppressWarnings("unchecked")
- int cmp = midVal.compareTo(key);
- if (cmp <0)
- low = mid + 1;
- else if (cmp> 0)
- high = mid - 1;
- else
- return mid; // key found
- }
- return -(low + 1); // key not found.
- }
关于 Object 类型, Oracle 大神写的这个二分法寻找索引的代码暂时没看懂.
来源: https://www.cnblogs.com/joy99/p/9374931.html