Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android文件存儲位置切換

android文件存儲位置切換

編輯:關於Android編程

 最近有個需求,助手的google衛星地圖和OpenCycleMap下載的離線地圖數據,要能夠在內置存儲和外置存儲空間之間切換,因為離線瓦片數據非常大,很多戶外用戶希望將這些文件存儲在外置TF卡上,不占用內置存儲空間,所以把最近研究的整理了下,分享給大家。

  需要考慮和遇到的問題(主要是不同手機、不同系統的兼容性):

  1.這樣獲取手機所有掛載的存儲器?

   Android是沒有提供顯式的接口的,首先肯定是要閱讀系統設置應用“存儲”部分的源碼,看存儲那裡是通過什麼方式獲取的。最後找到StorageManager和StorageVolume這2個重要的類,然後通過反射獲取StorageVolume[]列表。

  2.用什麼標示一個存儲器的唯一性?

   存儲路徑?不行(有些手機不插TF卡,內置存儲路徑是/storage/sdcard0,插上TF卡後,內置存儲路徑變成/storage/sdcard1,TF卡變成/storage/sdcard0)。

   存儲卡名稱?不行(可能會切換系統語言,導致名稱匹配失敗,名稱的resId也不行,較低的系統版本StorageVolume沒有mDescriptionId這一屬性)。

   經過測試,發現使用mStorageId可以標示存儲器的唯一性,存儲器數量改變,每個存儲器的id不會改變。

  3.如何獲得存儲器的名稱?

   經測試,不同的手機主要有3種獲取存儲器名換的方法:getDescription()、getDescription(Context context)、先獲得getDescriptionId()再通過resId獲取名稱。

  4.任務文件下載一半時,切換文件保存存儲器,怎麼處理?

   有2種方案:

   4.1 切換時,如果新的存儲空間足夠所有文件轉移,先停止所有下載任務,將所有下載完和下載中的文件拷貝到新的存儲空間,然後再更新下載數據庫下載任務的存儲路徑,再恢復下載任務;

   4.2 切換時,先拷貝所有下載完成的文件到新的存儲空間,下載任務繼續下載,下載完成再移動到新的存儲空間。

  5.在4.4系統上,第三方應用無法讀取外置存儲卡的問題。(參考“External Storage”)

   google為了在程序卸載時,能夠完全徹底的將程序所有數據清理干淨,應用將不能向2級存儲區域寫入文件。

   “The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions. Restricting writes in this way ensures the system can clean up files when applications are uninstalled.”

   要能夠在4.4系統上TF卡寫入文件,必須先root,具體方法可以google。

   所以4.4系統上,切換會導致文件轉移和下載失敗,用戶如果要切換到TF卡,至少需要提醒用戶,並最好給出4.4上root解決方法。

  以下是獲取存儲器的部分代碼:

public static class MyStorageVolume{
        public int mStorageId;
        public String mPath;
        public String mDescription;
        public boolean mPrimary;
        public boolean mRemovable;
        public boolean mEmulated;
        public int mMtpReserveSpace;
        public boolean mAllowMassStorage;
        public long mMaxFileSize;  //最大文件大小。(0表示無限制)
        public String mState;      //返回null

        public MyStorageVolume(Context context, Object reflectItem){
            try {
                Method fmStorageId = reflectItem.getClass().getDeclaredMethod("getStorageId");
                fmStorageId.setAccessible(true);
                mStorageId = (Integer) fmStorageId.invoke(reflectItem);
            } catch (Exception e) {
            }

            try {
                Method fmPath = reflectItem.getClass().getDeclaredMethod("getPath");
                fmPath.setAccessible(true);
                mPath = (String) fmPath.invoke(reflectItem);
            } catch (Exception e) {
            }

            try {
                Method fmDescriptionId = reflectItem.getClass().getDeclaredMethod("getDescription");
                fmDescriptionId.setAccessible(true);
                mDescription = (String) fmDescriptionId.invoke(reflectItem);
            } catch (Exception e) {
            }
            if(mDescription == null || TextUtils.isEmpty(mDescription)){
                try {
                    Method fmDescriptionId = reflectItem.getClass().getDeclaredMethod("getDescription");
                    fmDescriptionId.setAccessible(true);
                    mDescription = (String) fmDescriptionId.invoke(reflectItem, context);
                } catch (Exception e) {
                }
            }
            if(mDescription == null || TextUtils.isEmpty(mDescription)){
                try {
                    Method fmDescriptionId = reflectItem.getClass().getDeclaredMethod("getDescriptionId");
                    fmDescriptionId.setAccessible(true);
                    int mDescriptionId = (Integer) fmDescriptionId.invoke(reflectItem);
                    if(mDescriptionId != 0){
                        mDescription = context.getResources().getString(mDescriptionId);
                    }
                } catch (Exception e) {
                }
            }

            try {
                Method fmPrimary = reflectItem.getClass().getDeclaredMethod("isPrimary");
                fmPrimary.setAccessible(true);
                mPrimary = (Boolean) fmPrimary.invoke(reflectItem);
            } catch (Exception e) {
            }

            try {
                Method fisRemovable = reflectItem.getClass().getDeclaredMethod("isRemovable");
                fisRemovable.setAccessible(true);
                mRemovable = (Boolean) fisRemovable.invoke(reflectItem);
            } catch (Exception e) {
            }

            try {
                Method fisEmulated = reflectItem.getClass().getDeclaredMethod("isEmulated");
                fisEmulated.setAccessible(true);
                mEmulated = (Boolean) fisEmulated.invoke(reflectItem);
            } catch (Exception e) {
            }

            try {
                Method fmMtpReserveSpace = reflectItem.getClass().getDeclaredMethod("getMtpReserveSpace");
                fmMtpReserveSpace.setAccessible(true);
                mMtpReserveSpace = (Integer) fmMtpReserveSpace.invoke(reflectItem);
            } catch (Exception e) {
            }

            try {
                Method fAllowMassStorage = reflectItem.getClass().getDeclaredMethod("allowMassStorage");
                fAllowMassStorage.setAccessible(true);
                mAllowMassStorage = (Boolean) fAllowMassStorage.invoke(reflectItem);
            } catch (Exception e) {
            }

            try {
                Method fMaxFileSize = reflectItem.getClass().getDeclaredMethod("getMaxFileSize");
                fMaxFileSize.setAccessible(true);
                mMaxFileSize = (Long) fMaxFileSize.invoke(reflectItem);
            } catch (Exception e) {
            }

            try {
                Method fState = reflectItem.getClass().getDeclaredMethod("getState");
                fState.setAccessible(true);
                mState = (String) fState.invoke(reflectItem);
            } catch (Exception e) {
            }
        }

        /**
         * 獲取Volume掛載狀態, 例如Environment.MEDIA_MOUNTED
         */
        public String getVolumeState(Context context){
            return StorageVolumeUtil.getVolumeState(context, mPath);
        }

        public boolean isMounted(Context context){
            return getVolumeState(context).equals(Environment.MEDIA_MOUNTED);
        }

        public String getDescription(){
            return mDescription;
        }

        /**
         * 獲取存儲設備的唯一標識
         */
        public String getUniqueFlag(){
            return "" + mStorageId;
        }

        /*public boolean isUsbStorage(){
            return mDescriptionId == android.R.string.storage_usb;
        }*/

        /**
         * 獲取目錄可用空間大小
         */
        public long getAvailableSize(){
            return StorageVolumeUtil.getAvailableSize(mPath);
        }

        /**
         * 獲取目錄總存儲空間
         */
        public long getTotalSize(){
            return StorageVolumeUtil.getTotalSize(mPath);
        }

        @Override
        public String toString() {
            return "MyStorageVolume{" +
                    "\nmStorageId=" + mStorageId +
                    "\n, mPath='" + mPath + '\'' +
                    "\n, mDescription=" + mDescription +
                    "\n, mPrimary=" + mPrimary +
                    "\n, mRemovable=" + mRemovable +
                    "\n, mEmulated=" + mEmulated +
                    "\n, mMtpReserveSpace=" + mMtpReserveSpace +
                    "\n, mAllowMassStorage=" + mAllowMassStorage +
                    "\n, mMaxFileSize=" + mMaxFileSize +
                    "\n, mState='" + mState + '\'' +
                    '}' + "\n";
        }
    }

存儲信息MyStorageVolume

public static List getVolumeList(Context context){
        List svList = new ArrayList(3);
        StorageManager mStorageManager = (StorageManager)context
                .getSystemService(Activity.STORAGE_SERVICE);
        try {
            Method mMethodGetPaths = mStorageManager.getClass().getMethod("getVolumeList");
            Object[] list = (Object[]) mMethodGetPaths.invoke(mStorageManager);
            for(Object item : list){
                svList.add(new MyStorageVolume(context, item));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return svList;
    }

獲取所有存儲器

github上的測試例子:

https://github.com/John-Chen/BlogSamples/tree/master/StorageTest

  

如果還有什麼地方沒有考慮到的,歡迎討論。  

其他精彩文章文章

android學習筆記(41)android選項菜單和子菜單(SubMenu )

android學習筆記(40)Notification的功能與用法

android學習筆記(42)android使用監聽器來監聽菜單事件

android學習筆記(43)android創建單選菜單和復選菜單

jQuery教程(12)-ajax操作之基於請求加載數據

jQuery教程(13)-ajax操作之追加 HTML

更多關於android開發文章


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved