《安卓开发框架》序列小说,一些用户的操作

《安卓开发框架》连串文章>>>

本身的博客
本人的博客:Android6.0动态权限申请手续以及需要小心的有的坑

一、什么是Activity?

   
简单来说:Activity就是布满整个窗口或者悬浮于另外窗口上的互动界面。在一个应用程序中平常由两个Activity构成,都会在Manifest.xml中指定一个主的Activity,如下设置

<actionandroid:name=”android.intent.action.MAIN”
/>

当程序第一次运行时用户就会看那些Activity,那么些Activity可以通过启动其他的Activity举行相关操作。当启动其他的Activity时这个当前的那一个Activity将会告一段落,新的
Activity将会压入栈中,同时取得用户大旨,这时就可在那些Activity上操作了。都知晓栈是先进后出的口径,那么当用户按Back键时,当前
的这一个Activity销毁,前一个Activity重新回升。

前言

差一点每个连串都会有各式各样的工具类,在支付中经过它们可更直白惠及地落实效益。上边将介绍demo中逐条工具类的使用,而现实的贯彻请下载demo查看代码。


因为工作亟待,简单探讨了一下Android6.0权力申请,在Google提供的sample的根底上,写了一个简练的demo。算是自己的笔记吧,可能会相比混乱,首假诺有利于将来翻看。前期有另外问题,随时更新~

二、Activity生命周期

先看下图:

图片 1

其一图不再多说咋样,下边我们透过一个实例来验证问题。新建工程,编写如下代码:

[java] view
plain

copy
print?

  1. <span style=”font-size:18px;”>package com.android.ttx.actiitylifedemo;  
  2. import android.app.Activity;  
  3. import android.os.Bundle;  
  4. import android.util.Log;  
  5. import android.view.KeyEvent;  
  6. public class ActivityLifeDemo extends Activity {  
  7.     private final static String TAG=”ActivityLifeDemo”;  
  8.       
  9.     @Override  
  10.     public void onCreate(Bundle savedInstanceState) {  
  11.         super.onCreate(savedInstanceState);  
  12.         setContentView(R.layout.main);  
  13.           
  14.         Log.i(TAG, “onCreate”);  
  15.     }  
  16.     @Override  
  17.     protected void onStart() {  
  18.         Log.i(TAG, “onStart”);  
  19.         super.onStart();  
  20.     }  
  21.     @Override  
  22.     protected void onRestart() {  
  23.         Log.i(TAG, “onRestart”);  
  24.         super.onRestart();  
  25.     }  
  26.     @Override  
  27.     protected void onResume() {  
  28.         Log.i(TAG, “onResume”);  
  29.         super.onResume();  
  30.     }  
  31.     @Override  
  32.     protected void onPause() {  
  33.         Log.i(TAG, “onPause”);  
  34.         super.onPause();  
  35.     }  
  36.     @Override  
  37.     protected void onStop() {  
  38.         Log.i(TAG, “onStop”);  
  39.         super.onStop();  
  40.     }  
  41.     @Override  
  42.     protected void onDestroy() {  
  43.         Log.i(TAG, “onDestroy”);  
  44.         super.onDestroy();  
  45.     }  
  46. }  
  47. </span>  

代码很粗略,只提到到一个Activity,一些用户的操作,大家通过记录操作和打印日志的艺术来看望Activity的生命周期过程。

1、  运行
看看如下打印日志:
08-31 08:46:53.916: INFO/ActivityLifeDemo(312): onCreate
08-31 08:46:53.916: INFO/ActivityLifeDemo(312): onStart
08-31 08:46:53.916: INFO/ActivityLifeDemo(312): onResume
2、按下回到按键:
08-31 09:29:57.396: INFO/ActivityLifeDemo(354): onPause
08-31 09:29:58.216: INFO/ActivityLifeDemo(354): onStop
08-31 09:29:58.216: INFO/ActivityLifeDemo(354): onDestroy
3、长按Home键,弹出近来打开过的应用程序,点击ActivityLifeDemo
08-31 08:51:46.916: INFO/ActivityLifeDemo(312): onCreate
08-31 08:51:46.916: INFO/ActivityLifeDemo(312): onStart
08-31 08:51:46.936: INFO/ActivityLifeDemo(312): onResume
4、按Home键
08-31 08:53:32.676: INFO/ActivityLifeDemo(312): onPause
08-31 08:53:33.796: INFO/ActivityLifeDemo(312): onStop
5、在AllList中点击打开
08-31 08:54:14.286: INFO/ActivityLifeDemo(312): onRestart
08-31 08:54:14.286: INFO/ActivityLifeDemo(312): onStart
08-31 08:54:14.296: INFO/ActivityLifeDemo(312): onResume

经过日记音讯,我们可以看来。Activity的启动过
程:onCreate—onStart—onResume;下重临键时:onPause—onStop—onDestroy
正如上边就是,当按下重返键时,此Activity弹出栈,程序销毁。确实如此,我们重新
打开时的起步过程又回去onCreate—onStart—onResume。OK,启动未来按下Home键,回到Launcher,查看打印音讯:onPause—onStop,再一次打开的运转过程:onRestart—onStart—onResume。

我们经过对Activity的各样操作,构成了Activity的生命周期,大家看出无论对Activity做什么样的操作,都会吸纳到有关的回调方法,那么我们在付出的经过中经过那么些回调方法就足以写工作,比如说释放部分重量级的目标,网络连接,数据库连接,文件读等等。

以下是逐一艺术的详实表达:

onCreate():当 activity 第一次创立时会被调用。在这些格局中你需要形成具有的正常化静态设置 ,比如创设一个视图( view )、绑定列表的多少等等。假设能捕获到 activity 状
态的话,这么些点子传递进入的 Bundle 对象将存放了 activity 当前的状态。调用该办法后一般会调用 onStart() 方法。

onRestart():在 activity 被终止后再行启动时会调用该办法。其持续会调用 onStart 方法。

onStart()à当 activity 对于用户可见前即调用这么些艺术。假设 activity回到前台则随之调用 onResume() ,假如 activity 隐藏则调用onStop()

onResume():在 activity 先河与用户交互前调用该方法。在这儿该activity 处于 activity 栈的顶部,并且接受用户的输入。其继续会调用 onPause() 方法。

onPause():在系统准备上马复苏另外 activity 时会调用该措施。这多少个艺术中一般用来交给一些还没封存的改变到持久数据 中,截至部分动画片或其他一些耗 CPU 的操作等等。无论
在该措施里面举办任何操作,都急需较便捷完成,因为只要它不回去的话,下一个 activity 将不可能苏醒出来。假如 activity 重返到前台将
会调用 onResume() ,假诺 activity 变得对用户不可见了将会调用onStop() 。

onStop():在 activity 对用户不可见时
将调用该办法。可能会因为脚下 activity 正在被销毁,或另一个 activity (已经存在的activity 或新
的 activity )已经回复了正准备覆盖它,而调用该办法。倘诺 activity 正准备重临与用户交互时继续会调用onRestart ,假设 activity 正在被保释则会调用 onDestroy 。

onDestroy():在 activity 被销毁前
会调用该措施。这是 activity 能选择到的末尾一个调用。可能会因为有人调用了 finish 方法使得当前activity 正在关闭,或系统
为了保障内存临时释放这一个 activity的实例,而调用该方法。你能够用 isFinishing 方法来区分那三种不同的情状。

介绍

  • 本demo
    github下载地址!!!

  • Google提供的demo的下载地址

  • 6.0权力的基本知识,以下是需要独自申请的权能,共分为9组,每组只要有一个权力申请成功了,就默认整组权限都得以动用了。

      group:android.permission-group.CONTACTS
        permission:android.permission.WRITE_CONTACTS
        permission:android.permission.GET_ACCOUNTS    
        permission:android.permission.READ_CONTACTS
    
      group:android.permission-group.PHONE
        permission:android.permission.READ_CALL_LOG
        permission:android.permission.READ_PHONE_STATE 
        permission:android.permission.CALL_PHONE
        permission:android.permission.WRITE_CALL_LOG
        permission:android.permission.USE_SIP
        permission:android.permission.PROCESS_OUTGOING_CALLS
        permission:com.android.voicemail.permission.ADD_VOICEMAIL
    
      group:android.permission-group.CALENDAR
        permission:android.permission.READ_CALENDAR
        permission:android.permission.WRITE_CALENDAR
    
      group:android.permission-group.CAMERA
        permission:android.permission.CAMERA
    
      group:android.permission-group.SENSORS
        permission:android.permission.BODY_SENSORS
    
      group:android.permission-group.LOCATION
        permission:android.permission.ACCESS_FINE_LOCATION
        permission:android.permission.ACCESS_COARSE_LOCATION
    
      group:android.permission-group.STORAGE
        permission:android.permission.READ_EXTERNAL_STORAGE
        permission:android.permission.WRITE_EXTERNAL_STORAGE
    
      group:android.permission-group.MICROPHONE
        permission:android.permission.RECORD_AUDIO
    
      group:android.permission-group.SMS
        permission:android.permission.READ_SMS
        permission:android.permission.RECEIVE_WAP_PUSH
        permission:android.permission.RECEIVE_MMS
        permission:android.permission.RECEIVE_SMS
        permission:android.permission.SEND_SMS
        permission:android.permission.READ_CELL_BROADCASTS
    
  • 以下是普通权限,只需要在AndroidManifest.xml中申请即可。

      android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
      android.permission.ACCESS_NETWORK_STATE
      android.permission.ACCESS_NOTIFICATION_POLICY
      android.permission.ACCESS_WIFI_STATE
      android.permission.ACCESS_WIMAX_STATE
      android.permission.BLUETOOTH
      android.permission.BLUETOOTH_ADMIN
      android.permission.BROADCAST_STICKY
      android.permission.CHANGE_NETWORK_STATE
      android.permission.CHANGE_WIFI_MULTICAST_STATE
      android.permission.CHANGE_WIFI_STATE
      android.permission.CHANGE_WIMAX_STATE
      android.permission.DISABLE_KEYGUARD
      android.permission.EXPAND_STATUS_BAR
      android.permission.FLASHLIGHT
      android.permission.GET_ACCOUNTS
      android.permission.GET_PACKAGE_SIZE
      android.permission.INTERNET
      android.permission.KILL_BACKGROUND_PROCESSES
      android.permission.MODIFY_AUDIO_SETTINGS
      android.permission.NFC
      android.permission.READ_SYNC_SETTINGS
      android.permission.READ_SYNC_STATS
      android.permission.RECEIVE_BOOT_COMPLETED
      android.permission.REORDER_TASKS
      android.permission.REQUEST_INSTALL_PACKAGES
      android.permission.SET_TIME_ZONE
      android.permission.SET_WALLPAPER
      android.permission.SET_WALLPAPER_HINTS
      android.permission.SUBSCRIBED_FEEDS_READ
      android.permission.TRANSMIT_IR
      android.permission.USE_FINGERPRINT
      android.permission.VIBRATE
      android.permission.WAKE_LOCK
      android.permission.WRITE_SYNC_SETTINGS
      com.android.alarm.permission.SET_ALARM
      com.android.launcher.permission.INSTALL_SHORTCUT
      com.android.launcher.permission.UNINSTALL_SHORTCUT
    

三、怎样启动一个新的Activity?

要启动一个新的Activity,我们能够透过调用Context中的startActivity来启动。像这么:

[java] view
plain

copy
print?

  1. <span style=”font-size:18px;”>Intent intent = new Intent(this, ActivityDemo.class);  
  2. startActivity(intent);  // ActivityDemo是急需启动的Activity类  
  3. </span>  

由此地点的章程能够启动新的Activity了,但即使自身要从眼前的Activity中传递数据到新的Activity呢?很粗略:

[java] view
plain

copy
print?

  1. <span style=”font-size:18px;”>Intent intent = new Intent(this,ActivityDemo.class);  
  2. Bundle bundle = new Bundle();  
  3. bundle.putBoolean(“bool_key”, true);  
  4. intent.putExtras(bundle);  
  5. startActivity(intent);  
  6. </span>  

再有,有时候我们需要启动带再次回到值的Activity,简单的讲就是亟需新开行的Activity重回时将值传递给启动它的Activity,像这样:

[java] view
plain

copy
print?

  1. <span style=”font-size:18px;”>Intent intent = new Intent(ActivityLifeDemo.this,RevalueActivity.class);  
  2. startActivityForResult(intent, 0x1001);  
  3. </span>  

ActivityLifeDemo是现阶段的Activity,启动RevalueActivity,我们在ActivityLifeDemo中需要拿到RevalueActivity传回到的值。那么在RevalueActivity中就不可以不这样写:

[java] view
plain

copy
print?

  1. <span style=”font-size:18px;”>Intent intent  = new Intent();  
  2. intent.putExtra(“revalue_key”,”haha-revalueActivity”);  
  3. setResult(0x1001, intent);</span>  

那么“revalue_key”值在哪儿拿到呢?必须重写onActivityResult方法,通过判断requestCode,来规定

[java] view
plain

copy
print?

  1. <span style=”font-size:18px;”>if(requestCode==0x1001){  
  2.             String str = data.getStringExtra(“revalue_key”);  
  3.             Log.i(TAG, “重临的值为:”+str);  
  4.         }  
  5. </span>  

好了,详细的请看代码吧。下载地址:http://download.csdn.net/detail/tangcheng_ok/3580700

 

1. Log打印

demo中提供了LogUtil工具类(出自ZhaoKaiQiang),和平凡的Log一样包含Verbose、Debug、Info、Warn、Error、Assert多少个等级,还协助将json或xml文本格式化后输出。
使用:
1)控制是否打印。正式打包上线时可设为false:

LogUtil.init(true);

2)打印

//比如打印Error级日志
LogUtil.e(TAG, message);

//将jsonString格式化后打印出来
LogUtil.json(TAG, jsonString);

//将xmlString格式化后打印出来
LogUtil.xml(TAG, xmlString);

本条Log工具类一个很大的好处是,你可以高速地跟踪到调用打印的具体地方。如图:

图片 2

Log跟踪1

点击MoviePresenter即可定位到输出打印的地方

图片 3

Log跟踪2

提请手续

    1. 将targetSdkVersion设置为23,注意,如若你将targetSdkVersion设置为>=23,则必须服从AndroidGoogle的渴求,动态的提请权限,假使你暂时不打算补助动态权限申请,则targetSdkVersion最大不得不设置为22.
  • 2
    在AndroidManifest.xml中申请你需要的权柄,包括一般权限和内需提请的例外权限。

  • 3.开始申请权限,此处分为3部。

  • (1)检查是不是通过权限checkSelfPermission(),尽管已经拉开,则一向做你想做的。

  • (2)假若未张开,则判断是否需要向用户解释为何申请权限shouldShowRequestPermissionRationale。

  • (3)假若急需(即重临true),则足以弹出对话框指示用户申请权限原因,用户确认后申请权限requestPermissions(),假如不需要(即重回false),则间接申请权限requestPermissions()。
    (这里是一机关代码,底部有相比较完善的代码,整个demo可以在github中下载)。

图片 4

单个权限申请.png

     /**
         * Requests permission.
         *
         * @param activity
         * @param requestCode request code, e.g. if you need request CAMERA permission,parameters is PermissionUtils.CODE_CAMERA
         */
        public static void requestPermission(final Activity activity, final int requestCode, PermissionGrant permissionGrant) {
            if (activity == null) {
                return;
            }

            Log.i(TAG, "requestPermission requestCode:" + requestCode);
            if (requestCode < 0 || requestCode >= requestPermissions.length) {
                Log.w(TAG, "requestPermission illegal requestCode:" + requestCode);
                return;
            }

            final String requestPermission = requestPermissions[requestCode];

            //如果是6.0以下的手机,ActivityCompat.checkSelfPermission()会始终等于PERMISSION_GRANTED,
        // 但是,如果用户关闭了你申请的权限(如下图,在安装的时候,将一些权限关闭了),ActivityCompat.checkSelfPermission()则可能会导致程序崩溃(java.lang.RuntimeException: Unknown exception code: 1 msg null),
        // 你可以使用try{}catch(){},处理异常,也可以判断系统版本,低于23就不申请权限,直接做你想做的。permissionGrant.onPermissionGranted(requestCode);
//        if (Build.VERSION.SDK_INT < 23) {
//            permissionGrant.onPermissionGranted(requestCode);
//            return;
//        }

            int checkSelfPermission;
            try {
                checkSelfPermission = ActivityCompat.checkSelfPermission(activity, requestPermission);
            } catch (RuntimeException e) {
                Toast.makeText(activity, "please open this permission", Toast.LENGTH_SHORT)
                        .show();
                Log.e(TAG, "RuntimeException:" + e.getMessage());
                return;
            }

            if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
                Log.i(TAG, "ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED");


                if (ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission)) {
                    Log.i(TAG, "requestPermission shouldShowRequestPermissionRationale");
                    shouldShowRationale(activity, requestCode, requestPermission);

                } else {
                    Log.d(TAG, "requestCameraPermission else");
                    ActivityCompat.requestPermissions(activity, new String[]{requestPermission}, requestCode);
                }

            } else {
                Log.d(TAG, "ActivityCompat.checkSelfPermission ==== PackageManager.PERMISSION_GRANTED");
                Toast.makeText(activity, "opened:" + requestPermissions[requestCode], Toast.LENGTH_SHORT).show();
//得到权限的时候,就可以在回调里面做你想做的事情了
                permissionGrant.onPermissionGranted(requestCode);
            }
        }

图片 5

6.0以下系统的应用程序安装界面.png

四、保存Activity运行情形

因而重写onSaveInstanceState()方法来兑现Activity的运行情形,请留意以下几点:

1)由于activity 对象被中止或截至时,它仍然保留在内存里面,关于它的成员音信和脚下情状都是运动的,所以此时得以保存Activity的境况,从而使用户所作的Activity的改观保存在内存中

2) 
当系统回收内存而将Activity销毁时,就不可能保存其意况,所以需要调用onSaveInstanceState()方法来落实动静的保留

3) 
很多情形并不需要保持状态音信,比如按下重临键间接关闭程序,所以并不可以保证会调用onSaveInstanceState。固然调用了该形式,一般是在
onStop 方法在此以前且可能在 onPause 之后调用。即便如此,即便你没做另外操作或尚未落实 onSaveInstanceState() 方
法,你的 activity 状态也能由此Activity 类里面默认实现的 onSaveInstanceState 方法復苏出来。特别是会为布局
中的视图( View )默认调用onSaveInstanceState 方法,并在这多少个艺术中允许每一个视图提供它需要还原的另外音讯。几乎每一
个 Android框架中的 widget 都视意况实现了这个法子。

注:因为 onSaveInstanceState 方法
不必然会被调用,所以你应当只是用它来保存一些 activity 的变换过程气象(即 UI 的动静),而无法用来保存永久性数据。但您可以用 onPause 方法在用户距离 activity 时来保存永久性数据,比如需要保留到数据库的数据。

有一个很好的情势能够用来检验应用程序保存情状的力量,就
是简单地打转你的设施来改变屏幕的大方向。因为当屏幕方向改变时,系统为了给新的矛头提供一个或许优异的代表资源,会销毁 activity 并新建一个新
的。由于这一个原因,你的 activity 是否能在其重新成立时做到保存境况就彰显越来越首要,因为用户时时会在行使应用程序时旋转屏幕的。

上文部分内容参考了:http://blog.csdn.net/sam_zhang1984/article/details/6430817,在这边多谢这位博主了。

2. 倾家荡产打印

demo中提供了CrashLogUtil工具类,用于在先后崩溃时,输出很是日志到手机本地文件中,方便在没连接电脑时翻算命当信息。
拔取方法:
1.Application中开头化

CrashLogUtil.getInstance().init(this);//初始化崩溃打印

2.可指定特别信息所出口的公文(地方)

File dirTemp = FileUtil.generateDirectory(FileUtil.getExternalCacheDir(), "temp");
File fileOutput = FileUtil.generateFile(dirTemp, fileName);
//指定输出文件
CrashLogUtil.getInstance().setFileOutput(fileOutput);

不指定的话,文件默认就保存在/storage/emulated/0/Android/data/com.xxx.xxx/cache/temp下。
先后崩溃时,即可到相应的职位下查看分外信息,如图:

图片 6

翻开崩溃日志1

图片 7

翻看崩溃日志2

备注!!!

(1)checkSelfPermission:检查是否具有那多少个权力
(2)requestPermissions:请求权限,一般会弹出一个体系对话框,询问用户是否打开这么些权力。
(3)shouldShowRequestPermissionRationale:Android原生系统中,倘使第二次弹出权力申请的对话框,会冒出“将来不再弹出”的指示框,假诺用户勾选了,你再申请权限,则shouldShowRequestPermissionRationale重临true,意思是说要给用户一个
解释,告诉用户为何要这个权力。可是,在实际开支中,需要留意的是,很多有线电话对原生系统做了改动,比如华为,三星4的6.0的shouldShowRequestPermissionRationale
就径直返回false,而且在报名权限时,假诺用户接纳了闭门羹,则不会再弹出对话框了。。。。
所以说这个地点有坑,我的化解形式是,在回调里面处理,假如用户拒绝了那么些权力,则打开本利用信息界面,由用户自己手动开启那些权力。
(4)每个应用都有协调的权限管理界面,里面有本利用申请的权杖以及各类气象,尽管用户已经允许了你申请的权力,他也随时可以关闭

图片 8

权限管理界面.png

五、完全退出程序

透过下面的牵线,大家清楚当点击back键时,程序调用了
onDestroy方法,程序退出了,不过大家查阅其经过,发现调用了onDestroy方法之后这一个Activity还在运转。甚至调用了
finish()方法之后先后还可以在过程中来看。通过上边这种办法得以兑现程序的通通脱离:

[java] view
plain

copy
print?

  1. <span style=”font-size:18px;”>Intent intent = new Intent();  
  2. Intent.setClass(context,MainActivity.class);  
  3. intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
  4. intent.putExtra(“flag”,EXIT_APPLICATION);  
  5. context.startActivity(intnet);   
  6. </span> 

3. 无线电话系统项目

demo中提供了SystemTypeUtil工具类,用于拍卖与手机系统项目相关的事件。
一些手机的类别是遵照原生Android系统改造的(如一加,金立),所以在稍微功用的兑现上急需做配合处理,如设置情状栏中图文的颜色形式、跳转到权限管理页面。

  • 判断手机品类

boolean flag;
flag = SystemTypeUtil.isEMUI();//是否为华为手机
flag = SystemTypeUtil.isMIUI();//是否为小米手机
flag = SystemTypeUtil.isFlyme();//是否为魅族手机
  • 跳转到权限管理页面

//跳转,兼容不同手机系统类型
SystemTypeUtil.goToPermissionManager(context);
  • 设置情形栏中图文的颜色形式(深色情势或亮色形式)

boolean isDark = true;//true表示深色模式,false表示亮色模式
Window window = getWindow();
boolean flag = SystemTypeUtil.setStatusBarLightMode(window, isDark);//返回true表示设置成功

深色格局效能图:

图片 9

深色情势

亮色格局效用图:

图片 10

亮色情势

五次提请六个权力

其实和报名一个权力是同样的,只是requestPermissions(final @NonNull
Activity activity,
final @NonNull String[] permissions, final int
requestCode),里面的permissions给的参数多些而已。

图片 11

提请六个权限.png

 /**
     * 一次申请多个权限
     */
    public static void requestMultiPermissions(final Activity activity, PermissionGrant grant) {

        final List<String> permissionsList = getNoGrantedPermission(activity, false);
        final List<String> shouldRationalePermissionsList = getNoGrantedPermission(activity, true);

        //TODO checkSelfPermission
        if (permissionsList == null || shouldRationalePermissionsList == null) {
            return;
        }
        Log.d(TAG, "requestMultiPermissions permissionsList:" + permissionsList.size() + ",shouldRationalePermissionsList:" + shouldRationalePermissionsList.size());

        if (permissionsList.size() > 0) {
            ActivityCompat.requestPermissions(activity, permissionsList.toArray(new String[permissionsList.size()]),
                    CODE_MULTI_PERMISSION);
            Log.d(TAG, "showMessageOKCancel requestPermissions");

        } else if (shouldRationalePermissionsList.size() > 0) {
            showMessageOKCancel(activity, "should open those permission",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions(activity, shouldRationalePermissionsList.toArray(new String[shouldRationalePermissionsList.size()]),
                                    CODE_MULTI_PERMISSION);
                            Log.d(TAG, "showMessageOKCancel requestPermissions");
                        }
                    });
        } else {
            grant.onPermissionGranted(CODE_MULTI_PERMISSION);
        }

    }
  • 有关权限请求结果的回调。Activity实现ActivityCompat.OnRequestPermissionsResultCallback接口,重写onRequestPermissionsResult方法。

     @Override
      public void onRequestPermissionsResult(final int requestCode, @NonNull String[] permissions,
                                             @NonNull int[] grantResults) {
          PermissionUtils.requestPermissionsResult(this, requestCode, permissions, grantResults, mPermissionGrant);
    
      }
    

4. android 6.0权力申请

android6.0后(targetSdkVersion>=23)对于敏感权限,app需要向用户指出授权申请。
demo中提供了一个比较简单PermissionUtil工具类,用于6.0本子的权柄申请。github上有不少高star的6.0权力开源库,我们可以自动查阅。

这边说下一般的提请流程:
1)在 AndroidManifest.xml 添加权限讲明。
2)使用 checkSelfPermission 检查某个权限是否已经提请。
3)权限未申请,使用 requestPermissions
申请权限,然后会回调onRequestPermissionsResult。
4)在 onRequestPermissionsResult 回调中判断权限是否申请成功。
5)假如申请破产,则使用 shouldShowRequestPermissionRationale
判断用户是否勾选了 “不再升迁”。勾选了的话,则弹出一个 Dialog
指点用户到安装界面授予权限。没勾选的话,可以什么都不做,也得以弹出弹出一个
Dialog 携带用户到安装界面授予权限。

全方位申请权限工具类代码

package com.example.android.system.runtimepermissions;

import android.Manifest;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by qianxiaoai on 2016/7/7.
 */
public class PermissionUtils {

    private static final String TAG = PermissionUtils.class.getSimpleName();
    public static final int CODE_RECORD_AUDIO = 0;
    public static final int CODE_GET_ACCOUNTS = 1;
    public static final int CODE_READ_PHONE_STATE = 2;
    public static final int CODE_CALL_PHONE = 3;
    public static final int CODE_CAMERA = 4;
    public static final int CODE_ACCESS_FINE_LOCATION = 5;
    public static final int CODE_ACCESS_COARSE_LOCATION = 6;
    public static final int CODE_READ_EXTERNAL_STORAGE = 7;
    public static final int CODE_WRITE_EXTERNAL_STORAGE = 8;
    public static final int CODE_MULTI_PERMISSION = 100;

    public static final String PERMISSION_RECORD_AUDIO = Manifest.permission.RECORD_AUDIO;
    public static final String PERMISSION_GET_ACCOUNTS = Manifest.permission.GET_ACCOUNTS;
    public static final String PERMISSION_READ_PHONE_STATE = Manifest.permission.READ_PHONE_STATE;
    public static final String PERMISSION_CALL_PHONE = Manifest.permission.CALL_PHONE;
    public static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;
    public static final String PERMISSION_ACCESS_FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
    public static final String PERMISSION_ACCESS_COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
    public static final String PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE;
    public static final String PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;

    private static final String[] requestPermissions = {
            PERMISSION_RECORD_AUDIO,
            PERMISSION_GET_ACCOUNTS,
            PERMISSION_READ_PHONE_STATE,
            PERMISSION_CALL_PHONE,
            PERMISSION_CAMERA,
            PERMISSION_ACCESS_FINE_LOCATION,
            PERMISSION_ACCESS_COARSE_LOCATION,
            PERMISSION_READ_EXTERNAL_STORAGE,
            PERMISSION_WRITE_EXTERNAL_STORAGE
    };

    interface PermissionGrant {
        void onPermissionGranted(int requestCode);
    }

    /**
     * Requests permission.
     *
     * @param activity
     * @param requestCode request code, e.g. if you need request CAMERA permission,parameters is PermissionUtils.CODE_CAMERA
     */
    public static void requestPermission(final Activity activity, final int requestCode, PermissionGrant permissionGrant) {
        if (activity == null) {
            return;
        }

        Log.i(TAG, "requestPermission requestCode:" + requestCode);
        if (requestCode < 0 || requestCode >= requestPermissions.length) {
            Log.w(TAG, "requestPermission illegal requestCode:" + requestCode);
            return;
        }

        final String requestPermission = requestPermissions[requestCode];

        //如果是6.0以下的手机,ActivityCompat.checkSelfPermission()会始终等于PERMISSION_GRANTED,
        // 但是,如果用户关闭了你申请的权限,ActivityCompat.checkSelfPermission(),会导致程序崩溃(java.lang.RuntimeException: Unknown exception code: 1 msg null),
        // 你可以使用try{}catch(){},处理异常,也可以在这个地方,低于23就什么都不做,
        // 个人建议try{}catch(){}单独处理,提示用户开启权限。
//        if (Build.VERSION.SDK_INT < 23) {
//            return;
//        }

        int checkSelfPermission;
        try {
            checkSelfPermission = ActivityCompat.checkSelfPermission(activity, requestPermission);
        } catch (RuntimeException e) {
            Toast.makeText(activity, "please open this permission", Toast.LENGTH_SHORT)
                    .show();
            Log.e(TAG, "RuntimeException:" + e.getMessage());
            return;
        }

        if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
            Log.i(TAG, "ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED");


            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission)) {
                Log.i(TAG, "requestPermission shouldShowRequestPermissionRationale");
                shouldShowRationale(activity, requestCode, requestPermission);

            } else {
                Log.d(TAG, "requestCameraPermission else");
                ActivityCompat.requestPermissions(activity, new String[]{requestPermission}, requestCode);
            }

        } else {
            Log.d(TAG, "ActivityCompat.checkSelfPermission ==== PackageManager.PERMISSION_GRANTED");
            Toast.makeText(activity, "opened:" + requestPermissions[requestCode], Toast.LENGTH_SHORT).show();
            permissionGrant.onPermissionGranted(requestCode);
        }
    }

    private static void requestMultiResult(Activity activity, String[] permissions, int[] grantResults, PermissionGrant permissionGrant) {

        if (activity == null) {
            return;
        }

        //TODO
        Log.d(TAG, "onRequestPermissionsResult permissions length:" + permissions.length);
        Map<String, Integer> perms = new HashMap<>();

        ArrayList<String> notGranted = new ArrayList<>();
        for (int i = 0; i < permissions.length; i++) {
            Log.d(TAG, "permissions: [i]:" + i + ", permissions[i]" + permissions[i] + ",grantResults[i]:" + grantResults[i]);
            perms.put(permissions[i], grantResults[i]);
            if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                notGranted.add(permissions[i]);
            }
        }

        if (notGranted.size() == 0) {
            Toast.makeText(activity, "all permission success" + notGranted, Toast.LENGTH_SHORT)
                    .show();
            permissionGrant.onPermissionGranted(CODE_MULTI_PERMISSION);
        } else {
            openSettingActivity(activity, "those permission need granted!");
        }

    }


    /**
     * 一次申请多个权限
     */
    public static void requestMultiPermissions(final Activity activity, PermissionGrant grant) {

        final List<String> permissionsList = getNoGrantedPermission(activity, false);
        final List<String> shouldRationalePermissionsList = getNoGrantedPermission(activity, true);

        //TODO checkSelfPermission
        if (permissionsList == null || shouldRationalePermissionsList == null) {
            return;
        }
        Log.d(TAG, "requestMultiPermissions permissionsList:" + permissionsList.size() + ",shouldRationalePermissionsList:" + shouldRationalePermissionsList.size());

        if (permissionsList.size() > 0) {
            ActivityCompat.requestPermissions(activity, permissionsList.toArray(new String[permissionsList.size()]),
                    CODE_MULTI_PERMISSION);
            Log.d(TAG, "showMessageOKCancel requestPermissions");

        } else if (shouldRationalePermissionsList.size() > 0) {
            showMessageOKCancel(activity, "should open those permission",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions(activity, shouldRationalePermissionsList.toArray(new String[shouldRationalePermissionsList.size()]),
                                    CODE_MULTI_PERMISSION);
                            Log.d(TAG, "showMessageOKCancel requestPermissions");
                        }
                    });
        } else {
            grant.onPermissionGranted(CODE_MULTI_PERMISSION);
        }

    }


    private static void shouldShowRationale(final Activity activity, final int requestCode, final String requestPermission) {
        //TODO
        String[] permissionsHint = activity.getResources().getStringArray(R.array.permissions);
        showMessageOKCancel(activity, "Rationale: " + permissionsHint[requestCode], new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                ActivityCompat.requestPermissions(activity,
                        new String[]{requestPermission},
                        requestCode);
                Log.d(TAG, "showMessageOKCancel requestPermissions:" + requestPermission);
            }
        });
    }

    private static void showMessageOKCancel(final Activity context, String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(context)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", null)
                .create()
                .show();

    }

    /**
     * @param activity
     * @param requestCode  Need consistent with requestPermission
     * @param permissions
     * @param grantResults
     */
    public static void requestPermissionsResult(final Activity activity, final int requestCode, @NonNull String[] permissions,
                                                @NonNull int[] grantResults, PermissionGrant permissionGrant) {

        if (activity == null) {
            return;
        }
        Log.d(TAG, "requestPermissionsResult requestCode:" + requestCode);

        if (requestCode == CODE_MULTI_PERMISSION) {
            requestMultiResult(activity, permissions, grantResults, permissionGrant);
            return;
        }

        if (requestCode < 0 || requestCode >= requestPermissions.length) {
            Log.w(TAG, "requestPermissionsResult illegal requestCode:" + requestCode);
            Toast.makeText(activity, "illegal requestCode:" + requestCode, Toast.LENGTH_SHORT).show();
            return;
        }

        Log.i(TAG, "onRequestPermissionsResult requestCode:" + requestCode + ",permissions:" + permissions.toString()
                + ",grantResults:" + grantResults.toString() + ",length:" + grantResults.length);

        if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.i(TAG, "onRequestPermissionsResult PERMISSION_GRANTED");
            //TODO success, do something, can use callback
            permissionGrant.onPermissionGranted(requestCode);

        } else {
            //TODO hint user this permission function
            Log.i(TAG, "onRequestPermissionsResult PERMISSION NOT GRANTED");
            //TODO
            String[] permissionsHint = activity.getResources().getStringArray(R.array.permissions);
            openSettingActivity(activity,  "Result" + permissionsHint[requestCode]);
        }

    }

    private static void openSettingActivity(final Activity activity, String message) {

        showMessageOKCancel(activity, message, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Intent intent = new Intent();
                intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                Log.d(TAG, "getPackageName(): " + activity.getPackageName());
                Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
                intent.setData(uri);
                activity.startActivity(intent);
            }
        });
    }


    /**
     * @param activity
     * @param isShouldRationale true: return no granted and shouldShowRequestPermissionRationale permissions, false:return no granted and !shouldShowRequestPermissionRationale
     * @return
     */
    public static ArrayList<String> getNoGrantedPermission(Activity activity, boolean isShouldRationale) {

        ArrayList<String> permissions = new ArrayList<>();

        for (int i = 0; i < requestPermissions.length; i++) {
            String requestPermission = requestPermissions[i];


            //TODO checkSelfPermission
            int checkSelfPermission = -1;
            try {
                checkSelfPermission = ActivityCompat.checkSelfPermission(activity, requestPermission);
            } catch (RuntimeException e) {
                Toast.makeText(activity, "please open those permission", Toast.LENGTH_SHORT)
                        .show();
                Log.e(TAG, "RuntimeException:" + e.getMessage());
                return null;
            }

            if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
                Log.i(TAG, "getNoGrantedPermission ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED:" + requestPermission);

                if (ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission)) {
                    Log.d(TAG, "shouldShowRequestPermissionRationale if");
                    if (isShouldRationale) {
                        permissions.add(requestPermission);
                    }

                } else {

                    if (!isShouldRationale) {
                        permissions.add(requestPermission);
                    }
                    Log.d(TAG, "shouldShowRequestPermissionRationale else");
                }

            }
        }

        return permissions;
    }

}

5. 网络状态

demo中提供了NetworkUtil工具类,用于查询网络状态

//当前网络是否可用,返回true表示可用,false表示不可以用
NetworkUtil.isNetWorkAvailable(context);

//当前网络是否为wifi网络,返回true表示是,false表示不是
NetworkUtil.isWifiConnected(context);

//当前网络是否为手机移动网络,返回true表示是,false表示不是
NetworkUtil.isMobileConnected(context);

...

界面调用代码

package com.example.android.system.runtimepermissions;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.widget.Toast;

import com.example.android.common.logger.Log;

/**
 * Created by qianxiaoai on 2016/7/8.
 */
public class PermissionActivity extends FragmentActivity implements ActivityCompat.OnRequestPermissionsResultCallback{
    private static final String TAG = PermissionActivity.class.getSimpleName();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_permission);
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        PermissionsFragment fragment = new PermissionsFragment();
        transaction.replace(R.id.content_fragment, fragment);
        transaction.commit();

    }

    /**
     * Called when the 'show camera' button is clicked.
     * Callback is defined in resource layout definition.
     */
    public void showCamera(View view) {
        Log.i(TAG, "Show camera button pressed. Checking permission.");
        PermissionUtils.requestPermission(this, PermissionUtils.CODE_CAMERA, mPermissionGrant);
    }

    public void getAccounts(View view) {
        PermissionUtils.requestPermission(this, PermissionUtils.CODE_GET_ACCOUNTS, mPermissionGrant);
    }

    public void callPhone(View view) {
        PermissionUtils.requestPermission(this, PermissionUtils.CODE_CALL_PHONE, mPermissionGrant);
    }

    public void readPhoneState(View view) {
        PermissionUtils.requestPermission(this, PermissionUtils.CODE_READ_PHONE_STATE, mPermissionGrant);
    }

    public void accessFineLocation(View view) {
        PermissionUtils.requestPermission(this, PermissionUtils.CODE_ACCESS_FINE_LOCATION, mPermissionGrant);
    }

    public void accessCoarseLocation(View view) {
        PermissionUtils.requestPermission(this, PermissionUtils.CODE_ACCESS_COARSE_LOCATION, mPermissionGrant);
    }

    public void readExternalStorage(View view) {
        PermissionUtils.requestPermission(this, PermissionUtils.CODE_READ_EXTERNAL_STORAGE, mPermissionGrant);
    }

    public void writeExternalStorage(View view) {
        PermissionUtils.requestPermission(this, PermissionUtils.CODE_WRITE_EXTERNAL_STORAGE, mPermissionGrant);
    }

    public void recordAudio(View view) {
        PermissionUtils.requestPermission(this, PermissionUtils.CODE_RECORD_AUDIO, mPermissionGrant);
    }


    private PermissionUtils.PermissionGrant mPermissionGrant = new PermissionUtils.PermissionGrant() {
        @Override
        public void onPermissionGranted(int requestCode) {
            switch (requestCode) {
                case PermissionUtils.CODE_RECORD_AUDIO:
                    Toast.makeText(PermissionActivity.this, "Result Permission Grant CODE_RECORD_AUDIO", Toast.LENGTH_SHORT).show();
                    break;
                case PermissionUtils.CODE_GET_ACCOUNTS:
                    Toast.makeText(PermissionActivity.this, "Result Permission Grant CODE_GET_ACCOUNTS", Toast.LENGTH_SHORT).show();
                    break;
                case PermissionUtils.CODE_READ_PHONE_STATE:
                    Toast.makeText(PermissionActivity.this, "Result Permission Grant CODE_READ_PHONE_STATE", Toast.LENGTH_SHORT).show();
                    break;
                case PermissionUtils.CODE_CALL_PHONE:
                    Toast.makeText(PermissionActivity.this, "Result Permission Grant CODE_CALL_PHONE", Toast.LENGTH_SHORT).show();
                    break;
                case PermissionUtils.CODE_CAMERA:
                    Toast.makeText(PermissionActivity.this, "Result Permission Grant CODE_CAMERA", Toast.LENGTH_SHORT).show();
                    break;
                case PermissionUtils.CODE_ACCESS_FINE_LOCATION:
                    Toast.makeText(PermissionActivity.this, "Result Permission Grant CODE_ACCESS_FINE_LOCATION", Toast.LENGTH_SHORT).show();
                    break;
                case PermissionUtils.CODE_ACCESS_COARSE_LOCATION:
                    Toast.makeText(PermissionActivity.this, "Result Permission Grant CODE_ACCESS_COARSE_LOCATION", Toast.LENGTH_SHORT).show();
                    break;
                case PermissionUtils.CODE_READ_EXTERNAL_STORAGE:
                    Toast.makeText(PermissionActivity.this, "Result Permission Grant CODE_READ_EXTERNAL_STORAGE", Toast.LENGTH_SHORT).show();
                    break;
                case PermissionUtils.CODE_WRITE_EXTERNAL_STORAGE:
                    Toast.makeText(PermissionActivity.this, "Result Permission Grant CODE_WRITE_EXTERNAL_STORAGE", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    break;
            }
        }
    };

    /**
     * Callback received when a permissions request has been completed.
     */
    @Override
    public void onRequestPermissionsResult(final int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        PermissionUtils.requestPermissionsResult(this, requestCode, permissions, grantResults, mPermissionGrant);
    }
}

