1. 程式人生 > >Android API相容,其他API,UI適配(2)

Android API相容,其他API,UI適配(2)

- Gson、FastJson、org.JSON到底哪一個效率更高,速度更快- https://blog.csdn.net/zml_2015/article/details/52165317

-- 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方法圖片縮小的問題-https://blog.csdn.net/changemyself/article/details/43054933

- setImageDrawable(getResources().getDrawable()但是發現在5.1中是過期的
Android中getResources().getDrawable() 過時的解決方法-https://blog.csdn.net/xu20082100226/article/details/72625266
 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- https://blog.csdn.net/languobeibei/article/details/69389153

- 關於Java中null的十點詳解- https://www.cnblogs.com/greatfish/p/5906617.html
String str = null;
str = str+"hello";
列印結果為:null hello

-- TaskStackBuilder  API level16(4.1);4.0對應API是:14.
關於TaskStackBuilder- https://www.cnblogs.com/aheiabai/p/5931536.html
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()的區別- https://blog.csdn.net/qiumeng_1314/article/details/79466655
 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屬性跨應用定義標誌位-https://blog.csdn.net/ouzhuangzhuang/article/details/82258148
  系統級別應用
在需要定義的地方使用 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各個型別手機相容劉海屏解決方案- https://blog.csdn.net/mr_zengkun/article/details/80984117
Android中系統應用適配未知來源的管理許可權-https://blog.csdn.net/zdc9023/article/details/78861822
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修飾的程式碼塊)後再釋放鎖。