android開發筆記之內建圖片到相簿

hfreeman2008發表於2016-07-29

這裡寫圖片描述

開發需求

客戶提了一個需求,內建22張客戶提供的桌布到launcher的桌布中,並且要在相簿中顯示這22張桌布

初步實現

初步看,覺得這應該是一個非常簡單的需求,只要在luncher中對應以前的桌布中新增22張客戶的桌布就可以了

理想非常豐滿,現實是非常骨感!

我大公司研發部門實行開發平臺化大戰略,各個開發實行模組化戰術,各個模組,各個應用實行釋放apk不提供原始碼的策略

好政策啊!
領導英明啊!

我按照launcher apk提供配製桌布的方法,將客戶提供的22張桌布成功內建到launcher中,在launcher中可以看到桌布中有內建的客戶22張桌布,但是相簿中不能顯示。

我就去向launcher模組的負責人諮詢相關的解決方法。launcher告知我這要去找相簿模組。

好吧,去找相簿的負責人,相簿負責檢視了我的圖片內建的位置:

system/etc/iamgeswallpapers/

告知我說圖片內建到system中,圖片不能識別。要我去找以前做專案的人

我提出疑問:相簿應該提供一個內建圖片到相簿的方法

相簿的負責人直接回復:對於這種需求,我們不負責,這和相簿沒有關係

好吧,是我錯了,哥,對不起,麻煩你們了。

我再找以前做專案的人,問了一下此需求。他們告知我解決方案:
(1)先將圖片複製到system目錄下
(2)再內建一個apk,就可以了

(注,為什麼這位告訴我這麼詳細,因為是熟人!)

我按照上面的方法來實現:
第一:內建圖片到目錄(system/media/bootupResource)下:
先將圖片放到picture目錄下,然後在mk檔案中配置,複製圖片到(system/media/bootupResource):

配製方法:

PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/picture/hd_0.jpg:system/media/bootupResource/hd_0.jpg \
    $(LOCAL_PATH)/picture/hd_1.jpg:system/media/bootupResource/hd_1.jpg \
    $(LOCAL_PATH)/picture/hd_2.jpg:system/media/bootupResource/hd_2.jpg \
    $(LOCAL_PATH)/picture/hd_3.jpg:system/media/bootupResource/hd_3.jpg \
    $(LOCAL_PATH)/picture/hd_4.jpg:system/media/bootupResource/hd_4.jpg \
    $(LOCAL_PATH)/picture/hd_5.jpg:system/media/bootupResource/hd_5.jpg \
    $(LOCAL_PATH)/picture/hd_6.jpg:system/media/bootupResource/hd_6.jpg \
    $(LOCAL_PATH)/picture/hd_7.jpg:system/media/bootupResource/hd_7.jpg \
.................

第二:內建app應用BootupImage

此應用BootupImage主要的作用是二個,一是將(system/media/bootupResource)目錄下的圖片複製到我們定義的手機記憶體中,二是通知手機立刻掃描到新複製的圖片,以在相簿中顯示。

坑人的是,我內建此apk,相簿中就是沒有顯示圖片,我debug了半天,才發現原來是高通和MTK的讀取內建路徑的方法不同,我再移植對應的高通專案的此應用,功能是實現了。

重新實現

看了一下BootupImage應用,程式碼面向具體實現,程式碼的可讀性一般,沒有什麼規範性,沒有什麼擴充套件性和可移植性。

我決定重寫:

Util.java

關鍵方法說明:

boolean  copyFile(String src,String des)
---複製檔案功能:把路徑為src的檔案複製到路徑為des的位置
成功返回true,失敗為false
     public static boolean  copyFile(String src,String des){     
         boolean result = true;

         FileInputStream fis = null;
         FileOutputStream fos = null;
         try {
             //定義輸入和輸出的檔案
             File fin = new File(src);
             File fout = new File(des);
             //定義輸入流和輸出流的物件
             fis = new FileInputStream(fin);
             fos = new FileOutputStream(fout);
             //3.執行復制操作
             byte[] b = new byte[1024];
             int len;
             while ((len = fis.read(b)) != -1) {
                 fos.write(b, 0, len);
             }
         }catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
             result = false;
         }finally{
             //4.關閉對應的流,先關輸出流,後關輸入流
             if (fos != null) {
                 try {
                     fos.close();
                 } catch (IOException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                     result = false;
                 }
             }
             if(fis != null){
                 try {
                     fis.close();
                 } catch (IOException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                     result = false;
                 }
             }       
         }
         return result;
    }
public static boolean copyDirectory(String sourceDir, String destDir)
---複製資料夾功能:把路徑為src的資料夾複製到路徑為des的位置
成功返回true,失敗為false
    public static boolean copyDirectory(String sourceDir, String destDir){  

        boolean result = true;

        File sourceFile = new File(sourceDir);
        File destFile = new File(destDir);

        if(!sourceFile.exists()){
            android.util.Log.i(TAG, "sourceFile do not exist");
            return false;
        }
        if(!destFile.exists()){
            if(!destFile.mkdirs()){
                android.util.Log.i(TAG, "destFile mkdirs fail");
                return false;
            }
        }


        if(!destFile.canRead()){
            android.util.Log.i(TAG, "destFile can not Read");
            return false;
        }

        File[] file = sourceFile.listFiles();  
        for(int i=0;i<file.length;i++){

            if(file[i].isFile()){
                File sourceFileItem = file[i];
                File destFileItem = new File(destFile.getAbsolutePath()+File.separator+file[i].getName());          
                copyFile(sourceFileItem.getAbsolutePath(),destFileItem.getAbsolutePath());
            }

            if(file[i].isDirectory()){
                String source=sourceDir + File.separator + file[i].getName();   
                String dest=destDir + File.separator + file[i].getName();  
                result = copyDirectory(source, dest);
            }
        }   
        return result;
    }  
public static final void scanFile(final Context context,final String path)
---掃描檔案,讓手機可以實時識別變動的檔案
public static final void scanFile(final Context context,final String path){ 
        android.util.Log.i(TAG, "scanFile--:"+path);

        Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        scanIntent.setData(Uri.fromFile(new File(path)));
        context.sendBroadcast(scanIntent);
    }
public static final void scanDir(final Context context,final String path)
---掃描資料夾,讓手機可以實時識別變動的資料夾
    public static final void scanDir(final Context context,final String path){
        android.util.Log.i(TAG, "scanDir");
        android.util.Log.i(TAG, "scanDir---path:"+path);

        File file = new File(path);
        File[] fileItemFiles = file.listFiles();

        for (int i = 0; i < fileItemFiles.length; i++) {

            String pathItem = fileItemFiles[i].getParent()+File.separator+fileItemFiles[i].getName();

            if(fileItemFiles[i].isFile()){
                scanFile(context,pathItem);
            }

            if(fileItemFiles[i].isDirectory()){
                scanDir(context,pathItem);
            }
        }   
    }

定義幾個關鍵的變數:

public static final String TAG = "Util";
//public static final String sourceDir = "/system/media/bootupResource";
public static final String sourceDir = "/system/media";
public static final String destDir_Without_SDCARD = Environment.getExternalStorageDirectory().getAbsolutePath() +File.separator+ "Pictures_01";
public static final String destDir_With_SDCARD = "/storage/sdcard1/Pictures";

呼叫方法

啟動執行緒,以Util.copyDirectory實現複製資料夾,並且以Util.scanDir掃描最新複製的資料夾,以方便手機識別變動的檔案,以讓圖片可以在相簿中顯示:

runnable = new Runnable() {         
            @Override
            public void run() {
                // TODO Auto-generated method stub
                //複製資料夾到對應的位置
                boolean result = Util.copyDirectory(Util.sourceDir,Util.destDir_Without_SDCARD);
                android.util.Log.i(TAG, "onClickDo:"+result);

                android.util.Log.i(TAG, "onClickDo:---scanDir");
                //掃描最新複製的資料夾,以識別變動的檔案
                Util.scanDir(getApplicationContext(), Util.destDir_Without_SDCARD);
            }
};
runnable.run(); 

Android.mk

配置app的android.mk檔案

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional 
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := TinnoCopyResourceToStorage
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)

AndroidManifest.xml

定義許可權:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />

以上其實已經實現了內建圖片到相簿中,並且實時讓手機識別,以在相簿中顯示。

擴充套件

那麼,如果客戶提出內建其它資源到特定的目錄路徑(比如鈴聲,音樂,視訊,apk,zip等等),並且讓手機實現識別到複製過來的資源,以讓手機實時識別和顯示。

啊噢,哈哈。

告訴你一個好訊息吧,以上方法,你只需要修改src和des的路徑,就可以實現所有此類的需求。

並且已驗證!!

參考:

1.java核心技術之IO流(二)FileInputStream和FileOutputStream
http://blog.csdn.net/hfreeman2008/article/details/49159547

相關文章