某android平板項目開發筆記—計劃任務備份

前言:
很久,都沒更新過這個系列瞭…因為,除瞭圖表以外,然後就是數據庫瞭,調試瞭一個多星期的Ormlite數據庫,在最新版本中(orm 4.3.3)發現瞭幾個比較嚴重的bug(例如,查找id的時候無法使用Long類型),不過,還好,ormlite社區還算活躍,bug,已經在預覽中修復瞭.關於Ormlite數據庫的話,園子裡面已經有瞭寫得很不錯的教程瞭,我就不重復他們的勞動瞭.然後,數據庫搞定瞭,就是寫業務瞭,有這麼一個業務,就是,要求,在某個時間點,對插入的數據進行後臺更新,然後,就涉及到瞭使用計劃任務這麼一塊知識,覺得有必要做下筆記,這塊,以後應該也能用到
業務說明:
   在某時某刻進行數據庫的備份.
相關知識:
1,時間操作
(1) 熟悉使用Calendar
1,作為定時任務,我們需要一個具體的定時時間,以前,我是用Date 類取毫秒數,然後進行計數的操作
1.1例如
//以下為以前的某項目算相隔天數的演示代碼   
String startDate = mDateStart.getText().toString();
 
        String endDate = year + "-" + (month + 1) + "-" + day;
        Log.d("soap", startDate + "—" + endDate);
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        // long day=(startC.getTime()-endC.getTime())/(24*60*60*1000);
        try {
 
            Date start = df.parse(startDate);
            Date end = df.parse(endDate);
            Long d = (end.getTime() – start.getTime()) / (24 * 60 * 60 * 1000);
            Log.d("soap", "相隔天數" + d);
            if (d > 60) {
 
                return false;
            } else {
                return true;
            }
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
以前這樣寫,感覺挺傻的,希望大傢不要學習瞭,這次的業務需求,如果,是以前的話,我會一個創建具體時間字符串,然後用SimpleDateFormat,獲取毫秒數,這樣個人感覺,很不直觀,也麻煩,也不方便國際化,我們用Calendar做就非常簡單瞭.
1.2 定時23:00 執行備份操作
竟然是定時任務,我們就要熟悉一個android的一個用於做定時任務的類
AlarmManager
各位,先去看一下官方文檔,在接著看下去吧…
這個類是的初始化是必須要用Context.getSystemService(Context.ALARM_SERVICE).
以下為定時代碼塊
//初始化定時類
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
//設置定時時間,1分鐘後執行
Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, 1);
//設置時間到瞭執行的services
Intent intent = new Intent();
//創建一個servcies
intent.setClass(this, UpdateStatics.class);
PendingIntent pi = PendingIntent.getService(this, 0, intent, 0);
//設置定時
//需要android.permission.SET_TIME 權限
//第一個參數為定時類型(一共有四種,具體參見官方文檔),第二個參數為設置的定時時間為long類型,第三個為執行的目標
am.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);
以上代碼就會在,1分鐘後,系統執行UpdateStatics 類.
如果,我們要設置具體的時間,隻要具體設置Calendar的對象即可,例如23:00分執行
c.set(Calendar.HOUR_OF_DAY, 23);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
 
總結:
使用Calendar類操作時間,和進行時間計算,設置,是十分方便的事情,
2,備份操作
1, 建一個接口類用於,監聽操作.
 public interface CompletionListener {
    void onBackupComplete();
    void onRestoreComplete();
    void onError(int errorCode);
}
2,創建一個異步備份的類
public class BackupTask extends AsyncTask<String, Void, Integer> implements CompletionListener{
     
    //定義常量
    public static final int BACKUP_SUCCESS =1;
    public static final int RESTORE_SUCCESS = 2;
    public static final int BACKUP_ERROR = 3;
    public static final int RESTORE_NOFLEERROR = 4;
    public static final String COMMAND_BACKUP = "backupDatabase";
    public static final String COMMAND_RESTORE = "restroeDatabase";
    private Context mContext;
     
    public BackupTask(Context context){
        this.mContext = context;
    }
     
