本地网页端读取 SQLite 数据

更新时间:2016-01-31

放置 HTML 文件

  • 因为 Android Studio 默认是没有 assets 文件夹的,所以需要在 src/main/ 下新建 assets 文件夹,用于存放html文件
  • 另外该文件夹下是可以设置文件夹的,然后将实现写好的 HTML 以及 js/css 文件按你喜欢的方式放置就好了。

使用 WebView 加载

在 activity_web.xml(当前所用 activity 所对应的 layout)中 WebView 的布局设置

<WebView
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:id="@+id/ng"/>

进行相应的设置就能行了

private String url;
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_web);
  getSupportActionBar().setDisplayHomeAsUpEnabled(true);

  final WebView webView = (WebView)findViewById(R.id.ng);
  final WebSettings webSettings = webView.getSettings();
  // 要在网页中启用JavaScript,这句不能少
  webSettings.setJavaScriptEnabled(true);
  webSettings.setSupportZoom(false);
  webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

  url = "file:///android_asset/ng.html";
  // 避免调用手机上其他外部浏览器打开html页面
  webView.setWebViewClient(new WebViewClient() {
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
      view.loadUrl(url);
      return true;
    }
  });
  // 打开网页
  webView.loadUrl(url);
}

适用于 Android 4.4 之后

在 Android 4.4 之后 WebSQL 无法改变数据库的路径,需要借助 addJavasciptInterface() 来实现网页对 Android 方法的调用。由于网页通过 JavaScript 和 Android 中的 Java 的接口,也就是说,数据库的操作是通过 Android 代码实现的。

webView.addJavascriptInterface(new Object() {
  // 在android4.2以后一定需要这句话
  @JavascriptInterface  
  // 方法一定要是public类型的    
  public void doSomething() {
    //code..
  }
}, "Demo");

在 JavaScript 中调用:

// Demo前面定义过的
window.Demo.doSomething();

数据库操作部分,如果你有使用 SQL 的经验,应该比较好理解
首先需要定义表的结构,即需要一个 Contract Class

public final class RedContract {
  public RedContract() { }

  public static abstract class RedEntry implements BaseColumns {
    public static final String TABLE_NAME = "RedMoney";
    public static final String COLUMN_NAME_ENTRY_ID = "redid";
    public static final String COLUMN_NAME_AMOUNT = "amount";
    public static final String COLUMN_NAME_COMMENT = "comment";
  }
}

为了使用 SQLiteOpenHelper, 需要创建一个子类并重写 onCreate(), onUpgrade()onOpen() 等 callback 方法。也许还需要实现 onDowngrade(), 但这并不是必需的。

public class RedDbHelper extends SQLiteOpenHelper {
  public static final int DATABASE_VERSION = 1;
  public static final String DATABASE_NAME = "Red.db";
  public static final String SQL_CREATE_ENTRIES =
      "CREATE TABLE " + RedContract.RedEntry.TABLE_NAME + " (" +
      RedContract.RedEntry._ID + " INTEGER PRIMARY KEY," +
      RedContract.RedEntry.COLUMN_NAME_ENTRY_ID + " INTEGER,"+
      RedContract.RedEntry.COLUMN_NAME_AMOUNT + " INTEGER,"+
      RedContract.RedEntry.COLUMN_NAME_COMMENT + " TEXT" +
      " )";
  public static final String SQL_DELETE_ENTRIES =
      "DROP TABLE IF EXISTS " + RedContract.RedEntry.TABLE_NAME;

  public RedDbHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
  }
  public void onCreate(SQLiteDatabase db) {
    db.execSQL(SQL_CREATE_ENTRIES);
  }
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL(SQL_DELETE_ENTRIES);
    onCreate(db);
  }
  public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    onUpgrade(db, oldVersion, newVersion);
  }
}

添加信息至数据库,通过传递一个 ContentValues 对象到 insert() 方法:

