[アンドロイド] データベースtrongのアンドロイド – P5のバックアップとインポート

Androidのデータベースに書き込まれたシリーズのように、新しいでたらめに対する今日忙しい数日. ある程度 5, また、最後の部分は私がどのようにアンドロイドでのバックアップおよびインポートデータベースにご案内します.

ステップ 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>

ステップ 2: MainActivityできますバックアップとインポートのメニューを作成します。

キャップニャットファイル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 メソッド onFinishExportonFinishImport その, 2 この方法は、私たちは、通知を処理することを可能にするか、バックアップとインポートが完成行った後、.

イベントコールメニューを開始すると 2 メソッド backupData.exportToSDbackupData.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>

あなたはできます ここではソースコードをダウンロード.

それはそれだ. 私はあなたに良い学習を希望します.

チュートリアルで行われた投稿 データベースtrongのアンドロイド によって nguyenvanquan7826