[安卓] 数据库的Android仲 – P5备份和导入
今天忙碌的几天对杂乱无章所以新来的一系列写在Android的数据库. 部分 5, 也是最后一部分,我会引导你如何备份和导入数据库的android.
步 1: 允许读取和写入数据,在AndroidManifest.xml中的存储卡
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cachhoc.net.tut.demodatabase" >
<!-- set can read and write on sd card-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".NoteActivity"
android:label="@string/title_activity_note" >
</activity>
</application>
</manifest>
帽山一文件menu_main.xml – 文件菜单CUA MainActivity
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<item
android:id="@+id/menu_more"
android:icon="@drawable/ic_more"
android:title="Menu"
app:showAsAction="always">
<menu>
<item
android:id="@+id/menu_backup"
android:orderInCategory="100"
android:title="@string/backup_data"
app:showAsAction="never" />
<item
android:id="@+id/menu_import"
android:orderInCategory="100"
android:title="@string/import_data"
app:showAsAction="never" />
</menu>
</item>
</menu>
你自己也如上所述 1 项目 – 此产品是一个按钮 3 点 (溢出). 当你点击按钮 3 点会出现 2 菜单备份VA进口 (看视频) 是 2 它里面的物品.
MainActivity.java文件更新赶上事件菜单:
package cachhoc.net.tut.demodatabase;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, BackupData.OnBackupListener {
private ItemNoteAdapter adapter;
private List<Note> listNote = new ArrayList<>();
private Context context;
private DatabaseHelper db;
private BackupData backupData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
db = new DatabaseHelper(context);
backupData = new BackupData(context);
backupData.setOnBackupListener(this);
connectView();
}
/**
* connect java with xml view
*/
private void connectView() {
// find Float Action Button
findViewById(R.id.fab).setOnClickListener(this);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv_note);
// If the size of views will not change as the data changes.
recyclerView.setHasFixedSize(true);
// Setting the LayoutManager.
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
// Setting the adapter.
adapter = new ItemNoteAdapter(context, listNote);
recyclerView.setAdapter(adapter);
}
/**
* update list note when resume (open app or finish NoteActivity)
*/
public void onResume() {
super.onResume();
updateListNote();
}
/**
* select all note from database and set to ls
* use for loop to add into listNote.
* We must add all item in ls into listNote then adapter can update
* we add reverse ls to show new note at top of list
*/
private void updateListNote() {
// clear old list
listNote.clear();
// add all notes from database, reverse list
ArrayList<Note> ls = db.getListNote("SELECT * FROM " + DatabaseHelper.TABLE_NOTE);
// reverse list
for (int i = ls.size() - 1; i >= 0; i--) {
listNote.add(ls.get(i));
}
adapter.notifyDataSetChanged();
}
/**
* display note have id
*/
public static void showNote(Context context, long id) {
Intent intent = new Intent(context, NoteActivity.class);
// send id to NoteActivity
intent.putExtra(NoteActivity.ID, id);
context.startActivity(intent);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.fab:
showNote(context, NoteActivity.NEW_NOTE);
break;
default:
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_backup:
backupData.exportToSD();
break;
case R.id.menu_import:
backupData.importFromSD();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onFinishExport(String error) {
String notify = error;
if (error == null) {
notify = "Export success";
}
Toast.makeText(context, notify, Toast.LENGTH_SHORT).show();
}
@Override
public void onFinishImport(String error) {
String notify = error;
if (error == null) {
notify = "Import success";
updateListNote();
}
Toast.makeText(context, notify, Toast.LENGTH_SHORT).show();
}
}
你注意到我有 实现接口BackupData.OnBackupListener 在课堂上BackupData (在以后会写) 和覆盖 2 方法 onFinishExport 和 onFinishImport 其, 2 这种方法允许我们处理通知或执行备份和导入完成后,.
当您启动事件中调用菜单 2 方法 backupData.exportToSD 和 backupData.importFromSD 执行.
步 3: 执行写类BackupData
在前面描述她的脚步. 当用户选择backupdata那么我们将数据备份到位于某个文件夹的存储卡, 在此独自它保存在文件夹 MyNote. 该程序会自动创建该文件夹,如果它不存在. 备份文件的名称将是数据库的名称以及日期时间, 小时分秒作为第一视频后.
当用户选择导入数据, 如果你想导入之前备份您的现有数据,我们会问. 如果是这样,备份,然后列出导入先前的备份文件. 否则要导入的文件只只列表.
为了避免数据丢失,并避免在新的结构有些旧数据现有数据的情况下,错误, 我们删除现有的所有数据记录,然后将备份文件复制到一个临时数据库 (临时数据库) 然后复制表中的当前数据的整个记录和临时DATABSE. 例如你当前的数据表注, 此表列LAST_MODIFIED,在老DATABSE没有, 同时,如果直接复制导致了数据库,并没有last_modified列出错的应用.
这里是代码是比较明确的解释. 你可以阅读.
package cachhoc.net.tut.demodatabase;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Environment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
public class BackupData {
// url for database
private final String dataPath = "//data//cachhoc.net.tut.demodatabase//databases//";
// name of main data
private final String dataName = DatabaseHelper.DATABASE_NAME;
// data main
private final String data = dataPath + dataName;
// name of temp data
private final String dataTempName = DatabaseHelper.DATABASE_NAME + "_temp";
// temp data for copy data from sd then copy data temp into main data
private final String dataTemp = dataPath + dataTempName;
// folder on sd to backup data
private final String folderSD = Environment.getExternalStorageDirectory() + "/MyNote";
private Context context;
public BackupData(Context context) {
this.context = context;
}
// create folder if it not exist
private void createFolder() {
File sd = new File(folderSD);
if (!sd.exists()) {
sd.mkdir();
System.out.println("create folder");
} else {
System.out.println("exits");
}
}
/**
* Copy database to sd card
* name of file = database name + time when copy
* When finish, we call onFinishExport method to send notify for activity
*/
public void exportToSD() {
String error = null;
try {
createFolder();
File sd = new File(folderSD);
if (sd.canWrite()) {
SimpleDateFormat formatTime = new SimpleDateFormat("yyyy_MM_dd__HH_mm_ss");
String backupDBPath = dataName + "_" + formatTime.format(new Date());
File currentDB = new File(Environment.getDataDirectory(), data);
File backupDB = new File(sd, backupDBPath);
if (currentDB.exists()) {
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
} else {
System.out.println("db not exist");
}
}
} catch (Exception e) {
e.printStackTrace();
error = "Error backup";
}
onBackupListener.onFinishExport(error);
}
/**
* import data from file backup on sd card
* we must create a temp database for copy file on sd card to it.
* Then we copy all row of temp database into main database.
* It will keep struct of curren database not change when struct backup database is old
*
* @param fileNameOnSD name of file database backup on sd card
*/
public void importData(String fileNameOnSD) {
File sd = new File(folderSD);
// create temp database
SQLiteDatabase dbBackup = context.openOrCreateDatabase(dataTempName,
SQLiteDatabase.CREATE_IF_NECESSARY, null);
String error = null;
if (sd.canWrite()) {
File currentDB = new File(Environment.getDataDirectory(), dataTemp);
File backupDB = new File(sd, fileNameOnSD);
if (currentDB.exists()) {
FileChannel src;
try {
src = new FileInputStream(backupDB).getChannel();
FileChannel dst = new FileOutputStream(currentDB)
.getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
error = "Error load file";
} catch (IOException e) {
error = "Error import";
}
}
}
/**
*when copy old database into temp database success
* we copy all row of table into main database
*/
if (error == null) {
new CopyDataAsyncTask(dbBackup).execute();
} else {
onBackupListener.onFinishImport(error);
}
}
/**
* show dialog for select backup database before import database
* if user select yes, we will export curren database
* then show dialog to select old database to import
* else we onoly show dialog to select old database to import
*/
public void importFromSD() {
final AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppCompatAlertDialogStyle);
builder.setTitle(R.string.backup_data).setIcon(R.mipmap.ic_launcher)
.setMessage(R.string.backup_before_import);
builder.setPositiveButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
showDialogListFile(folderSD);
}
});
builder.setNegativeButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
showDialogListFile(folderSD);
exportToSD();
}
});
builder.show();
}
/**
* show dialog list all backup file on sd card
* @param forderPath folder conatain backup file
*/
private void showDialogListFile(String forderPath) {
createFolder();
File forder = new File(forderPath);
File[] listFile = forder.listFiles();
final String[] listFileName = new String[listFile.length];
for (int i = 0, j = listFile.length - 1; i < listFile.length; i++, j--) {
listFileName[j] = listFile[i].getName();
}
if (listFileName.length > 0) {
// get layout for list
LayoutInflater inflater = ((FragmentActivity) context).getLayoutInflater();
View convertView = (View) inflater.inflate(R.layout.list_backup_file, null);
final AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppCompatAlertDialogStyle);
// set view for dialog
builder.setView(convertView);
builder.setTitle(R.string.select_file).setIcon(R.mipmap.ic_launcher);
final AlertDialog alert = builder.create();
ListView lv = (ListView) convertView.findViewById(R.id.lv_backup);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(context,
android.R.layout.simple_list_item_1, listFileName);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
alert.dismiss();
importData(listFileName[position]);
}
});
alert.show();
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppCompatAlertDialogStyle);
builder.setTitle(R.string.delete).setIcon(R.mipmap.ic_launcher)
.setMessage(R.string.backup_empty);
builder.show();
}
}
/**
* AsyncTask for copy data
*/
class CopyDataAsyncTask extends AsyncTask<Void, Void, Void> {
ProgressDialog progress = new ProgressDialog(context);
SQLiteDatabase db;
public CopyDataAsyncTask(SQLiteDatabase dbBackup) {
this.db = dbBackup;
}
/**
* will call first
*/
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progress.setMessage("Importing...");
progress.show();
}
@Override
protected Void doInBackground(Void... params) {
copyData(db);
return null;
}
/**
* end process
*/
@Override
protected void onPostExecute(Void error) {
// TODO Auto-generated method stub
super.onPostExecute(error);
if (progress.isShowing()) {
progress.dismiss();
}
onBackupListener.onFinishImport(null);
}
}
/**
* copy all row of temp database into main database
* @param dbBackup
*/
private void copyData(SQLiteDatabase dbBackup) {
DatabaseHelper db = new DatabaseHelper(context);
db.deleteNote(null);
/** copy all row of subject table */
Cursor cursor = dbBackup.query(true, DatabaseHelper.TABLE_NOTE, null, null, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
Note note = db.cursorToNote(cursor);
db.insertNote(note);
cursor.moveToNext();
}
cursor.close();
context.deleteDatabase(dataTempName);
}
private OnBackupListener onBackupListener;
public void setOnBackupListener(OnBackupListener onBackupListener) {
this.onBackupListener = onBackupListener;
}
public interface OnBackupListener {
public void onFinishExport(String error);
public void onFinishImport(String error);
}
}
你需要注意 2 以下:
- 其用于导入数据库AsyncTask的,因为这个过程可能需要很长的时间. 这将有助于展示 1 仿佛没有用户放心的认为具有冷冻应用被处理对话框以指示用户.
-
在副本, 我所说的命令 注意注意= db.cursorToNote(光标); 以前cursorToNote秩序类和私营DatabaseHelper, 你现在要叫 修复公众 NHE.
该界面导入的文件列表
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/lv_backup"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
在文件string.xml一些变化
<resources>
<string name="app_name">My Note</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="add">Add</string>
<string name="delete">Delete</string>
<string name="save">Save</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="backup_data">Backup data</string>
<string name="import_data">Import data</string>
<string name="backup_before_import">Do you want backup curren database before import an old databas?</string>
<string name="select_file">Select file</string>
<string name="backup_empty">Backup file is empty</string>
<!-- -->
<string name="title_note">Title note</string>
<string name="content">Content</string>
<string name="title_activity_note">Create Note</string>
</resources>
您可以 在这里下载源代码.
这就是它,然后. 祝你学习好.
在本教程的帖子 数据库的Android仲 由 nguyenvanquan7826



欢迎您,陆军,
首先,我们发现了一系列的Android你的数据库是非常有用的.
我又试了一次,你的指导下,代码共享的东西 5 备份和导入. 但我不备份和导入失败不, 我检查了代码几次也没有找到其中的错误.
他们在Eclipse代码, 这是你的源代码. 我希望你帮她修复错误. 如果导入库项目,然后重新启动该项目再次失败,直到错误信息是构建是.
http://www.mediafire.com/download/jq14bp7dw4poe0a/SQLite_Demo.rar
军事谢谢!
这种新的考验对不起太忙几天来帮助你.
满足你 2 错误:
– 写入字符串表创建错误:
public static final String CREATE_TABLE_NOTE = "CREATE TABLE " + TABLE_NOTE + "(" + KEY_ID_NOTE + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL " + "," + KEY_TITLE_NOTE + " TEXT NOT NULL" + "," + KEY_CONTENT_NOTE + " TEXT NOT NULL" + "," + KEY_LAST_MODIFIED_NOTE + " TEXT DEFAULT \'\'" + ")";当您添加KEY_LAST_MODIFIED_NOTE你没有在文本默认的空间,以便在新的安装将不再作记录.
– 错误备份,因为你错了行:
您必须复制从表中TABLE_NOTE不会从数据库中拷贝.
修复:
有错误我backupdata.java
在这条线
SQLiteDatabase DBBACKUP = context.openOrCreateDatabase(dataTempName,
SQLiteDatabase.CREATE_IF_NECESSARY, 空值);
什么是错误? 你可以在这里发布错误或拍照?
你好,
请您可以更新到的gradle Android版本 3. 我有在新版本上运行旧的程序太多的问题. 我是一个初学者,所以我不知道该怎么办的变化. 我在网上什么都试过了, 没有任何帮助.
感谢报告. 该项目在我的教程使用旧版本与您. 你能告诉我你的问题?
你可以做一个例子备份和使用客房持久库恢复? 我有难以适应这一功能使用客房持久库
私人无效了CopyData(SQLiteDatabase DBBACKUP) {
DatabaseHelper DB =新DatabaseHelper(背景);
db.deleteNote(空值);
/** 复制主题表的所有行 */
光标光标= dbBackup.query(真正, DatabaseHelper.TABLE_NOTE, 空值, 空值, 空值, 空值, 空值, 空值, 空值);
cursor.moveToFirst();
而 (!cursor.isAfterLast()) {
注意注意= db.cursorToNote(光标);
db.insertNote(注意);
cursor.moveToNext();
}
cursor.close();
context.deleteDatabase(dataTempName);
}
你好, 对不起它, 我不使用这个库, 所以我不知道,使它.
你好,
我正在使用您的代码创建备份. 从getExternalStorageDirectory开始() 已不推荐使用. 下面怎么写 .
私有的最终String文件夹SD = Environment.getExternalStorageDirectory() + “/MyNote”;
谢谢,
你好, 你可以在这里看到: https://stackoverflow.com/questions/57116335/environment-getexternalstoragedirectory-deprecated-in-api-level-29-java