android 数据备份

某android平板项目开发笔记---计划任务备份

前言:

很久,都没更新过这个系列了…因为,除了图表以外,然后就是数据库了,调试了一个多星期的Ormlite数据库,在最新版本中(orm 4.3.3)发现了几个比较严重的bug(例如,查找id的时候无法使用Long类型),不过,还好,ormlite社区还算活跃,bug,已经在预览中修复了.关于Ormlite数据库的话,园子里面已经有了写得很不错的教程了,我就不重复他们的劳动了.然后,数据库搞定了,就是写业务了,有这么一个业务,就是,要求,在某个时间点,对插入的数据进行后台更新,然后,就涉及到了使用计划任务这么一块知识,觉得有必要做下笔记,这块,以后应该也能用到

业务说明:

   在某时某刻进行数据库的备份.

相关知识:

1,时间操作

(1) 熟悉使用Calendar

1,作为定时任务,我们需要一个具体的定时时间,以前,我是用Date 类取毫秒数,然后进行计数的操作

1.1例如

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//以下为以前的某项目算相隔天数的演示代码  
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).

以下为定时代码块

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//初始化定时类
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分执行

?
1
2
3
c.set(Calendar.HOUR_OF_DAY, 23);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);

 

总结:

使用Calendar类操作时间,和进行时间计算,设置,是十分方便的事情,

2,备份操作

1, 建一个接口类用于,监听操作.

?
1
2
3
4
5
public interface CompletionListener {
     void onBackupComplete();
     void onRestoreComplete();
     void onError(int errorCode);
}

2,创建一个异步备份的类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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包的源码了吧,因为,没找的,就贴不出来了.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的代码部分

?
1
2
3
4
5
6
7
8
9
10
11
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那部分的代码了.至于两者的区别,我就不清楚了.有知道的朋友,望告知

你可能感兴趣的:(android,数据库,String,calendar,command,Integer)