1. 程式人生 > 資料庫 >Android Studio 從外部匯入資料庫並顯示到頁面中

Android Studio 從外部匯入資料庫並顯示到頁面中

文章目錄

Android Studio從外部匯入資料庫並顯示到頁面中

最近在開發一個單詞學習的App, 準備好單詞的外部資料庫之後突然卡在了將資料庫匯入專案這一步,參考了很多網上的資料,自己動手嘗試了一遍,最後成功了。在這裡將我的操作過程記錄一下。

1. 從外部匯入資料庫

首先,要匯入的資料庫及其內容是這樣的(使用的資料庫工具是SQLite Expert Professional 4.2):
在這裡插入圖片描述
該資料庫儲存在檔案1.db中。

開啟Android Studio,在要匯入的專案中,切換至Project檢視,新建一個和Java、res同級的目錄assets(這個目錄的位置與開發環境有關,我看網上說使用Eclispe開發環境時它在res/下,但在AS中它必須與res目錄同級),然後將1.db

複製到assets目錄下:
在這裡插入圖片描述
做到這裡的時候,不知道大家有沒有這樣的疑問:為什麼要將資料庫檔案放在assets下?

有個解釋說,這個資料夾主要用於存放應用程式中使用的外部資原始檔,然後程式可以通過 I/O 流(使用AssetManager)對目錄中的檔案進行讀寫,存放在此目錄下的檔案都會被打包到釋出包中。

接著,實現類MyDBOpenHelper.java;

這個類就是實現從assets目錄讀取資料庫檔案然後寫入SD卡中,如果在SD卡中存在,就開啟資料庫,不存在就從assets目錄下複製過去。

import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.database.Cursor;
import android.util.Log;


public class MyDBOpenHelper extends SQLiteOpenHelper {
    private static String PACKAGE_NAME = "com.example.wordsofmultilanguage"; //包名
    private static String DB_PATH =  "/data" + Environment.getDataDirectory().getAbsolutePath() + "/" + PACKAGE_NAME + "/databases/";
    private static String DB_NAME = "1";
    private SQLiteDatabase db;
    private final Context context;

    public MyDBOpenHelper(Context context) {
        super(context,  DB_NAME , null, 1);
        this. context  = context;
    }

    public void createDB() throws IOException {
        this.getReadableDatabase();
        try {
            copyDB();
        } catch (IOException e) {
            throw new Error("Error copying database");
        }
    }
    public void copyDB() throws IOException{
        try {
            InputStream ip =  context.getAssets().open(DB_NAME+".db");
            Log.i("Input Stream....",ip+"");
            String op=  DB_PATH  +  DB_NAME ;
            OutputStream output = new FileOutputStream( op);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = ip.read(buffer))>0){
                output.write(buffer, 0, length);
                Log.i("Content.... ",length+"");
            }
            output.flush();
            output.close();
            ip.close();
        }
        catch (IOException e) {
            Log.v("error", e.toString());
        }
    }

    public void openDB() throws SQLException {
        String myPath = DB_PATH + DB_NAME;
        db = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
        Log.i("open DB......",db.toString());
    }

    @Override
    public synchronized void close() {

        if(db != null)
            db.close();

        super.close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

2. 顯示資料庫內容

在頁面上顯示資料庫內容(即英文單詞和釋義)時,用到了ListView控制元件,新建一個 佈局檔案im.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<ListView
    android:id="@+id/word_info"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>
</LinearLayout>

對ListView的每一條item做佈局item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/word"
        android:textSize="16dp"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/mean1"
        android:textSize="16dp"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/mean2"
        android:textSize="16dp"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/mean3"
        android:textSize="16dp"
        />

</LinearLayout>

完成第一步外部資料庫的匯入之後,定義一個類initdate.java用來例項化資料庫:

public class initdate {
    public String word;
    public String meaning1;
    public String meaning2;
    public String meaning3;
    public initdate(String word, String meaning1, String meaning2, String meaning3){
        this.word = word;
        this.meaning1 = meaning1;
        this.meaning2 = meaning2;
        this.meaning3 = meaning3;
    }
}

然後,實現類

package com.example.wordsofmultilanguage;

import android.content.Context;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.SimpleTimeZone;

import android.database.Cursor;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class test extends AppCompatActivity {
	//建立一個List物件來儲存資料
    List<initdate>list = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.im);
        ListView listView = (ListView)this.findViewById(R.id.word_info);

        MyDBOpenHelper db;
        db = new MyDBOpenHelper(this);
        try {
            db.createDB();
        } catch (IOException ioe) {
            throw new Error("Database not created....");
        }

        try {
            db.openDB();
        } catch (SQLException sqle) {
            throw sqle;
        }
        
        SQLiteDatabase db1;
        db1 = openOrCreateDatabase("1", Context.MODE_PRIVATE, null);
        Cursor c = db1.rawQuery("SELECT * FROM words1", null);

        c.moveToFirst();

        //獲取表資料
        while (!c.isAfterLast()) {
            list.add(new initdate(c.getString(c.getColumnIndex("word")),c.getString(c.getColumnIndex("meaning1")),
                    c.getString(c.getColumnIndex("meaning2")),c.getString(c.getColumnIndex("meaning3"))));

            c.moveToNext();
        }
		
		//將獲取到的資料通過一個迴圈存放到map物件中
        List<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>();
        for(int i = 0; i < list.size(); i++){
            HashMap<String, Object>item = new HashMap<String, Object>();
            item.put("word", list.get(i).word);
            item.put("meaning1", list.get(i).meaning1);
            if(list.get(i).meaning2 != null){
                item.put("meaning2", list.get(i).meaning2);
            }
            //item.put("meaning2", list.get(i).meaning2);
            if(list.get(i).meaning3 != null){
                item.put("meaning2", list.get(i).meaning3);
            }
            //item.put("meaning3", list.get(i).mmeaning3);
            data.add(item);
        }
        //建立SimpleAdapter介面卡將資料繫結到item顯示控制元件上
        SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.item,
                new String[]{"word", "meaning1", "meaning2", "meaning3"}, new int[]{R.id.word, R.id.mean1, R.id.mean2, R.id.mean3});
        //實現列表的顯示
        listView.setAdapter(adapter);
    }
}

效果圖:
在這裡插入圖片描述

3. 踩坑記錄

在操作過程中,匯入資料庫檔案的時候曾經碰到以下問題:
在這裡插入圖片描述
我資料庫使用的編碼形式是UTF-8,這是我匯入1.db檔案後顯示的內容,全是亂碼,並且提示File was loaded in the wrong encoding: 'UTF-8',我的解決辦法是啥也不做,不用管,只要原先的資料庫內容沒問題,繼續往下做就可以。原因好像是因為AS打不開這個型別的檔案,要用專門的SQLite工具開啟,如果嘗試開啟的話就會變成一堆亂碼,而且從此以後不管刪除、重新匯入多少次AS都很”貼心“地給你顯示成亂碼。(小白第一次用 AS 開發專案,啥也不懂,被這玩意兒坑死了,想了各種辦法,最後發現它根本不影響……)