最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android10填坑適配指南(實際經(jīng)驗代碼)

 更新時間:2019年11月26日 10:09:29   作者:黃海彬  
這篇文章主要介紹了Android10填坑適配指南(實際經(jīng)驗代碼),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

今天看到一篇好的文章,分享給大家,膜拜大佬。

Android10填坑適配指南,包含實際經(jīng)驗代碼,絕不照搬翻譯文檔

1.Region.Op相關異常:java.lang.IllegalArgumentException: Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed

當 targetSdkVersion >= Build.VERSION_CODES.P 時調(diào)用 canvas.clipPath(path, Region.Op.XXX); 引起的異常,參考源碼如下:

@Deprecated
public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) {
  checkValidClipOp(op);
  return nClipPath(mNativeCanvasWrapper, path.readOnlyNI(), op.nativeInt);
}

private static void checkValidClipOp(@NonNull Region.Op op) {
  if (sCompatiblityVersion >= Build.VERSION_CODES.P
   && op != Region.Op.INTERSECT && op != Region.Op.DIFFERENCE) {
   throw new IllegalArgumentException(
     "Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed");
  }
}

我們可以看到當目標版本從Android P開始,Canvas.clipPath(@NonNull Path path, @NonNull Region.Op op) ; 已經(jīng)被廢棄,而且是包含異常風險的廢棄API,只有 Region.Op.INTERSECT 和 Region.Op.DIFFERENCE 得到兼容,幾乎所有的博客解決方案都是如下簡單粗暴:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
 canvas.clipPath(path);
} else {
 canvas.clipPath(path, Region.Op.XOR);// REPLACE、UNION 等
}

但我們一定需要一些高級邏輯運算效果怎么辦?如小說的仿真翻頁閱讀效果,解決方案如下,用Path.op代替,先運算Path,再

給canvas.clipPath:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
 Path mPathXOR = new Path();
 mPathXOR.moveTo(0,0);
 mPathXOR.lineTo(getWidth(),0);
 mPathXOR.lineTo(getWidth(),getHeight());
 mPathXOR.lineTo(0,getHeight());
 mPathXOR.close();
 //以上根據(jù)實際的Canvas或View的大小,畫出相同大小的Path即可
 mPathXOR.op(mPath0, Path.Op.XOR);
 canvas.clipPath(mPathXOR);
}else {
 canvas.clipPath(mPath0, Region.Op.XOR);
}

2.明文HTTP限制

當 targetSdkVersion >= Build.VERSION_CODES.P 時,默認限制了HTTP請求,并出現(xiàn)相關日志:

java.net.UnknownServiceException: CLEARTEXT communication to xxx not permitted by network security policy

第一種解決方案:在AndroidManifest.xml中Application添加如下節(jié)點代碼

<application android:usesCleartextTraffic="true">

第二種解決方案:在res目錄新建xml目錄,已建的跳過 在xml目錄新建一個xml文件network_security_config.xml,然后在AndroidManifest.xml中Application添加如下節(jié)點代碼

android:networkSecurityConfig="@xml/network_config"

名字隨機,內(nèi)容如下:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
 <base-config cleartextTrafficPermitted="true" />
</network-security-config>

3.Android Q中的媒體資源讀寫

1、掃描系統(tǒng)相冊、視頻等,圖片、視頻選擇器都是通過ContentResolver來提供,主要代碼如下:

private static final String[] IMAGE_PROJECTION = {
   MediaStore.Images.Media.DATA,
   MediaStore.Images.Media.DISPLAY_NAME,
   MediaStore.Images.Media._ID,
   MediaStore.Images.Media.BUCKET_ID,
   MediaStore.Images.Media.BUCKET_DISPLAY_NAME};

 Cursor imageCursor = mContext.getContentResolver().query(
     MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
     IMAGE_PROJECTION, null, null, IMAGE_PROJECTION[0] + " DESC");

String path = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[0]));
String name = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[1]));
int id = imageCursor.getInt(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[2]));
String folderPath = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[3]));
String folderName = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[4]));

//Android Q 公有目錄只能通過Content Uri + id的方式訪問,以前的File路徑全部無效,如果是Video,記得換成MediaStore.Videos
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
  path = MediaStore.Images.Media
      .EXTERNAL_CONTENT_URI
      .buildUpon()
      .appendPath(String.valueOf(id)).build().toString();
 }

2、判斷公有目錄文件是否存在,自Android Q開始,公有目錄File API都失效,不能直接通過new File(path).exists();判斷公有目錄文件是否存在,正確方式如下:

public static boolean isAndroidQFileExists(Context context, String path){
  AssetFileDescriptor afd = null;
  ContentResolver cr = context.getContentResolver();
  try {
   Uri uri = Uri.parse(path);
   afd = cr.openAssetFileDescriptor(uri, "r");
   if (afd == null) {
    return false;
   } else {
    close(afd);
   }
  } catch (FileNotFoundException e) {
   return false;
  }finally {
   close(afd);
  }
  return true;
}

3、copy或者下載文件到公有目錄,保存Bitmap同理,如Download,MIME_TYPE類型可以自行參考對應的文件類型,這里只對APK作出說明,從私有目錄copy到公有目錄demo如下(遠程下載同理,只要拿到OutputStream即可,亦可下載到私有目錄再copy到公有目錄):

public static void copyToDownloadAndroidQ(Context context, String sourcePath, String fileName, String saveDirName){
  ContentValues values = new ContentValues();
  values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
  values.put(MediaStore.Downloads.MIME_TYPE, "application/vnd.android.package-archive");
  values.put(MediaStore.Downloads.RELATIVE_PATH, "Download/" + saveDirName.replaceAll("/","") + "/");

  Uri external = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
  ContentResolver resolver = context.getContentResolver();

  Uri insertUri = resolver.insert(external, values);
  if(insertUri == null) {
   return;
  }

  String mFilePath = insertUri.toString();

  InputStream is = null;
  OutputStream os = null;
  try {
   os = resolver.openOutputStream(insertUri);
   if(os == null){
    return;
   }
   int read;
   File sourceFile = new File(sourcePath);
   if (sourceFile.exists()) { // 文件存在時
    is = new FileInputStream(sourceFile); // 讀入原文件
    byte[] buffer = new byte[1444];
    while ((read = is.read(buffer)) != -1) {
     os.write(buffer, 0, read);
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }finally {
   close(is,os);
  }

}

4、保存圖片相關

 /**
  * 通過MediaStore保存,兼容AndroidQ,保存成功自動添加到相冊數(shù)據(jù)庫,無需再發(fā)送廣播告訴系統(tǒng)插入相冊
  *
  * @param context  context
  * @param sourceFile 源文件
  * @param saveFileName 保存的文件名
  * @param saveDirName picture子目錄
  * @return 成功或者失敗
  */
 public static boolean saveImageWithAndroidQ(Context context,
             File sourceFile,
             String saveFileName,
             String saveDirName) {
  String extension = BitmapUtil.getExtension(sourceFile.getAbsolutePath());

  ContentValues values = new ContentValues();
  values.put(MediaStore.Images.Media.DESCRIPTION, "This is an image");
  values.put(MediaStore.Images.Media.DISPLAY_NAME, saveFileName);
  values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
  values.put(MediaStore.Images.Media.TITLE, "Image.png");
  values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/" + saveDirName);

  Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
  ContentResolver resolver = context.getContentResolver();

  Uri insertUri = resolver.insert(external, values);
  BufferedInputStream inputStream = null;
  OutputStream os = null;
  boolean result = false;
  try {
   inputStream = new BufferedInputStream(new FileInputStream(sourceFile));
   if (insertUri != null) {
    os = resolver.openOutputStream(insertUri);
   }
   if (os != null) {
    byte[] buffer = new byte[1024 * 4];
    int len;
    while ((len = inputStream.read(buffer)) != -1) {
     os.write(buffer, 0, len);
    }
    os.flush();
   }
   result = true;
  } catch (IOException e) {
   result = false;
  } finally {
   close(os, inputStream);
  }
  return result;
}

4.EditText默認不獲取焦點,不自動彈出鍵盤

該問題出現(xiàn)在 targetSdkVersion >= Build.VERSION_CODES.P 情況下,且設備版本為Android P以上版本,解決方法在onCreate中加入如下代碼,可獲得焦點,如需要彈出鍵盤可延遲一下:

mEditText.post(() -> {
  mEditText.requestFocus();
  mEditText.setFocusable(true);
  mEditText.setFocusableInTouchMode(true);
});

5.安裝APK Intent及其它共享文件相關Intent

/*
* 自Android N開始,是通過FileProvider共享相關文件,但是Android Q對公有目錄 File API進行了限制,只能通過Uri來操作,
* 從代碼上看,又變得和以前低版本一樣了,只是必須加上權限代碼Intent.FLAG_GRANT_READ_URI_PERMISSION
*/ 
private void installApk() {
  if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
   //適配Android Q,注意mFilePath是通過ContentResolver得到的,上述有相關代碼
   Intent intent = new Intent(Intent.ACTION_VIEW);
   intent.setDataAndType(Uri.parse(mFilePath) ,"application/vnd.android.package-archive");
   intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
   startActivity(intent);
   return ;
  }

  File file = new File(saveFileName + "demo.apk");
  if (!file.exists())
   return;
  Intent intent = new Intent(Intent.ACTION_VIEW);
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
   intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
   Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "net.oschina.app.provider", file);
   intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
  } else {
   intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
   intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  }
  startActivity(intent);
}

6.Activity透明相關,windowIsTranslucent屬性

Android Q 又一個天坑,如果你要顯示一個半透明的Activity,這在android10之前普通樣式Activity只需要設置windowIsTranslucent=true即可,但是到了AndroidQ,它沒有效果了,而且如果動態(tài)設置View.setVisibility(),界面還會出現(xiàn)殘影...

解決辦法:使用Dialog樣式Activity,且設置windowIsFloating=true,此時問題又來了,如果Activity根布局沒有設置fitsSystemWindow=true,默認是沒有侵入狀態(tài)欄的,使界面看上去正常。

7.剪切板兼容

Android Q中只有當應用處于可交互情況(默認輸入法本身就可交互)才能訪問剪切板和監(jiān)聽剪切板變化,在onResume回調(diào)也無法直接訪問剪切板,這么做的好處是避免了一些應用后臺瘋狂監(jiān)聽響應剪切板的內(nèi)容,瘋狂彈窗。

因此如果還需要監(jiān)聽剪切板,可以使用應用生命周期回調(diào),監(jiān)聽APP后臺返回,延遲幾毫秒訪問剪切板,再保存最后一次訪問得到的剪切板內(nèi)容,每次都比較一下是否有變化,再進行下一步操作。

8.第三方分享圖片等操作,直接使用文件路徑的,如QQ圖片分享,都需要注意,這是不可行的,都只能通過MediaStore等API,拿到Uri來操作

這些是我們根據(jù)sdk升級到29時遇到的實際問題而羅列出來的,不是翻譯AndroidQ中的行為變更,具體問題請根據(jù)自身實際自行解決。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Android編程監(jiān)聽APK安裝與刪除等過程的方法

    Android編程監(jiān)聽APK安裝與刪除等過程的方法

    這篇文章主要介紹了Android編程監(jiān)聽APK安裝與刪除等過程的方法,涉及Android事件監(jiān)聽、權限控制、廣播操作等相關實現(xiàn)技巧,需要的朋友可以參考下
    2017-10-10
  • Android實現(xiàn)短信驗證碼獲取自動填寫功能(詳細版)

    Android實現(xiàn)短信驗證碼獲取自動填寫功能(詳細版)

    這篇文章主要為大家詳細介紹了Android實現(xiàn)短信驗證碼獲取自動填寫功能,很實用的功能分享給大家,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Android自定義帶水滴的進度條樣式(帶漸變色效果)

    Android自定義帶水滴的進度條樣式(帶漸變色效果)

    這篇文章主要介紹了Android自定義帶水滴的進度條樣式(帶漸變色效果)的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-12-12
  • Android四大組件之BroadcastReceiver詳解

    Android四大組件之BroadcastReceiver詳解

    今天小編就為大家分享一篇關于Android四大組件之BroadcastReceiver詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Android自定義View實現(xiàn)帶4圓角或者2圓角的效果

    Android自定義View實現(xiàn)帶4圓角或者2圓角的效果

    這篇文章主要介紹了Android自定義View實現(xiàn)帶4圓角或者2圓角的效果,本文通過實例代碼截圖給大家展示的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • Android實現(xiàn)動態(tài)高斯模糊背景效果

    Android實現(xiàn)動態(tài)高斯模糊背景效果

    在現(xiàn)代 Android UI 中,動態(tài)高斯模糊背景 常見于對話框或彈窗后面的模糊遮罩,相比靜態(tài)模糊圖,動態(tài)模糊可隨著內(nèi)容滾動或變化實時更新,使界面更具層次感與沉浸感,所以本文給大家介紹了Android實現(xiàn)動態(tài)高斯模糊背景效果,需要的朋友可以參考下
    2025-04-04
  • android TabLayout使用方法詳解

    android TabLayout使用方法詳解

    這篇文章主要為大家詳細介紹了android TabLayout使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Android多線程斷點續(xù)傳下載示例詳解

    Android多線程斷點續(xù)傳下載示例詳解

    這篇文章主要為大家詳細介紹了Android多線程斷點續(xù)傳下載示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Android客制化adb shell進去后顯示shell@xxx的標識

    Android客制化adb shell進去后顯示shell@xxx的標識

    今天小編就為大家分享一篇關于Android客制化adb shell進去后顯示shell@xxx的標識,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Android AutoCompleteTextView控件使用實例

    Android AutoCompleteTextView控件使用實例

    AutoCompleteTextView這個控件用于輸入框的自動完成提示,非常適合搜索框等。它本質上是個EditText,實際上它也是從EditText繼承的,使用起來也十分簡單
    2014-04-04

最新評論

甘孜县| 昭苏县| 湄潭县| 清新县| 万州区| 攀枝花市| 嘉禾县| 长丰县| 河源市| 北宁市| 城步| 上饶市| 宝应县| 南木林县| 两当县| 靖安县| 定襄县| 商水县| 西乌| 都江堰市| 台前县| 沁水县| 鄱阳县| 南部县| 库尔勒市| 潞西市| 昌黎县| 长丰县| 安化县| 千阳县| 临猗县| 五寨县| 三河市| 武强县| 保德县| 定兴县| 大庆市| 新建县| 怀远县| 庆安县| 阿拉善左旗|