    @Override
    protected Integer doInBackground(String… params) {
        //1,獲得數據庫路徑
        File dbFile = mContext.getDatabasePath("xxx.db");
        //2,創建保存的數據庫的路徑
        File exportDir = new File(Environment.getExternalStorageDirectory(),"shopBackup");
        if(!exportDir.exists()){
            exportDir.mkdirs();
        }
        File backup = new File(exportDir, dbFile.getName());
        //3,檢查操作
        String command = params[0];
        if(command.equals(COMMAND_BACKUP)){
            //復制文件
            try {
                backup.createNewFile();
                fileCopy(dbFile, backup);
                return BACKUP_SUCCESS;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return BACKUP_ERROR;
            }
        }else{
            return BACKUP_ERROR;
        }
         
         
    }
 
 
    private void fileCopy(File source, File dest) throws IOException {
        FileChannel inChannel = new FileInputStream(source).getChannel();
        FileChannel outChannel = new FileOutputStream(dest).getChannel();
//      FileInputStream fis = new FileInputStream(dbFile);
//      FileOutputStream fos = new FileOutputStream(backup);
//      byte buffer[] = new byte[4 * 1024];
//      while(fis.read(buffer) != -1){
//          fos.write(buffer);
//      }
//      fos.flush();
//      
        long size =  inChannel.size();
        try {
            inChannel.transferTo(0, inChannel.size(), outChannel);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            if(inChannel != null){
                inChannel.close();
            }
            if(outChannel != null){
                outChannel.close();
            }
        }
    }
     
    @Override
    protected void onPostExecute(Integer result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        switch (result) {
        case BACKUP_SUCCESS:
            onBackupComplete();
            break;
 
        default:
            break;
        }
    }
 
    @Override
    public void onBackupComplete() {
         
        Log.d("backup", "ok");
 
    }
 
 
 
    @Override
    public void onRestoreComplete() {
        // TODO Auto-generated method stub
         
    }
 
 
    @Override
    public void onError(int errorCode) {
        // TODO Auto-generated method stub
         
    }
 
}
 
記得,設置好權限:
android.permission.WRITE_EXTERNAL_STORAGE
AsyncTask<Params,Progress,Result> 這個類的用法,官方文檔已經解釋的很詳細瞭,這裡也不做重復解釋.
關於:fileCopy(File source, File dest) 這個方法,我這裡改用瞭Nio 的方式進行操作.用註釋註釋的代碼是一般的方式,這個兩者有什麼區別呢?
文檔
java.nio.channels
類 FileChannel
transferTo
裡面有這麼一句話
與從此通道讀取並將內容寫入目標通道的簡單循環語句相比,此方法可能高效得多。很多操作系統可將字節直接從文件系統緩存傳輸到目標通道,而無需實際復制各字節。
看到這句話我就使用瞭這個方法瞭,然後,為瞭搞清楚實現的方式,我查看瞭一下transferTo 的源碼隻是一個抽象方法,然後,在的FileInputSteam裡面找的瞭channel 的實現方法,不過可惜的,具體的實現代碼,我的源碼包沒有.
然後我順便比較瞭java 和 android java 對於獲取,channel的區別
java jdk_1.6_u30 默認的fileChannel是用sun包進行實現,然後,關於實現的部分,應該要下個sun包的源碼瞭吧,因為,沒找的,就貼不出來瞭.
public FileChannel getChannel() {
synchronized (this) {
    if (channel == null) {
    channel = FileChannelImpl.open(fd, true, false, this);
 
            /*
             * Increment fd's use count. Invoking the channel's close()
             * method will result in decrementing the use count set for
             * the channel.
             */
            fd.incrementAndGetUseCount();
 
        }
    return channel;
}
android java getChannel的代碼部分
 public FileChannel getChannel() {
     // BEGIN android-changed
     synchronized(this) {
         if (channel == null) {
             channel = FileChannelFactory.getFileChannel(this, fd.descriptor,
                     IFileSystem.O_RDONLY);
         }
         return channel;
     }
     // END android-changed
 }
 
android java同樣,我的源碼包到實現filechannel 部分的代碼就沒瞭,對於獲取filechannel ,google 是重寫瞭sun那部分的代碼瞭.至於兩者的區別,我就不清楚瞭.有知道的朋友,望告知

 

作者:遊戲阿柴

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *