某android平板項目開發筆記---計劃任務備份
前言:
很久,都沒更新過這個系列了…因爲,除了圖表以外,然後就是數據庫了,調試了一個多星期的Ormlite數據庫,在最新版本中(orm 4.3.3)發現了幾個比較嚴重的bug(例如,查找id的時候無法使用Long類型),不過,還好,ormlite社區還算活躍,bug,已經在預覽中修復了.關於Ormlite數據庫的話,園子裏面已經有了寫得很不錯的教程了,我就不重複他們的勞動了.然後,數據庫搞定了,就是寫業務了,有這麼一個業務,就是,要求,在某個時間點,對插入的數據進行後臺更新,然後,就涉及到了使用計劃任務這麼一塊知識,覺得有必要做下筆記,這塊,以後應該也能用到
業務說明:
在某時某刻進行數據庫的備份.
相關知識:
1,時間操作
(1) 熟悉使用Calendar
1,作爲定時任務,我們需要一個具體的定時時間,以前,我是用Date 類取毫秒數,然後進行計數的操作
1.1例如
1234567891011121314151617181920212223//以下爲以前的某項目算相隔天數的演示代碼
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).
以下爲定時代碼塊
1234567891011121314//初始化定時類
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分執行
123c.set(Calendar.HOUR_OF_DAY, 23);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
總結:
使用Calendar類操作時間,和進行時間計算,設置,是十分方便的事情,
2,備份操作
1, 建一個接口類用於,監聽操作.
12345public interface CompletionListener {
void onBackupComplete();
void onRestoreComplete();
void onError(int errorCode);
}
2,創建一個異步備份的類
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110public 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
類 FileChanneltransferTo
裏面有這麼一句話
與從此通道讀取並將內容寫入目標通道的簡單循環語句相比,此方法可能高效得多。很多操作系統可將字節直接從文件系統緩存傳輸到目標通道,而無需實際複製各字節。
看到這句話我就使用了這個方法了,然後,爲了搞清楚實現的方式,我查看了一下transferTo 的源碼只是一個抽象方法,然後,在的FileInputSteam裏面找的了channel 的實現方法,不過可惜的,具體的實現代碼,我的源碼包沒有.
然後我順便比較了java 和 android java 對於獲取,channel的區別
java jdk_1.6_u30 默認的fileChannel是用sun包進行實現,然後,關於實現的部分,應該要下個sun包的源碼了吧,因爲,沒找的,就貼不出來了.
123456789101112131415public 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的代碼部分
1234567891011public 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那部分的代碼了.至於兩者的區別,我就不清楚了.有知道的朋友,望告知