6. File相关

demo中提供了FileUtil工具类,用于拍卖File相关的操作

  • SD卡是否能用

FileUtil.isSDCardAvailable();
  • 创办文件夹

/**
* 创建一个文件夹, 存在则返回, 不存在则新建
*
* @param String parentDirectory 父目录路径
* @param String directory  目录名
* @return 文件,null代表失败
*/
FileUtil.generateDirectory(parentDirectory, directory);

/**
 * 创建一个文件夹, 存在则返回, 不存在则新建
 *
 * @param File parentDirectory 父目录
 * @param String directory  目录名
 * @return 文件,null代表失败
 */
 FileUtil.generateDirectory(parentDirectory, directory)
  • 创设文件

/**
 * 创建一个文件, 存在则返回, 不存在则新建
 *
 * @param File catalog 父目录
 * @param String name    文件名
 * @return 文件,null代表失败
 */
 FileUtil.generateFile(catalog, name);

/**
* 根据全路径创建一个文件
*
* @param filePath 文件全路径
* @return 文件,null代表失败
*/
FileUtil.generateFile(filePath);
  • 剔除文件

/**
* 删除文件/文件夹
* 如果是文件夹,则会删除其下的文件以及它本身
* @param file file
* @return true代表成功删除
*/
FileUtil.deleteFile(file);
  • 算算文件大小

/**
 * 计算文件/文件夹的大小
 * @param file 文件或文件夹
 * @return long 文件大小
 */
FileUtil.calculateFileSize(file);
  • 取得系统提供的文书夹路径

//返回"/data"目录
FileUtil.getDataDirectory();

//返回"/storage/emulated/0"目录
FileUtil.getExternalStorageDirectory();

//返回"/system"目录
FileUtil.getRootDirectory();

//返回"/cache"目录
FileUtil.getDownloadCacheDirectory();

//返回"/data/user/0/com.xxx.xxx/cache"目录
FileUtil.getCacheDir();

//返回"/data/user/0/com.xxx.xxx/files"目录
FileUtil.getFilesDir();

//返回"/storage/emulated/0/Android/data/com.xxx.xxx/cache"目录
FileUtil.getExternalCacheDir();

/**
 * @param String type 所放的文件的类型,传入的参数是Environment类中的DIRECTORY_XXX静态变量
 * @return 返回"/storage/emulated/0/xxx"目录
 *         例如传入Environment.DIRECTORY_ALARMS则返回"/storage/emulated/0/Alarms"
 */
FileUtil.getExternalStoragePublicDirectory(type);

/**
 * @param String type 所放的文件的类型,传入的参数是Environment类中的DIRECTORY_XXX静态变量
 * @return  返回"/storage/emulated/0/Android/data/com.xxx.xxx/files/Alarms"目录
 *          例如传入Environment.DIRECTORY_ALARMS则返回"/storage/emulated/0/Android/data/com.xxx.xxx/files/Alarms"
 */
FileUtil.getExternalFilesDir(type);

xml布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:paddingLeft="@dimen/horizontal_page_margin"
              android:paddingRight="@dimen/horizontal_page_margin"
              android:paddingTop="@dimen/vertical_page_margin"
              android:paddingBottom="@dimen/vertical_page_margin"
              android:orientation="vertical"
    >

    <FrameLayout
        android:id="@+id/content_fragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Camera"
                    android:id="@+id/button_camera"
                    android:onClick="showCamera"/>

                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="RECORD_AUDIO"
                    android:onClick="recordAudio"/>
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="GET_ACCOUNTS"
                    android:onClick="getAccounts"/>

                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="CALL_PHONE"
                    android:onClick="callPhone"/>
            </LinearLayout>

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="PERMISSION_READ_PHONE_STATE"
                android:onClick="readPhoneState"/>

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="ACCESS_FINE_LOCATION"
                android:onClick="accessFineLocation"/>

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="ACCESS_COARSE_LOCATION"
                android:onClick="accessCoarseLocation"/>

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="READ_EXTERNAL_STORAGE"
                android:onClick="readExternalStorage"/>

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="WRITE_EXTERNAL_STORAGE"
                android:onClick="writeExternalStorage"/>

        </LinearLayout>
    </ScrollView>

</LinearLayout>

7. Activity栈管理

demo中提供了ActivityStackManager工具类,用于存放管理Activity栈。
应用流程:
1.在activity创立时调用pushOneActivity(Activity
activity)推入栈,可放于Activity基类中

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mStackManager = ActivityStackManager.getInstance();
    mStackManager.pushOneActivity(this);
}

2.在activity销毁时调用popOneActivity(Activity
activity)弹出栈,可放于Activity基类中

@Override
protected void onDestroy() {
    mStackManager.popOneActivity(this);
    super.onDestroy();
}

3.当你想要退出某个Activity时,可调用exitActivity(Class cls)

mStackManager.exitActivity(CollectActivity.class);

4.当您想要退出整个应用(所有Activity)时,可调用exitApplication()

mStackManager.exitApplication();

还提供了其他办法,具体请查看demo代码

清单文件申请的权能

  <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.READ_SMS"/>

    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>

8. SharedPreferences

demo中提供了PreferenceUtil工具类,用于SharedPreferences的数码插入、读取等操作。

  • 获取SharedPreferences

SharedPreferences sp = PreferenceUtil.getPreference(context, spName);
  • 安插数据

//int类型
PreferenceUtil.putInt(sp, key, value);
//String类型
PreferenceUtil.putString(sp, key, value);
//boolean类型
PreferenceUtil.putBoolean(sp, key, value);
//float类型
PreferenceUtil.putFloat(sp, key, value);
//long类型
PreferenceUtil.putLong(sp, key, value);
  • 读取数据

//int类型
PreferenceUtil.getInt(sp, key, defaultValue);
//String类型
PreferenceUtil.getString(sp, key, defaultValue);
//boolean类型
PreferenceUtil.getBoolean(sp, key, defaultValue);
//float类型
PreferenceUtil.getFloat(sp, key, defaultValue);
//long类型
PreferenceUtil.getLong(sp, key, defaultValue);

//读取所有数据,返回Map
PreferenceUtil.getAll(sp);
  • 清空数据

PreferenceUtil.clearAll(sp);

部分 资源文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="permissions">
        <item>@string/permission_recode_audio_hint</item>
        <item>@string/permission_get_accounts_hint</item>
        <item>@string/permission_read_phone_hint</item>
        <item>@string/permission_call_phone_hint</item>
        <item>@string/permission_camera_hint</item>
        <item>@string/permission_access_fine_location_hint</item>
        <item>@string/permission_access_coarse_location_hint</item>
        <item>@string/permission_read_external_hint</item>
        <item>@string/permission_white_external_hint</item>
    </string-array>
</resources>

 <string name="permission_get_accounts_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_GET_ACCOUNTS</string>
    <string name="permission_read_phone_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_READ_PHONE_STATE</string>
    <string name="permission_call_phone_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_CALL_PHONE</string>
    <string name="permission_camera_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_CAMERA</string>
    <string name="permission_access_fine_location_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_ACCESS_FINE_LOCATION</string>
    <string name="permission_access_coarse_location_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_ACCESS_COARSE_LOCATION</string>
    <string name="permission_read_external_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_READ_EXTERNAL_STORAGE</string>
    <string name="permission_white_external_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_WRITE_EXTERNAL_STORAGE</string>
    <string name="permission_recode_audio_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_RECORD_AUDIO</string>

9. Toast

demo中提供了ToastUtil工具类,方便吐司。
采纳流程
1.Application中最先化

ToastUtil.init(this);//初始化吐司

2.在要吐司的地方调用show

ToastUtil.show("hello world");

ToastUtil.show(R.string.appName);

10. 密度单位转换

demo提供了DensityUtil工具类,用于密度单位的变换

  • px转dp

int dp = DensityUtil.px2dp(context, px);
  • dp转px

int px = DensityUtil.dp2px(context, dp);
  • sp转px

int px = DensityUtil.sp2px(context, sp);
  • px转sp

int sp = DensityUtil.px2sp(context, px);

11. 高斯模糊

demo中提供了BlurUtil工具类,用于对Bitmap做高斯模糊处理,可以采取Java原生形式和RenderScript形式。

  • Java原生情势

//使用Java实现的高斯模糊效果(性能较低,模糊半径0-100,越大越模糊)
Bitmap bitmapAfter = BlurUtil.javaBlur(bitmapBefore, 15, true);
  • RenderScript方式

/**
* 使用RenderScript实现的高斯模糊效果(性能较高,模糊半径0-25,越大越模糊)
* 需在module下的build.gradle中加入
* renderscriptTargetApi 19
* renderscriptSupportModeEnabled true
*/
Bitmap bitmapAfter = BlurUtil.rsBlur(MyApplication.getInstance(), bitmapBefore, 15);

图片 12

高斯模糊效果

12. 加密

demo中提供了HashCoderUtil工具类,用于md5加密和sha1加密。

  • md5加密

String encrpt = HashCoderUtil.md5Crypt(password.getBytes());
//加盐值
String encrpt = HashCoderUtil.md5Crypt(password.getBytes(),salt);
  • sha1加密

String encrpt = HashCoderUtil.sha1Crypt(password.getBytes());
//加盐值
String encrpt = HashCoderUtil.sha1Crypt(password.getBytes(),salt);

13. 其他

demo中还提供了一个CommonUtil,负责一些相比杂碎的坚守,例如

  • 收获装备唯一ID号

String deviceId = CommonUtil.getDeviceUniqueId(context);
  • 始建/删除桌面急速模式

//创建
CommonUtil.creatShortcut(context);
//删除
CommonUtil.delShortcut(context);
  • 扩张View的触摸范围

//扩大view上下左右10个单位触摸的范围
CommonUtil.expandViewTouchDelegate(view,10,10,10,10);

另外,BlankJ提供了一个各类工具类的开源项目,我们各取所需呢。
https://github.com/Blankj/AndroidUtilCode/blob/master/README-CN.md


详尽代码请看demo,地址https://github.com/LJYcoder/DevBase
demo的内容流程,请看《安卓开发框架(MVP+主流框架+基类+工具类)—
开篇》

相关文章