編輯:關於Android編程
android6.0開始,權限的申請發生了改變,申請變的動態化,也就是運行時權限,和iOS相仿,動態化的意思是指,在每次使用需要危險權限的方法的時候,需要檢查程序是否獲得了該權限的許可。動態化的權限申請能夠讓用戶更加清晰的知道程序需要什麼權限,以及程序中哪些地方的操作需要涉及用戶安全。不再是僅僅在程序安裝的時候,一次性把所需要的普通的、危險級別的權限一次性列出來,然後展示給用戶。
當工程項目的target Sdk為23時,由於考慮到用戶如果沒有進行權限的動態檢查,那麼在運行到需要權限的代碼時,會發生crash,而當你的target Sdk為23以下時,則不強制要求權限的動態監測,此時app不會crash,還是可以正常的使用功能。
Google官網上動態申請權限的方法分了在Activity和Fragment這兩種,通過ContextCompat以及子類,ActivityCompat和FragmentCompat去進行權限的申請和權限的檢查,而申請的方式是彈出一個系統的不可以改寫的對話框,結果是通過Activity和Fragment的onRequestPermissionResult()方法進行返回。
具體可以參考官網
但是這種代碼會促使以前的工程進行大改造或者說代碼的邏輯會耦合的寫在同一個方法裡,顯的不方便和臃腫。所以以下的EasyPermissionUtil就是簡化權限請求的方式,同時可以使代碼的邏輯更加清晰。
由於權限的請求和結果的返回需要分開Activity和Fragment兩種去進行操作,這樣會比較麻煩,所以EasyPermissionUtil中投機取巧,通過開啟一個新的activity進行權限申請和檢查的操作,這樣不用去區分多種情況,同時也能夠把所有的申請過程和結果統一由EasyPermissionUtil進行處理。
接下來看一下整體的思想:
PermissionUtil.getInstance().request(MainActivity.this, new String[]{Manifest.permission.READ_CALENDAR}, mRequestCode,
new PermissionResultCallBack() {
@Override
public void onPermissionGranted() {
// 當所有權限的申請被用戶同意之後,該方法會被調用
}
@Override
public void onPermissionDenied(String... permissions) {
// 當權限申請中的某一個或多個權限,被用戶曾經否定了,並確認了不再提醒時,也就是權限的申請窗口不能再彈出時,該方法將會被調用
}
@Override
public void onRationalShow(String... permissions) {
// 當權限申請中的某一個或多個權限,被用戶否定了,但沒有確認不再提醒時,也就是權限窗口申請時,但被否定了之後,該方法將會被調用.
}
});
項目源碼下載以及介紹,請看github。
在PermissionUtil中,要做的是:
1.進行權限檢查
2.沒有得到權限許可的進行權限申請
3.返回權限申請的結果
public class PermissionUtil {
private PermissionResultCallBack mPermissionResultCallBack;
private volatile static PermissionUtil instance;
private int mRequestCode;
private Context mContext;
private Fragment mFragment;
private List mPermissionListNeedReq;
private String[] mPermissions;
public static PermissionUtil getInstance() {
if (instance == null) {
synchronized (PermissionUtil.class) {
if (instance == null) {
instance = new PermissionUtil();
}
}
}
return instance;
}
/**
* 用於fragment中請求權限
* @param fragment
* @param permissions
* @param requestCode
* @param callBack
*/
public void request(@NonNull Fragment fragment,@NonNull String[] permissions,@NonNull int requestCode, PermissionResultCallBack callBack) {
this.mFragment = fragment;
this.request(fragment.getActivity(), permissions, requestCode, callBack);
}
/**
* 用於activity中請求權限
* @param context
* @param permissions
* @param requestCode
* @param callBack
*/
public void request(@NonNull Context context,@NonNull String[] permissions,@NonNull int requestCode, PermissionResultCallBack callBack) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new RuntimeException("request permission only can run in MainThread!");
}
if (permissions.length == 0) {
return;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
onGranted();
return;
}
this.mContext = context;
this.mPermissions = permissions;
this.mRequestCode = requestCode;
this.mPermissionResultCallBack = callBack;
this.mPermissionListNeedReq = new ArrayList();
if (needToRequest()) {
requestPermissions();
} else {
onGranted();
}
}
/**
* 通過開啟一個新的activity作為申請權限的媒介
*/
private void requestPermissions() {
Intent intent = new Intent(mContext, HelpActivity.class);
intent.putExtra("permissions", mPermissions);
intent.putExtra("requestCode", mRequestCode);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
/**
* 檢查是否需要申請權限
* @return
*/
private boolean needToRequest() {
for (String permission : mPermissions) {
int checkRes = ContextCompat.checkSelfPermission(mContext, permission);
if (checkRes != PackageManager.PERMISSION_GRANTED) {
PermissionInfo info = new PermissionInfo(permission);
if (mContext instanceof Activity &&
ActivityCompat.shouldShowRequestPermissionRationale((Activity) mContext, permission)) {
info.setRationalNeed(true);
}
mPermissionListNeedReq.add(info);
}
}
if (mPermissionListNeedReq.size() > 0) {
mPermissions = new String[mPermissionListNeedReq.size()];
for (int i = 0; i < mPermissionListNeedReq.size(); i++) {
mPermissions[i] = mPermissionListNeedReq.get(i).getName();
}
return true;
}
return false;
}
/**
* 申請權限結果返回
* @param requestCode
* @param permissions
* @param grantResults
*/
@TargetApi(Build.VERSION_CODES.M)
protected void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == mRequestCode) {
if (mContext != null && mContext instanceof Activity) {
((Activity) mContext).onRequestPermissionsResult(requestCode, permissions, grantResults);
}
if (mFragment != null) {
mFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
boolean isAllGranted = true;
List needRationalPermissionList = new ArrayList();
List deniedPermissionList = new ArrayList();
for (int i = 0; i < permissions.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
if (mPermissionListNeedReq.get(i).isRationalNeed()) {
needRationalPermissionList.add(mPermissionListNeedReq.get(i));
} else {
deniedPermissionList.add(mPermissionListNeedReq.get(i));
}
isAllGranted = false;
}
}
if (needRationalPermissionList.size() != 0) {
showRational(needRationalPermissionList);
}
if (deniedPermissionList.size() != 0) {
onDenied(deniedPermissionList);
}
if (isAllGranted) {
onGranted();
}
}
}
/**
* 權限被用戶許可之後回調的方法
*/
private void onGranted() {
if (mPermissionResultCallBack != null) {
mPermissionResultCallBack.onPermissionGranted();
}
}
/**
* 權限申請被用戶否定之後的回調方法,這個主要是當用戶點擊否定的同時點擊了不在彈出,
* 那麼當再次申請權限,此方法會被調用
* @param list
*/
private void onDenied(List list) {
if(list == null || list.size() == 0) return;
String[] permissions = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
permissions[i] = list.get(i).getName();
}
if (mPermissionResultCallBack != null) {
mPermissionResultCallBack.onPermissionDenied(permissions);
}
}
/**
* 權限申請被用戶否定後的回調方法,這個主要場景是當用戶點擊了否定,但未點擊不在彈出,
* 那麼當再次申請權限的時候,此方法會被調用
* @param list
*/
private void showRational(List list) {
if(list == null || list.size() == 0) return;
String[] permissions = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
permissions[i] = list.get(i).getName();
}
if (mPermissionResultCallBack != null) {
mPermissionResultCallBack.onRationalShow(permissions);
}
}
}
在PermissionResutCallBack中,要做的是:
1.返回對應的結果
public interface PermissionResultCallBack {
/**
* 當所有權限的申請被用戶同意之後,該方法會被調用
*/
void onPermissionGranted();
/**
* 當權限申請中的某一個或多個權限,被用戶曾經否定了,並確認了不再提醒時,也就是權限的申請窗口不能再彈出時,
* 該方法將會被調用
* @param permissions
*/
void onPermissionDenied(String... permissions);
/**
* 當權限申請中的某一個或多個權限,被用戶否定了,但沒有確認不再提醒時,也就是權限窗口申請時,但被否定了之後,
* 該方法將會被調用.
* @param permissions
*/
void onRationalShow(String... permissions);
}
在HelpActivity中,要做的就是:
1.申請權限
2.通過onRequestPermissionUtil返回結果給PermissionUtil
當然這個activity必須是透明的,而且是沒有任何的view的,這樣看起來才不像是開了一個新的activity。
public class HelpActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
handleIntent(getIntent());
}
}
@Override
protected void onNewIntent(Intent intent) {
handleIntent(intent);
}
// 權限申請
@TargetApi(Build.VERSION_CODES.M)
private void handleIntent(Intent intent) {
String[] permissions = intent.getStringArrayExtra("permissions");
int requestCode = intent.getIntExtra("requestCode", 42);
ActivityCompat.requestPermissions(this, permissions, requestCode);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
// 返回結果
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
PermissionUtil.getInstance().onRequestPermissionResult(requestCode, permissions, grantResults);
finish();
}
}
JNI是一種可以在Java中調用C/C++代碼的技術,也就是說可以在Android上使用C/C++來開發。但是並不能用純C/C+&
效果: 代碼:https://github.com/ldb-github/Layout_Tab1、布局:使用LinearLayout布置標簽;再使用FrameL
前兩天寫的上章關於換膚的功能獲得了很好的反響,今天為大家介紹另一種方式。今天實現的策略也是網友建議的,然後我自己去寫了個demo,大家自己評估下相比第一種方式的優勢和劣
界面文件activity_main.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1