淺析Android位置權(quán)限以及數(shù)組尋找索引的坑
一、Android 危險(xiǎn)權(quán)限,來(lái)自官方文檔的坑
Android開(kāi)發(fā)者都知道,Android 6.0 之前,權(quán)限申請(qǐng)只需要在 AndroidManifest.xml 文件中聲明就可以。Android 6.0 開(kāi)始,權(quán)限申請(qǐng)發(fā)生了變化,危險(xiǎn)權(quán)限需要在應(yīng)用中動(dòng)態(tài)申請(qǐng),之前寫過(guò)一篇 Android 動(dòng)態(tài)申請(qǐng)危險(xiǎn)權(quán)限的筆記,詳情參考: Android 6.0 動(dòng)態(tài)申請(qǐng)危險(xiǎn)權(quán)限。
先截個(gè)圖,看看Android官方的說(shuō)明:

再看危險(xiǎn)權(quán)限的分組情況:

意思是,對(duì)危險(xiǎn)權(quán)限進(jìn)行了分組,同一組中,只要有有一個(gè)權(quán)限被授權(quán)了,同組中其它權(quán)限也就默認(rèn)授權(quán)了。比如,我授權(quán)應(yīng)用有讀存儲(chǔ)卡的權(quán)限之后,應(yīng)用也就有了寫存儲(chǔ)卡的權(quán)限,事實(shí)上也確實(shí)如此。
然而問(wèn)題來(lái)了,利用 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();
}
}
}
通過(guò)官方的危險(xiǎn)權(quán)限組,我們也能看到:Location 權(quán)限組里包含:ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 兩個(gè)權(quán)限,按照上面的說(shuō)明,兩個(gè)權(quán)限只要有一個(gè)申請(qǐng)授權(quán)成功,即可成功獲取經(jīng)緯度。——然鵝,當(dāng)成功申請(qǐng)了 ACCESS_COARSE_LOCATION 權(quán)限后,程序依然會(huì)崩,錯(cuò)誤信息提示,需要獲得 ACCESS_FINE_LOCATION 權(quán)限 。
二、Spinner 的 setSelection() 方法,源于自己想當(dāng)然的坑
Android 中的下拉列表控件 spinner 有一個(gè)方法 setSelection(int position) ,顯示第幾項(xiàng)。此方法可能沒(méi)有效果???總是顯示第一項(xiàng)???
當(dāng)在做兩個(gè)spinner聯(lián)動(dòng)時(shí),spinner2依據(jù)spinner1的選擇填充數(shù)據(jù),然后使用setSeletion(2)來(lái)設(shè)置默認(rèn)項(xiàng)。結(jié)果發(fā)現(xiàn):spinner2顯示的總是第一項(xiàng),但是實(shí)際選擇的確實(shí)已經(jīng)是position 2的位置 。
解決方法:
舊代碼:
spinner.setAdapter(adapter); spinner.setSelection(2);
解決方案有二:
(1)
spinner.setAdapter(adapter); spinner.setSelection(2,true); //spinner會(huì)重新layout
(2) 推薦
spinner.setAdapter(adapter); adapter.notifyDataSetChanged(); //通知spinner刷新數(shù)據(jù) spinner.setSelection(2);
那么,這到底是什么原因造成的?我認(rèn)為這是一個(gè)bug 。這種情況通常發(fā)生在重新填充數(shù)據(jù)之后,除此之外,使用setSelection(int position)都能得到正確的顯示。
setSelection(int position, boolean animate)和setSelection(int position) 實(shí)現(xiàn)機(jī)制有較大區(qū)別,當(dāng)調(diào)用前者時(shí)重新layout,立即觸發(fā)onItemSelected函數(shù),作用相當(dāng)于用手直接點(diǎn)擊。而后者設(shè)置了下次選擇位置:setNextSelectedPositionInt(position); 然后請(qǐng)求Layout;,而requestLayout并非立即執(zhí)行,僅僅是一個(gè)schedule。但是后者可能在重新裝載數(shù)據(jù)然后Layout時(shí)丟失了某些狀態(tài)。
然鵝,我要說(shuō)的坑不是這樣,我沒(méi)有兩個(gè) Spinner 聯(lián)動(dòng),我出現(xiàn)的問(wèn)題是這樣的,上代碼
布局文件:
<?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 + "項(xiàng)";
}
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項(xiàng)");
mSpTest.setSelection(index);
}
}
運(yùn)行結(jié)果:

what???
為什么會(huì)這樣呢? spinner 表示這個(gè)鍋它不背,其實(shí)這個(gè)坑怪我自己想當(dāng)然了,原因在于錯(cuò)誤地使用了 Arrays.binarySearch(Object[] a , Object key) 這個(gè)方法,想當(dāng)然地認(rèn)為了返回值為查找到數(shù)組的 index。代碼中, index 的實(shí)際值是 -2 。
網(wǎng)上找了一下資料:
binarySearch(int[] a, int key) 此方法的規(guī)則是這樣的:
1、如果找到關(guān)鍵字,則返回值為關(guān)鍵字在數(shù)組中的位置索引,且索引從0開(kāi)始
2、如果沒(méi)有找到關(guān)鍵字,返回值為負(fù)的插入點(diǎn)值,所謂插入點(diǎn)值就是第一個(gè)比關(guān)鍵字大的元素在數(shù)組中的位置索引,而且這個(gè)位置索引從1開(kāi)始。
而binarySearch(Object[] a, Object key) 最終調(diào)用方法的源碼如下:
// 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.
}
關(guān)于 Object 類型,Oracle 大神寫的這個(gè)二分法尋找索引的代碼暫時(shí)沒(méi)看懂。
- android仿微信聯(lián)系人索引列表功能
- Android ItemDecoration 實(shí)現(xiàn)分組索引列表的示例代碼
- android仿微信通訊錄搜索示例(匹配拼音,字母,索引位置)
- Android 實(shí)現(xiàn)帶字母索引的側(cè)邊欄功能
- Android自定義View實(shí)現(xiàn)通訊錄字母索引(仿微信通訊錄)
- Android通用索引欄實(shí)現(xiàn)代碼
- Android手機(jī)聯(lián)系人帶字母索引的快速查找
- Android手機(jī)聯(lián)系人快速索引(手機(jī)通訊錄)
- android將搜索引擎設(shè)置為中國(guó)雅虎無(wú)法搜索問(wèn)題解決方法
- android 左右滑動(dòng)+索引圖標(biāo)實(shí)現(xiàn)方法與代碼
- Android 解決游戲發(fā)行切包資源索引沖突的問(wèn)題
相關(guān)文章
Android實(shí)現(xiàn)動(dòng)態(tài)高斯模糊背景效果
在現(xiàn)代 Android UI 中,動(dòng)態(tài)高斯模糊背景 常見(jiàn)于對(duì)話框或彈窗后面的模糊遮罩,相比靜態(tài)模糊圖,動(dòng)態(tài)模糊可隨著內(nèi)容滾動(dòng)或變化實(shí)時(shí)更新,使界面更具層次感與沉浸感,所以本文給大家介紹了Android實(shí)現(xiàn)動(dòng)態(tài)高斯模糊背景效果,需要的朋友可以參考下2025-04-04
基于Android studio3.6的JNI教程之opencv實(shí)例詳解
這篇文章主要介紹了基于Android studio3.6的JNI教程之opencv實(shí)例詳解,本文通過(guò)實(shí)例代碼截圖的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
Android編程出現(xiàn)Button點(diǎn)擊事件無(wú)效的解決方法示例
這篇文章主要介紹了Android編程出現(xiàn)Button點(diǎn)擊事件無(wú)效的解決方法,結(jié)合實(shí)例形式分析了Android編程中出現(xiàn)Button點(diǎn)擊事件無(wú)效的原因及相關(guān)的解決方法,需要的朋友可以參考下2018-02-02
Android仿微博加載長(zhǎng)圖滾動(dòng)查看效果
這篇文章主要為大家詳細(xì)介紹了Android仿微博加載長(zhǎng)圖滾動(dòng)查看效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
Android?WebView升級(jí)詳細(xì)操作指南
Android的WebView差異化很嚴(yán)重,下面這篇文章主要給大家介紹了關(guān)于Android?WebView升級(jí)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-07-07
Android fragment 轉(zhuǎn)場(chǎng)動(dòng)畫創(chuàng)建步驟
在 Android 中,可以使用 setCustomAnimations() 方法來(lái)繪制自定義的 Fragment 轉(zhuǎn)場(chǎng)動(dòng)畫,本文分步驟給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-03-03
Android編程實(shí)現(xiàn)自定義title功能示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)自定義title功能,結(jié)合具體實(shí)例形式分析了Android自定義title的具體實(shí)現(xiàn)步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-03-03
Android自定義控件實(shí)現(xiàn)簡(jiǎn)單的輪播圖控件
這篇文章主要介紹了Android自定義控件實(shí)現(xiàn)簡(jiǎn)單的輪播圖控件的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-04-04

