1. 背景
Environment.getExternalStorageDirectory()是Android 2.x時代的產物,那時Android主流設備只有很小的內置存儲器,然后都會外置一張sd卡,那時這個方法返回的就是外置sd卡的根路徑。
但隨着Android進入4.x時代,大部分Android設備都已經內置一個較大存儲卡,甚至不提供外置存儲卡插槽了,此時Environment.getExternalStorageDirectory()返回的路徑其實是由內置存儲卡虛擬出來的一個目錄,用戶在這一目錄下有全部權限。
按理說Android應該繼續提供其他的方法來返回其他的外置存儲卡的路徑,但這一次Android卻沒有,因為Android系統開發者們發現之前直接允許程序任意訪問sd卡的做法導致sd卡上垃圾文件的不可管理性,尤其在程序被卸載后,由於不知道那些文件是由這一程序創建的,所以無法關聯刪除,因此Android 4.0並不給程序開發者提供外置存儲卡的路徑,而是提供了諸如getExternalFilesDirs()和getExternalCacheDirs()這樣的方法,直接給開發者提供一個限制內的存儲文件的空間,這個空間是與程序關聯的,因此在卸載程序時這兩個目錄下的文件也會被關聯刪除。
2.問題一
在AndroidManifest里寫入了相機權限,讀寫權限,但華為手機調用Camera失敗,無法寫入手機內存等。
原因:Android系統從6.0版本開始增加了一種運行時權限,Camera正好屬於運行時權限,這種權限的授權不像6.0以前的Android系統可以安裝APP的時候就一次性授權。所以需要在代碼里手動申請權限。某些程序在華為G9上一測試就崩掉的原因:程序在運行中請求camera.open()時實際上程序並未獲得操作Camera的權限,所以camera.open()會一直打開失敗。對於運行時權限不清楚的可以百度搜索Android6.0運行時權限。
問題二
華為G9手機Environment.getExternalStorageDirectory()得到的是什么?
答:從手機上自帶的文件管理器來看,上面有兩個存儲位置,一個是內部存儲,是華為G9內置的SD卡;一個是SanDisk SD 卡,這個是自己買的然后安裝上去的。那么,用Environment.getExternalStorageDirectory()得到的是哪個內存里的路徑呢?該方法得到的是/storage/emulated/0是內部存儲,也就是華為G9內置的SD卡,當然這是我經過測試后得到的,如下圖所示。
問題三
使用ContextCompat和ActivityCompat報錯
原因:因為這兩個是sdk19以上版本v4包新加的,所以要導入V4包,最好是導入最新的版本,步驟file->project structure->dependencies->右邊“+”號然后添加v4包即可。
代碼部分就只寫最主要的吧,最底下有源碼地址
MainActivity.java
public class MainActivity extends Activity { public static final int TAKE_PHOTO = 1; public static final int CROP_PHOTO = 2; private static final String IMAGE_FILE_NAME = "head_image.jpg";// 頭像文件 private static final int CODE_CAMERA_REQUEST = 0xa1;//拍照請求碼 private static String[] PERMISSIONS_STORAGE = { // Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,//寫權限 Manifest.permission.CAMERA//照相權限 }; private Button btn; private ImageView img; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = (Button) findViewById(R.id.take_photo); img = (ImageView) findViewById(R.id.picture); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //用intent調用相機 Intent intentFromCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //判斷sd卡是否可用 if (SDCardUtils.isSDCardEnable()){ //ContentValues與HashMap類似,但ContentValues只能保存數據類型,不能保存對象類型 ContentValues values = new ContentValues(); //key-value形式 values.put(MediaStore.Images.Media.TITLE,IMAGE_FILE_NAME); //EXTRA_OUTPUT用於存儲所請求的圖像或視頻的解析Uri imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),IMAGE_FILE_NAME)); intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT,imageUri); } // startActivityForResult(intentFromCapture,CODE_CAMERA_REQUEST); } }); //用於判斷SDK版本是否大於23 if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){ //檢查權限 int i = ContextCompat.checkSelfPermission(this,PERMISSIONS_STORAGE[0]); //如果權限申請失敗,則重新申請權限 if(i!= PackageManager.PERMISSION_GRANTED){ //重新申請權限函數 startRequestPermission(); Log.e("這里","權限請求成功"); } } } /** * 重新申請權限函數 */ private void startRequestPermission(){ //321為請求碼 ActivityCompat.requestPermissions(this,PERMISSIONS_STORAGE,321); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode==CODE_CAMERA_REQUEST&&resultCode==RESULT_OK){ try { Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); img.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } } } }
源碼地址:http://download.csdn.net/detail/u013293125/9737050