[mobilesafe] 03_拷贝数据库到系统目录

Android 4.0

拷贝数据库到系统目录 

加载外部文件的几种常见做法:
1. 放在assets目录下
InputStream is = am.open("address.db"); 不会对该文件生成id
 
2. 放在res目录下的raw目录下.(文件过大,不宜放在raw目录)
InputStream is =getResources().openRawResource(R.raw.address);
编译这个文件生成id
 
3. javase做法
InputStream is = getClassLoader().getResourceAsStream("address.db");
放在Assets目录下,然后拷贝到/data/data/包名/files/目录下
技术点:

1、放在SplashActivity,在其加载的时候,进行数据库的拷贝

2、拷贝的操作放在子线程中拷贝,像金山的放在主线程,就有一段时间是黑屏的阶段,用户体验就会很差
AssetManager assetManager = SplashActivity.this.getAssets();
InputStream inputStream = assetManager.open("phoneAddress.db");
File file = new File(SplashActivity.this.getFilesDir(), "phoneAddress.db");
FileOutputStream fos = new FileOutputStream(file);  
3、仅仅在程序第一次加载的时候进行拷贝,以后就不再拷贝了,要进行文件是否存在的判断
File file = new File(SplashActivity.this.getFilesDir(),"phoneAddress.db");
    if (file != null && file.exists()) {// 数据库已存在
         ToastUtils.showToastInThread(this"数据库已经存在了。");
         return;
    }  
4、在子线程中更新UI的方便方法
activity.runOnUiThread(new Runnable() {
     @Override
     public void run() {
         Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();
     }
});
方式一:放在assets资产目录,访问assets中文件的写法:file:///assets/address.db
String path = "file:///assets/phoneAddress.db";
SQLiteDatabase database = SQLiteDatabase.openDatabase(path, null,SQLiteDatabase.OPEN_READONLY);  
问题:利用SQLiteDatabase打不开该数据库
解决:而是将存放在assets中的数据库,拷贝到/data/data/包名/files/目录下
实现:

/**
 * 6、从assets中拷贝电话号码数据库文件到/data/data/包名/files/目录下
 */
public void copyAddressDb() {
    // 检查数据库是否已经拷贝过了.
    File file = new File(SplashActivity.this.getFilesDir(),"phoneAddress.db");
    if (file != null && file.exists()) {// 数据库已存在
        ToastUtils.showToastInThread(this"数据库已经存在了。");
        return;
    }
    // Splash界面加载时,拷贝数据文件到相应的目录下面,应该在子线程中拷贝
    new Thread() {
        @Override
        public void run() {
            try {
                
                // 问题:这个资产目录,是在apk中,SQLiteDatabase访问不到
                /*String path = "file:///assets/phoneAddress.db";
                SQLiteDatabase database = SQLiteDatabase.openDatabase(path, null,SQLiteDatabase.OPEN_READONLY);*/
            
                // 解决:拷贝释放到/data/data/包名/files/address.db
                AssetManager assetManager = SplashActivity.this.getAssets();
                InputStream inputStream = assetManager.open("phoneAddress.db");
                File file = new File(SplashActivity.this.getFilesDir(), "phoneAddress.db");
                FileOutputStream fos = new FileOutputStream(file);
                byte[] buf = new byte[1024];
                int len = 0;
                while ((len = inputStream.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                }
                fos.close();
                inputStream.close();
                ToastUtils.showToastInThread(SplashActivity.this,"拷贝数据库成功O(∩_∩)O!");
            } catch (IOException e) {
                e.printStackTrace();
                ToastUtils.showToastInThread(SplashActivity.this,"拷贝数据库失败(⊙o⊙)…");
            }
        }
    }.start();
}
子线程中更新UI的方便API:
package cn.zengfansheng.mobilesafe.utils;
 
import android.app.Activity;
import android.widget.Toast;
 
/**
* 2、在子线程更新UI的工具类
* @author hacket
*/

public class ToastUtils {
 
    /**
     * 1、在子线程中更新UI界面,使用Toast的方式更新UI
     * @param activity 要更新的activity
     * @param msg 显示的字符串
     */

    public static void showToastInThread(final Activity activity, final String msg) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();
            }
        });
    }
}