- Gson、FastJson、org.JSON到底哪一个效率更高,速度更快- 
-- Try catch与throw new Exception的区别?
  Try catch可以捕获住异常,不让程序崩溃;
  throw new Exception 与 throws Exception抛出异常,不去处理,会导致程序崩溃。
 抛出异常,程序会崩溃吗,会的。-- WifiP2pManager 4.0,使用WiFi P2P需要Android API Level >= 14才可以;
 SDK4.1对应API 16;
  Android 4.1API WifiManager新特性;
  WifiP2P是在 Android 4.0 以上系统中加入的功能,通过WifiP2P可以在不连接网络的情况下,直接与配对的设备进行数据交换。他相比蓝牙传输速率更快,更远;相比网络传输过程中不会消耗流量。WifiP2P的传输依赖于无限WiFi,因此设备之间通信需要连接同一个WiFi网络。在WifiP2P技术中有一个核心类WifiP2pManager,他提供了所有的通信相关的广播信息,监听信息,设备信息以及初始化操作等。在信息传输过程中需要有个接收端接收信息和发送端发送信息,这里称为客户端和服务端,客户端和服务端通过WifiP2P作为传输手段,通过socket作为信息载体,进行通信。https://www.jianshu.com/p/14ec886bb624 android wifi 点对点传输- https://github.com/changchengfeng/WifiP2PSample
 Wi-Fi DirectAPI在Android 4.1中被增强以支持在WifiP2pManager中的预先关联服务发现。这允许在连接之前使用Wi-Fi Direct通过服务发现和筛选周围的设备。与此同时,Network ServiceDiscovery允许你在一个已存在并保持连接的网络上发现一个服务(例如一个本地的Wi-Fi网络)。-- 解决Android ImageView用setImageDrawable方法图片缩小的问题-
- setImageDrawable(getResources().getDrawable()但是发现在5.1中是过期的
 Android中getResources().getDrawable() 过时的解决方法-
  1.当你这个Drawable不受主题影响时
 ResourcesCompat.getDrawable(getResources(), R.drawable.name, null);
  2.当你这个Drawable受当前Activity主题的影响时
 ContextCompat.getDrawable(getActivity(), R.drawable.name);
  3.当你这个Drawable想使用另外一个主题样式时
 ResourcesCompat.getDrawable(getResources(), R.drawable.name, anotherTheme);Android中图片setImageResource和setBackgroundResource的区别
  刚好项目中碰到需要再一个button点击的时候进行图片的切换, 很简单的实现了,但是呢,之前使是iv_setBackgroundResource的方法来设置背景图片的切换,因为之前都是这么干的,可是这个翻水水了,会出现背景图片重叠阴影的问题,后面使用了setImageResource,直接去设置图片的资源路径就显示正常了。原因是现在的图片是带有阴影的背景的,所以设置setBackground会出现问题。
  
 在代码中为ImageView引用图片之setImageDrawable和setBackgroundResource- - 关于Java中null的十点详解- 
 String str = null;
 str = str+"hello";
 打印结果为:null hello-- TaskStackBuilder  API level16(4.1);4.0对应API是:14.
 关于TaskStackBuilder- 
 TaskStackBuilder  API level16(4.1)
 TaskStackBuilder可以构造一个合成的回退栈,主要用于跨任务导航,应用于Android3.0及新版本。
   我们通常利用返回键导航app,而返回键是基于当前任务的导航,这种局部的导航只有将当前任务中所有Activity结束掉时才返回上个任务,若从当前app跳转到另一app时就涉及到不同任务的跳转,也就是从任务一跳转到任务二时,从任务二中按返回键时无法直接返回到任务一,除非任务二中只存在一个Activity。
   为了提供更好的用户体验,在跨应用的跳转中,利用TaskStackBuilder的getPendingIntent(int requestCode, int flags),可将当前任务中的Activity和要启动的Activity合成为一个新的任务,而用户按返回键的操作就作用在这个新任务中,这相当于实现了跨任务直接跳转。
   若从任务一直接启动一个Intent去开启另一个应用的Activity,会直接把该Activity加入到这个应用的任务二中去,按返回键时最终只会回到主界面,而不会回到任务一。若要向老版本兼容可使用android.support.v4.app.TaskStackBuilder实现相同效果。
 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
             TaskStackBuilder stackBuilder = TaskStackBuilder.create(mActivity);
             stackBuilder.addParentStack(CarActivity.class);
             stackBuilder.addNextIntent(intent);
             PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
                     PendingIntent.FLAG_UPDATE_CURRENT);            builder.setContentIntent(resultPendingIntent);
            NotificationManager notificationManager = (NotificationManager) mActivity
                     .getSystemService(Context.NOTIFICATION_SERVICE);
             Notification n = builder.build();
             n.flags = n.flags | Notification.FLAG_AUTO_CANCEL;
             notificationManager.notify(notificationFinished, n);
         } else {
             android.support.v4.app.TaskStackBuilder stackBuilder = android.support.v4.app.TaskStackBuilder.create(mActivity);
             stackBuilder.addParentStack(CarActivity.class);
             stackBuilder.addNextIntent(intent);
             PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
                     PendingIntent.FLAG_UPDATE_CURRENT);            builder.setContentIntent(resultPendingIntent);
            NotificationManager notificationManager = (NotificationManager) mActivity
                     .getSystemService(Context.NOTIFICATION_SERVICE);
             Notification n = builder.build();
             n.flags = n.flags | Notification.FLAG_AUTO_CANCEL;
             notificationManager.notify(notificationFinished, n);
         }private static long getTotalSize(String path) {
         StatFs fileStats = new StatFs(path);
         fileStats.restat(path);
         if (Build.VERSION.SDK_INT >= 18) {
             return (long) fileStats.getBlockCountLong() * fileStats.getBlockSizeLong();
         } else {
             return (long) fileStats.getBlockCount() * fileStats.getBlockSize();
         }
     }Canvas.saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int saveFlags):
本身和save方法差不多,但是它单独分配了一个画布用于绘制图层。它定义了一个画布区域(可设置透明度),此方法之后的所有绘制都在此区域中绘制,直到调用canvas.restore()方法。例如:在调用saveLayerAlpha方法之前绘制了一个“圆形”,在调用saveLayerAlpha方法之后绘制了一个“圆形”此时这两个圆形并不在同一个图层。下面给出一个例子以及样图来说明这个问题。
-- Thread.run(),start()
     调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void.。
  
   Thread的run()与start()的区别- 
  1.start()方法来启动线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码;通过调用Thread类的start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行操作的, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。 
   用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。
  2.run()方法当作普通方法的方式调用。程序还是要顺序执行,要等待run方法体执行完毕后,才可继续执行下面的代码; 程序中只有主线程——这一个线程, 其程序执行路径还是只有一条, 这样就没有达到写线程的目的。
   run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。public class Test {  
     public static void main(String[] args) {  
         Runner1 runner1 = new Runner1();  
         Runner2 runner2 = new Runner2();  
 //      Thread(Runnable target) 分配新的 Thread 对象。  
         Thread thread1 = new Thread(runner1);  
         Thread thread2 = new Thread(runner2);  
 //      thread1.start();  
 //      thread2.start();  
         thread1.run();  
         thread2.run();  
     }  
 }  
 class Runner1 implements Runnable { // 实现了Runnable接口,jdk就知道这个类是一个线程  
     public void run() {  
         for (int i = 0; i < 100; i++) {  
             System.out.println("进入Runner1运行状态——————————" + i);  
         }  
     }  
 }  
 class Runner2 implements Runnable { // 实现了Runnable接口,jdk就知道这个类是一个线程  
     public void run() {  
         for (int i = 0; i < 100; i++) {  
             System.out.println("进入Runner2运行状态==========" + i);  
         }  
     }  
 }  -- 提供的SwitchButton-https://github.com/kyleduo/SwitchButton
-- canvas.saveLayerAlpha
 // canvas.saveLayerAlpha(RectF bounds, int alpha, int saveFlags) 在API26被废弃,Canvas下Flag常量在API27
 //   canvas.saveLayerAlpha(mSaveLayerRectF, mAlpha, Canvas.MATRIX_SAVE_FLAG
 //                | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
 //                | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
         canvas.saveLayerAlpha ( mSaveLayerRectF , mAlpha ); View.setBackground上下版本兼容型的问题
 int sdk = android.os.Build.VERSION.SDK_INT;
         if (sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
             setBackgroundDrawable( drawable );
         }
         else {
             setBackground( drawable );
         }if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
                     setBackgroundDrawable( null );
                 }
                 else {
                     setBackground( null );
                 }LeftBtn.setBackground(ContextCompat.getDrawable(mActivity, R.drawable.guide_btn_prev_prss));