public void insert(View view) {
  RedDbHelper mDbHelper = new RedDbHelper(getBaseContext());
  SQLiteDatabase db = mDbHelper.getWritableDatabase();
  ContentValues values = new ContentValues();
  values.put(RedContract.RedEntry.COLUMN_NAME_ENTRY_ID, 2);
  values.put(RedContract.RedEntry.COLUMN_NAME_AMOUNT, 666);
  values.put(RedContract.RedEntry.COLUMN_NAME_COMMENT, "happy");
  int rowid;
  rowId = db.insert(
          RedContract.RedEntry.TABLE_NAME,
          null, //对于没有数据的项不进行补充
          values);
}

从数据库中读取信息,需要使用 query() 方法,传递需要查询的条件。查询后会返回一个 Cursor 对象。

RedDbHelper mDbHelper = new RedDbHelper(getBaseContext());
SQLiteDatabase db = mDbHelper.getReadableDatabase();
String[] projection = {
  RedContract.RedEntry.COLUMN_NAME_ENTRY_ID,
  RedContract.RedEntry.COLUMN_NAME_AMOUNT,
  RedContract.RedEntry.COLUMN_NAME_COMMENT
};
String selection = RedContract.RedEntry._ID + " Like ?";
String[] selectionArgs = { String.valueOf(1) };
String sortOrder = RedContract.RedEntry.COLUMN_NAME_ENTRY_ID + " DESC";
Cursor c = db.query(
    RedContract.RedEntry.TABLE_NAME,        //Table red
    projection,                             //select id,amount,comment
    selection,                              //where _ID like ?
    selectionArgs,                          //1
    null,
    null,
    sortOrder);                             // id desc

要查询在 cursor 中的行,使用 cursor 的其中一个 move 方法,但必须在读取值之前调用。一般来说应该先调用 moveToFirst() 函数,将读取位置置于结果集最开始的位置。

对每一行,我们可以使用 cursor 的其中一个 get 方法如 getString() 或 getLong() 获取列的值。对于每一个 get 方法必须传递想要获取的列的索引位置(index position),索引位置可以通过调用 getColumnIndex() 或 getColumnIndexOrThrow() 获得。

c.moveToFirst();
int id = c.getInt(
  c.getColumnIndexOrThrow(RedContract.RedEntry.COLUMN_NAME_ENTRY_ID)
);

JavaScript 与 Android 传输的数据使用 JSON 格式 Android 端需要使用 Gson
下载 gson-2.x.jar 并导入到 libs 文件夹下,举个栗子:

import com.google.gson.Gson;
class BagOfPrimitives {
  private int value1 = 1;
  private String value2 = "abc";
  private transient int value3 = 3;
  BagOfPrimitives() {
  // no-args constructor
  }
}

// Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String item = gson.toJson(obj);  
// ==> item is {"value1":1,"value2":"abc"}

JavaScript 中需先处理一下得到 JSON 类

item = JSON.parse(item);
// ==> item is {"value1":1,"value2":"abc"}

远程更新 HTML 代码

// TODO

适用于 Android 4.4 之前的

在4.4之后,Android 浏览器使用的内核从 Android webkit 切换到 Chromium webkit, WebView API也相应发生变化,其中包括 database storage API.

设置 Web SQL 的数据库路径

final String databasePath = this.getApplicationContext().getDir(database, Context.MODE_PRIVATE).getPath();
WebSettings settings = webView.getSettings();
settings.setDatabasePath(databasePath);

然后就可以通过 JavaScript 来操作数据库了,例如:

function loaddb() {
  // 建立/打开一个数据库
  var db = openDatabase(‘testdb’, ‘1.0’, ‘说明’, 2 * 1024 * 1024);

  db.transaction(function (tx){
    // 创建表
    tx.executeSql(‘CREATE TABLE IF NOT EXISTS person (_id INTEGER,
            person_name TEXT, address TEXT)’);
    // 在表中插入数据
    tx.executeSql(‘INSERT INTO person (_id, person_name, address)
            VALUES(1, “Hardik Trivedi”, “Ahmedabad,Gujarat,India”)’);
  });
}

说明

查看相关 Java 文件的完整代码:点我
要是你发现本文有哪里说错的,还请指出