android檔案儲存體位置切換

來源:互聯網
上載者:User

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.