-- RenderScript; ScriptIntrinsicBlur sdk4.2
 AndroidStudio中使用V8包中的RenderScript,只需要修改项目的build.gradle中的代码即可
 对于android gradle plugin v0.14+:
 android {
     ...
     defaultConfig {
         ...
         renderscriptTargetApi 19
         renderscriptSupportModeEnabled true
     }
     ...
 }
 在android gradle plugin v0.13.3及以前的版本中:
 android {
         ...
         defaultConfig {
             ...
             renderscriptTargetApi 19
             renderscriptSupportMode true
         }
         ...
     }
 之后,我们就可以在2.2以上的代码中使用v8包中的RenderScript了,如:
 import android.support.v8.renderscript.* android.renderscript.ScriptIntrinsicBlur 4.2导致这个问题就是因为这个api不能向下兼容,现在我们就来解决这个问题。其实google早就提供了方案,我们只需要使用就好了。
 1、引入renderscript-v8.jar(将jar包放在libs目录下,add to build path)-- Android 8.0 利用Settings.Global属性跨应用定义标志位-
   系统级别应用
 在需要定义的地方使用 SystemProperties.set(“dev.xxx.xxx”, “false”);
 在获取的部分使用 SystemProperties.getBoolean(“ro.mmitest”, false))
 最后记得要导包 import android.os.SystemProperties
   非系统级别应用
 在需要定义的地方使用 Settings.Global.putInt(context.getContentResolver(),“xxx.xxx”,1);
 在获取的部分使用 boolean mTag = Settings.Global.getInt(getActivity().getContentResolver(),“xxx.xxx”, 0) == 1;
 依旧别忘记导包 import android.provider.Settings;Android实践 -- 设置系统日期时间和时区-https://www.jianshu.com/p/6c6a6091545d
 <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
 <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>--适配未知来源的管理权限,手机兼容刘海屏解决方案
 关于Android各个类型手机兼容刘海屏解决方案- 
 Android中系统应用适配未知来源的管理权限-
 Android中为了防止一些不良应用的随便静默安装,设置了未知来源应用的开关,在不同的android版本中使上会有所区别
 /**
      * 打开未知来源权限
      * @param context
      */
     public static void openNonMarketAppsPerm(Context context){
         if (Build.VERSION.SDK_INT < 17) {
             int flag = Settings.Secure.getInt(context.getContentResolver(),
                     Settings.Secure.INSTALL_NON_MARKET_APPS, 0);
             if(flag == 0){
                 Settings.Secure.putInt(context.getContentResolver(),
                         Settings.Secure.INSTALL_NON_MARKET_APPS, 1);
             }
         } else {
             int flag = Settings.Global.getInt(context.getContentResolver(),
                     Settings.Global.INSTALL_NON_MARKET_APPS, 0);
             if(flag == 0){
                 Settings.Global.putInt(context.getContentResolver(),
                         Settings.Global.INSTALL_NON_MARKET_APPS, 1);
             }
         }
     }
  /**
      * 关闭未知来源权限
      * @param context
      */
     public static void closeNonMarketAppsPerm(Context context){
         if (Build.VERSION.SDK_INT < 17) {
             int flag = Settings.Secure.getInt(context.getContentResolver(),
                     Settings.Secure.INSTALL_NON_MARKET_APPS, 1);
             if(flag == 1) {
                 Settings.Secure.putInt(context.getContentResolver(),
                         Settings.Secure.INSTALL_NON_MARKET_APPS, 0);
             }
         } else {
             int flag= Settings.Global.getInt(context.getContentResolver(),
                     Settings.Global.INSTALL_NON_MARKET_APPS, 1);
             if (flag==1){
                 Settings.Global.putInt(context.getContentResolver(),
                         Settings.Global.INSTALL_NON_MARKET_APPS, 0);
             }
         }
     }    /**
      * 检查状态是否打开
      * @param context
      */
     public static boolean checkNonMarketAppsPermStatus(Context context){
         boolean unKnowSource=false;
         if (Build.VERSION.SDK_INT<17){
             unKnowSource=Settings.Secure.getInt(context.getContentResolver(),
                     Settings.Secure.INSTALL_NON_MARKET_APPS, 0)==1;
         }else{
             unKnowSource=Settings.Global.getInt(context.getContentResolver(),
                     Settings.Global.INSTALL_NON_MARKET_APPS, 0)==1;
         }
         return unKnowSource;
     }
  如果兼容4.0以下版本则需要把Settings.Secure 和Settings.Global 改为:Settings.System方式获取未知来源的状态或修改状态- wait(),notify/notifyAll
  当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。
  当执行notify/notifyAll方法时,会唤醒一个处于等待该 对象锁 的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁。