成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

老司機淡飆車技術:Android7.0適配心得

移動開發 Android
Android7.0發布已經有一個多月了,Android7.0在給用戶帶來一些新的特性的同時,也給開發者帶來了新的挑戰,這幾天我將應用適配到Android7.0,其中也遇到了不少問題也踩了一些坑,在這里就把我在Android7.0適配上的一些心得分享給大家,讓大家的應用能早一天跑在Android7.0上。

Android7.0發布已經有一個多月了,Android7.0在給用戶帶來一些新的特性的同時,也給開發者帶來了新的挑戰,這幾天我將應用適配到Android7.0,其中也遇到了不少問題也踩了一些坑,在這里就把我在Android7.0適配上的一些心得分享給大家,讓大家的應用能早一天跑在Android7.0上。

權限更改

隨著Android版本越來越高,Android對隱私的保護力度也越來越大。從Android6.0引入的動態權限控制(Runtime Permissions)到Android7.0的“私有目錄被限制訪問”,“StrictMode API 政策”。這些更改在為用戶帶來更加安全的操作系統的同時也為開發者帶來了一些新的任務。如何讓你的APP能夠適應這些改變而不是cash,是擺在每一位Android開發者身上的責任。

目錄被限制訪問

一直以來,在目錄及文件的訪問保護方面iOS做的是很到位的,如:iOS的沙箱機制。但,Android在這方面的保護就有些偏弱了,在Android中應用可以讀寫手機存儲中任何一個目錄及文件,這也帶來了很多的安全問題。現在Android也在著力解決這一問題。

在Android7.0中為了提高私有文件的安全性,面向 Android N 或更高版本的應用私有目錄將被限制訪問。對于這個權限的更改開發者需要留意一下改變:

  • 私有文件的文件權限不在放權給所有的應用,使用 MODE_WORLD_READABLE 或 MODE_WORLD_WRITEABLE 進行的操作將觸發 SecurityException。

應對策略:這項權限的變更將意味著你無法通過File API訪問手機存儲上的數據了,基于File API的一些文件瀏覽器等也將受到很大的影響,看到這大家是不是驚呆了呢,不過迄今為止,這種限制尚不能完全執行。 應用仍可能使用原生 API 或 File API 來修改它們的私有目錄權限。 但是,Android官方強烈反對放寬私有目錄的權限??梢钥闯鍪掌饘λ接形募脑L問權限是Android將來發展的趨勢。

  • 給其他應用傳遞 file:// URI 類型的Uri,可能會導致接受者無法訪問該路徑。 因此,在Android7.0中嘗試傳遞 file:// URI 會觸發 FileUriExposedException。

應對策略:大家可以通過使用FileProvider來解決這一問題。

  • DownloadManager 不再按文件名分享私人存儲的文件。COLUMN_LOCAL_FILENAME在Android7.0中被標記為deprecated , 舊版應用在訪問 COLUMN_LOCAL_FILENAME時可能出現無法訪問的路徑。 面向 Android N 或更高版本的應用在嘗試訪問 COLUMN_LOCAL_FILENAME 時會觸發 SecurityException。

應對策略:大家可以通過ContentResolver.openFileDescriptor()來訪問由 DownloadManager 公開的文件。

應用間共享文件

在Android7.0系統上,Android 框架強制執行了 StrictMode API 政策禁止向你的應用外公開 file:// URI。 如果一項包含文件 file:// URI類型 的 Intent 離開你的應用,應用失敗,并出現 FileUriExposedException 異常,如調用系統相機拍照,或裁切照片。

應對策略:若要在應用間共享文件,可以發送 content:// URI類型的Uri,并授予 URI 臨時訪問權限。 進行此授權的最簡單方式是使用 FileProvider類。 如需有關權限和共享文件的更多信息,請參閱共享文件。

在Android7.0上調用系統相機拍照,裁切照片

調用系統相機拍照

在Android7.0之前,如果你想調用系統相機拍照可以通過以下代碼來進行:

  1. File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg"); 
  2.  
  3. if (!file.getParentFile().exists())file.getParentFile().mkdirs(); 
  4.  
  5. Uri imageUri = Uri.fromFile(file); 
  6.  
  7. Intent intent = new Intent(); 
  8.  
  9. intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設置Action為拍照 
  10.  
  11. intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//將拍取的照片保存到指定URI 
  12.  
  13. startActivityForResult(intent,1006);   

 

 

 

在Android7.0上使用上述方式調用系統相拍照會拋出如下異常:

  1. android.os.FileUriExposedException: file:////storage/emulated/0/temp/1474956193735.jpg exposed beyond app through Intent.getData()at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)at android.net.Uri.checkFileUriExposed(Uri.java:2346)at android.content.Intent.prepareToLeaveProcess(Intent.java:8933)at android.content.Intent.prepareToLeaveProcess(Intent.java:8894)at android.app.Instrumentation.execStartActivity(Instrumentation.java:1517)at android.app.Activity.startActivityForResult(Activity.java:4223)...at android.app.Activity.startActivityForResult(Activity.java:4182) 

  

這是由于Android7.0執行了“StrictMode API 政策禁”的原因,不過小伙伴們不用擔心,上文講到了可以用FileProvider來解決這一問題, 現在我們就來一步一步的解決這個問題。

使用FileProvider

使用FileProvider的大致步驟如下:

第一步:在manifest清單文件中注冊provider

  1. <provider 
  2.  
  3.     android:name="android.support.v4.content.FileProvider" 
  4.  
  5.     android:authorities="com.jph.takephoto.fileprovider" 
  6.  
  7.     android:grantUriPermissions="true" 
  8.  
  9.     android:exported="false"
  10.  
  11.     <meta-data 
  12.  
  13.         android:name="android.support.FILE_PROVIDER_PATHS" 
  14.  
  15.         android:resource="@xml/file_paths" /> 
  16.  
  17. </provider>  

心得:exported:要求必須為false,為true則會報安全異常。grantUriPermissions:true,表示授予 URI 臨時訪問權限。

第二步:指定共享的目錄

為了指定共享的目錄我們需要在資源(res)目錄下創建一個xml目錄,然后創建一個名為“file_paths”(名字可以隨便起,只要和在manifest注冊的provider所引用的resource保持一致即可)的資源文件,內容如下:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2.  
  3. <resources> 
  4.  
  5.     <paths> 
  6.  
  7.         <external-path path="" name="camera_photos" /> 
  8.  
  9.     </paths> 
  10.  
  11. </resources>  
  • 代表的根目錄: Context.getFilesDir()
  • 代表的根目錄: Environment.getExternalStorageDirectory()
  • 代表的根目錄: getCacheDir()

心得:上述代碼中path="",是有特殊意義的,它代碼根目錄,也就是說你可以向其它的應用共享根目錄及其子目錄下任何一個文件了,如果你將path設為path="pictures", 那么它代表著根目錄下的pictures目錄(eg:/storage/emulated/0/pictures),如果你向其它應用分享pictures目錄范圍之外的文件是不行的。

第三步:使用FileProvider

上述準備工作做完之后,現在我們就可以使用FileProvider了。

還是以調用系統相機拍照為例,我們需要將上述拍照代碼修改為如下:

  1. File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg"); 
  2.  
  3. if (!file.getParentFile().exists())file.getParentFile().mkdirs(); 
  4.  
  5. Uri imageUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", file);//通過FileProvider創建一個content類型的Uri 
  6.  
  7. Intent intent = new Intent(); 
  8.  
  9. intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加這一句表示對目標應用臨時授權該Uri所代表的文件 
  10.  
  11. intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設置Action為拍照 
  12.  
  13. intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//將拍取的照片保存到指定URI 
  14.  
  15. startActivityForResult(intent,1006);  

上述代碼中主要有兩處改變:

  1. 將之前Uri的scheme類型為file的Uri改成了有FileProvider創建一個content類型的Uri。
  2. 添加了intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);來對目標應用臨時授權該Uri所代表的文件。

心得:上述代碼通過FileProvider的Uri getUriForFile (Context context, String authority, File file) 靜態方法來獲取Uri,該方法中authority參數就是清單文件中注冊provider的android:authorities="com.jph.takephoto.fileprovider"。 對Web服務器如tomcat,IIS比較熟悉的小伙伴,都只知道為了網站內容的安全和高效,Web服務器都支持為網站內容設置一個虛擬目錄,其實FileProvider也有異曲同工之處。

將getUriForFile方法獲取的Uri打印出來如下:

  1. content://com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg`。   

其中camera_photos就是file_paths.xml中paths的name。

因為上述指定的path為path="",所以content://com.jph.takephoto.fileprovider/camera_photos/代表的真實路徑就是根目錄,即:/storage/emulated/0/。

content://com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg代表的真實路徑是:/storage/emulated/0/temp/1474960080319.jpg。

另外,推薦大家使用開源工具庫TakePhoto, TakePhoto是一款在Android設備上獲取照片(拍照或從相冊、文件中選擇)、裁剪圖片、壓縮圖片的開源工具庫。

裁切照片

在Android7.0之前,你可以通過如下方法來裁切照片:

  1. File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg"); 
  2.  
  3. if (!file.getParentFile().exists())file.getParentFile().mkdirs(); 
  4.  
  5. Uri outputUri = Uri.fromFile(file); 
  6.  
  7. Uri imageUri=Uri.fromFile(new File("/storage/emulated/0/temp/1474960080319.jpg")); 
  8.  
  9. Intent intent = new Intent("com.android.camera.action.CROP"); 
  10.  
  11. intent.setDataAndType(imageUri, "image/*"); 
  12.  
  13. intent.putExtra("crop""true"); 
  14.  
  15. intent.putExtra("aspectX", 1); 
  16.  
  17. intent.putExtra("aspectY", 1); 
  18.  
  19. intent.putExtra("scale"true); 
  20.  
  21. intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); 
  22.  
  23. intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); 
  24.  
  25. intent.putExtra("noFaceDetection"true); // no face detection 
  26.  
  27. startActivityForResult(intent,1008);  

和拍照一樣,上述代碼在Android7.0上同樣會引起android.os.FileUriExposedException異常,解決辦法就是上文說說的使用FileProvider。

然后,將上述代碼改為如下即可:

  1. File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");if (!file.getParentFile().exists())file.getParentFile().mkdirs();Uri outputUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider",file);Uri imageUri=FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg");//通過FileProvider創建一個content類型的UriIntent intent = new Intent("com.android.camera.action.CROP");intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);intent.setDataAndType(imageUri, "image/*");intent.putExtra("crop""true");intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);intent.putExtra("scale"true);intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());intent.putExtra("noFaceDetection"true); // no face detectionstartActivityForResult(intent,1008); 

另外,裁切照片推薦大家使用開源工具庫TakePhoto, TakePhoto是一款在Android設備上獲取照片(拍照或從相冊、文件中選擇)、裁剪圖片、壓縮圖片的開源工具庫。

電池和內存

Android 6.0(API 級別 23)引入了低電耗模式,Android7.0在電池和內存上又做了進一步優化, 來減少Android應用對電量的消耗以及對內存的占用。這些優化所帶來的一些規則的變更可能會影響你的應用訪問系統資源,以及你的系統通過特定隱式 Intent 與其他應用互動的方式。 所以開發人員需要特別注意這些改變。

低電耗模式

在低電耗模式下,當用戶設備未插接電源、處于靜止狀態且屏幕關閉時,該模式會推遲 CPU 和網絡活動,從而延長電池壽命。 Android7.0通過在設備未插接電源且屏幕關閉狀態下、但不一定要處于靜止狀態(例如用戶外出時把手持式設備裝在口袋里)時應用部分 CPU 和網絡限制,進一步增強了低電耗模式。

也就是說,Android7.0會在手機屏幕關閉的狀態下,限時應用對CPU以及網絡的使用。

具體規則如下:

  1. 當設備處于充電狀態且屏幕已關閉一定時間后,設備會進入低電耗模式并應用第一部分限制: 關閉應用網絡訪問、推遲作業和同步。
  2. 如果進入低電耗模式后設備處于靜止狀態達到一定時間,系統則會對 PowerManager.WakeLock、AlarmManager 鬧鈴、GPS 和 Wi-Fi 掃描應用余下的低電耗模式限制。 無論是應用部分還是全部低電耗模式限制,系統都會喚醒設備以提供簡短的維護時間窗口,在此窗口期間,應用程序可以訪問網絡并執行任何被推遲的作業/同步。

后臺優化

小伙伴們都知道在Android中有一些隱式廣播,使用這些隱式廣播可以做一些特定的功能,如,當手機網絡變成WiFi時自動下載更新包等。 但,這些隱式廣播會在后臺頻繁啟動已注冊偵聽這些廣播的應用,從而帶來很大的電量消耗,為緩解這一問題來提升設備性能和用戶體驗,在Android 7.0中刪除了三項隱式廣播,以幫助優化內存使用和電量消耗。

Android 7.0 應用了以下優化措施:

  1. 在 Android 7.0上 應用不會收到 CONNECTIVITY_ACTION 廣播,即使你在manifest清單文件中設置了請求接受這些事件的通知。 但,在前臺運行的應用如果使用BroadcastReceiver 請求接收通知,則仍可以在主線程中偵聽 CONNECTIVITY_CHANGE。
  2. 在 Android 7.0上應用無法發送或接收 ACTION_NEW_PICTURE 或ACTION_NEW_VIDEO 類型的廣播。

應對策略:Android 框架提供多個解決方案來緩解對這些隱式廣播的需求。 例如,JobScheduler API 提供了一個穩健可靠的機制來安排滿足指定條件(例如連入無限流量網絡)時所執行的網絡操作。 您甚至可以使用 JobScheduler API 來適應內容提供程序變化。

另外,大家如果想了解更多關于后臺的優化可查閱后臺優化。

移動設備會經歷頻繁的連接變更,例如在 Wi-Fi 和移動數據之間切換時。 目前,可以通過在應用清單中注冊一個接收器來偵聽隱式 CONNECTIVITY_ACTION 廣播, 讓應用能夠監控這些變更。 由于很多應用會注冊接收此廣播,因此單次網絡切換即會導致所有應用被喚醒并同時處理此廣播。

責任編輯:龐桂玉 來源: 安卓巴士Android開發者門戶
相關推薦

2016-10-10 08:38:40

Windows 10備份格式化

2017-08-14 16:16:32

2020-11-09 14:15:23

代碼菜鳥老司機

2017-05-24 10:58:28

linux系統技巧

2018-08-02 16:46:58

2016-09-19 08:46:15

2018-10-09 09:42:27

MySQL優化單表

2020-03-09 10:21:12

Java集合類 Guava

2021-04-09 09:51:52

CyclicBarri Java循環柵欄

2018-09-28 15:06:41

MySQL優化指南數據庫

2016-11-28 16:09:37

2024-06-04 09:48:14

自動駕駛模型

2018-12-19 10:52:35

嵌入式CPU微處理器

2023-04-17 08:00:00

2019-08-20 09:30:18

Spring Clou組件Eureka

2018-12-04 09:07:36

運維問題排查

2017-10-17 11:09:06

2017-11-27 10:02:29

程序員技術提高

2016-05-12 15:34:04

云計算

2017-03-17 15:10:52

微信消息撤回功能
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日日夜夜精品视频 | 久久久久久免费精品一区二区三区 | 中文字幕亚洲精品 | 亚洲免费观看视频网站 | 毛片网站在线观看 | 久久成人精品 | 成人国产精品久久久 | h视频在线免费 | 久久久国产一区 | 亚洲一一在线 | 欧美中文字幕一区二区三区亚洲 | 国产高清精品在线 | 美女人人操 | 国产黄视频在线播放 | 中文字幕1区2区3区 日韩在线视频免费观看 | 男人的天堂视频网站 | 国产精品精品视频一区二区三区 | 韩日一区二区 | 国产成人综合在线 | 欧美一级片在线看 | 欧洲亚洲一区 | 99久久久久国产精品免费 | 成人自拍av| 亚洲国产精品suv | 日本一区二区高清视频 | 四虎永久免费影院 | 国产精品极品美女在线观看免费 | 久久久久久国产精品免费免费狐狸 | 日皮视频免费 | 精品九九九 | 91精品国产一区二区三区 | 国产婷婷 | 伊人二区| 国产精品观看 | 免费精品久久久久久中文字幕 | 福利在线看 | 国产精品一区2区 | 国产片一区二区三区 | 密色视频 | 精品一区二区久久 | 精品一区二区三区入口 |