Android 應用開發】Android 數據存儲 之 SQLite數據庫詳解

      網友投稿 919 2022-05-29

      .

      轉載請注明出處 :?http://blog.csdn.net/shulianghan/article/details/19028665

      .

      SQLiteDataBase示例程序-?:

      -- GirHub?- https://github.com/han1202012/SQLite_NewsList.git.

      SQLiteOpenHelper示例程序-?:

      --?GitHub?:?https://github.com/han1202012/NewsSearch.git?.

      SQLite數據庫簡介 :

      -- 輕量級 : SQLite數據庫是一個輕量級的數據庫, 適用于少量數據的CURD;

      -- 文件本質 : SQLite數據庫支持大部分SQL語法, 允許使用SQL語句操作數據庫, 其本質是一個文件, 不需要安裝啟動;

      -- 數據讀寫 : SQLite數據庫打開只是打開了一個文件的讀寫流, 如果有大數據量讀寫, 需要高并發存儲, 那么就不應該使用SQLite;

      一. 使用SQLiteDataBase操作數據庫

      SQLiteDataBase簡介 : SQLIteDataBase代表一個數據庫, 其本質是一個數據庫文件, 創建該類對象, 可以使用該對象的一系列方法操作數據庫;

      1. SQLiteDataBase方法介紹

      (1) 打開數據庫方法

      使用靜態方法打開文件對應的數據庫, 數據庫文件通常是 文件名.db 形式的;

      打開數據庫: 根據標志位flag要求打開數據庫, 這個方法很強大;

      public static SQLiteDatabase openDatabase (String path, SQLiteDatabase.CursorFactory factory, int flags)

      -- 參數① path : path 要打開 或者 需要創建的 數據庫文件的路徑;

      -- 參數② factory : 當打開的數據庫執行查詢語句的時候 會創建一個Cursor對象, 這時會調用Cursor工廠類 factory, 可以填寫null默認值;

      -- 參數③ flag :

      OPEN_READWRITE 打開一個讀寫數據庫, 如果磁盤滿了, 之前寫入的也作廢;

      READ_OPENONLY 打開只讀數據庫, 這時讀取數據庫的可靠方法;

      CREATE_IF_NECESSARY 打開數據庫, 如果數據庫不存在, 就創建這個數據庫;

      NO_LOCALIZED_CALLATORS 打開數據庫 不根據本地語言順序進行排序, 使用這種模式創建數據庫, 排序器不會被創建, 使用這個數據庫 和 創建這個數據庫的時候必須都使用這個標識, 如果這個標識被使用了, 那么setLocal()方法將不會起到任何作用;

      打開數據庫 : 根據數據庫文件 對象打開數據庫, 如果數據庫不存在就創建數據庫;

      public static SQLiteDatabase openOrCreateDatabase (File file, SQLiteDatabase.CursorFactory factory)

      打開數據庫 : 根據數據庫文件 路徑打開數據庫, 如果數據庫不存在就創建數據庫;

      public static SQLiteDatabase openOrCreateDatabase (String path, SQLiteDatabase.CursorFactory factory)

      (2) 操作數據庫方法

      執行SQL語句, 如果需要動態傳入SQL語句參數, 將動態參數放入一個Object[]數組中;

      public void execSQL (String sql, Object[] bindArgs)

      該方法適用于 :修改表結構,創建和刪除表 觸發器 視圖 索引等,重建數據庫表的索引,數據庫升級,事物中保存點,沒有返回值的語句;

      參數介紹 :

      -- 參數① sql: 要執行的SQL語句, 只能執行一條, 多條語句用分號隔開不管用, 參數使用 "?" 占位符代替;

      -- 參數② bingArgs: 替換上面SQL語句中的 "?" 占位符, 按照數組中的順序依次替換;

      該方法執行固定的SQL語句, 沒有參數, 用法與上面的 execSQL(sql, bindArgs)一致;

      public void execSQL (String sql)

      插入數據 : 向數據庫中的 一個表 插入 一行 數據;

      public long insert (String table, String nullColumnHack, ContentValues values)

      -- 參數① table : 數據庫中的表名, 要插入數據的表;

      -- 參數② nullColumnHack : 該參數是可選的, 數據庫表中不允許插入一行空的數據, 插入數據至少有一列不為null才能插入, 如果后面的values是null, 并且不知道列的名稱, 那么插入操作會失敗, 為了避免這種情況, 就出現了本參數, 為了防止 values為null的情況;

      -- 參數③ values : 相當于一個Map集合,鍵 是列名,值 是對應列名要插入的數據;

      插入原則 : 不管 第三個 ContentValues參數 是否為null, 執行insert()方法都會添加一條記錄, 如果values參數為null, 會添加一個除主鍵之外其它字段都為null的記錄;

      nullColumnHack參數作用分析SQL語句 : 在SQL語句中在表名后面必須跟著一個列名, 例如 " insert into appale_info(name) values("喬幫主") ", 這是values參數不為null的情況下,如果values參數為null, 那么導致表名 "apple_info" 后面的列名也為null, 這樣SQL語句就不合法了, 因此這里必須加上一個默認的列名, 以防values參數為null;

      實例 :

      //創建表數據, 鍵 為 列名, 值 為 對應的表數據

      ContentValues values = new ContentValues();

      values.put("name", "喬幫主");

      values.put("age", 54);

      //向表中插入數據, 如果values為null, 就會添加一個

      long rowsNum = db.insert("apple_info", "name", values);

      上面代碼轉成SQL語句 :

      insert into apple_info (name, age) values ('喬幫主', 54)

      假如values為null轉化成SQL語句 :

      insert into apple_info (name) values ()

      更新指定表中的特定數據 :

      public int update (String table, ContentValues values, String whereClause, String[] whereArgs)

      參數介紹 :

      -- 參數① table : 數據庫表名稱;

      -- 參數② values : 該值類似Map集合, 鍵 是 列名, 值 是 要更新的數據, 這個值可以為null, 如果為null 這些數據會被清空;

      -- 參數③ whereClause: where選擇語句, 選擇那些行進行數據的更新, 如果該參數為 null, 就會修改所有行;

      -- 參數④ whereArgs : where選擇語句的參數, 逐個替換 whereClause 中的占位符;

      返回值 : 返回修改的行數;

      實例 :

      //創建表數據, 鍵 為 列名, 值 為 對應的表數據

      ContentValues values = new ContentValues();

      values.put("name", "喬幫主");

      values.put("age", 54);

      int result = db.update("apple_info", values, "name=?", new String[]{"喬幫主"});

      update apple_info set name='喬幫主', age=56 where name='喬幫主'

      刪除指定表中特定數據 :

      public int delete (String table, String whereClause, String[] whereArgs)

      -- 參數① table : 要操作的數據庫表名;

      -- 參數② whereClause : where選擇語句, 選擇哪些行要被刪除, 如果為null, 就刪除所有行;

      -- 參數③ whereArgs : where語句的參數, 逐個替換where語句中的 "?" 占位符;

      實例 :

      int result = db.delete("apple_info", "name=?", new String[]{"喬幫主"});

      delete apple_info where name='喬幫主'

      .

      public Cursor query (boolean distinct, String table, String[] columns,

      String selection, String[] selectionArgs,

      String groupBy, String having,

      String orderBy, String limit,

      CancellationSignal cancellationSignal)

      參數介紹 :

      -- 參數① distinct : 是否去重復, true 去重復;

      -- 參數② table : 要查詢的表名;

      -- 參數③ columns : 要查詢的列名, 如果為null, 就會查詢所有的列;

      -- 參數④ whereClause : 條件查詢子句, 在這里可以使用占位符 "?";

      -- 參數⑤ whereArgs : whereClause查詢子句中的傳入的參數值, 逐個替換 "?" 占位符;

      -- 參數⑥ groupBy: 控制分組, 如果為null 將不會分組;

      -- 參數⑦ having : 對分組進行過濾;

      -- 參數⑧ orderBy : 對記錄進行排序;

      -- 參數⑨ limite : 用于分頁, 如果為null, 就認為不進行分頁查詢;

      -- 參數⑩ cancellationSignal : 進程中取消操作的信號, 如果操作被取消, 當查詢命令執行時會拋出?OperationCanceledException 異常;

      實例 :

      Cursor cursor = db.query(true, "apple_info", new String[]{"_id, name, age"},

      "name like ?", new String[]{"喬%"},

      null, null,

      "_id desc", "5, 10");

      cursor.close();

      通過執行SQL語句, 查詢結果;

      public Cursor rawQuery (String sql, String[] selectionArgs)

      -- 參數① sql : 要執行的SQL語句, 可以使用 "?" 作為占位符;

      -- 參數② selectionArgs : sql語句中的參數, 按照次序依次替換占位符 "?";

      (3) SQLite中的事務

      開啟事務 :

      public void beginTransaction ()

      public void endTransaction ()

      public boolean inTransaction ()

      示例代碼 :

      db.beginTransaction();

      try {

      ... ...

      //調用該方法設置事務成功, 如果沒有調用該方法, 在調用endTransaction()方法的時候會回滾事務

      db.setTransactionSuccessful();

      } finally {

      db.endTransaction();

      }

      2. Cursor的相關方法

      (1) 移動記錄指針方法

      方法作用 : 將記錄指針向上 或者 向下移動offset行, offset為正數就是向下,為負數 就是向上;

      public abstract boolean move (int offset)

      記錄指針移動到第一行, 如果移動成功返回true;

      public abstract boolean moveToFirst ()

      記錄指針移動到最后一行, 如果移動成功返回true;

      public abstract boolean moveToLast ()

      移動到上一行, 成功返回true;

      public abstract boolean moveToPrevious ()

      移動到下一行, 成功返回true;

      public abstract boolean moveToNext ()

      移動到指定行, 成功返回true;

      public abstract boolean moveToPosition (int position)

      (2) 獲取記錄數據方法

      獲取某個類型的數據 :

      public abstract float getFloat (int columnIndex);//獲取浮點型數據

      public abstract int getInt (int columnIndex);//獲取整型數據

      public abstract long getLong (int columnIndex);//獲取長整型數據

      public abstract short getShort (int columnIndex);//獲取短整型數據

      public abstract String getString (int columnIndex);//獲取字符串數據

      3. sqlite3工具介紹

      工具簡介 : sqlite3 是一個簡單的數據庫管理工具, 該用于位于 SDK tools 目錄下;

      獲取數據庫文件 : 使用虛擬機運行程序在 data/data/包名 安裝目錄下, 數據庫文件在里面可以找到;

      打開數據庫 : 進入cmd命令行, 使用sqlite3 數據庫文件 命令打開數據庫;

      常用的sqlite3 工具命令:

      -- 打開數據庫: sqlite3 文件路徑名 ;

      -- 查看當前數據庫 : .database ;

      -- 查看當前數據庫中的表 : .tables ;

      -- 查看sqlite3的幫助 : .help ;

      4. SQLite的數據存儲格式

      支持的數據類型 : SQLite數據庫 內部 只支持null,integer,real(浮點型),text(文本),blob(二進制數據) 五種數據類型;

      數據類型轉換 : SQLite可以接受varchar(n), char(n), decimal(p,s) 等數據類型, 不過內部的機制使將這個數據類型轉換成上面的五種數據類型進行存儲;

      無類型限制: SQLite允許將各種類型的數據保存到各種類型的字段中, 沒有嚴格的某個字段 必須存放某個類型的數據這樣的限制, 因此創建數據庫 和 插入數據的時候不用關心這個列的數據類型;

      -- eg: 在SQLite中可以將字符串數據放到整型字段中, 但是主鍵id, 不能隨便放其它數據, 只能存放64衛整數;

      二. 新聞列表程序實例

      1. 要點解析

      (1) 數據庫相關操作

      使用?openOrCreateDatabase()方法創建數據庫 : 傳入數據庫的路徑 和 CursorFactory對象;

      -- Context.getFilesDir()方法: 該方法返回 內存中應用安裝目錄中的 文件存儲目錄的絕對路徑, 在這里是 "data/data/shuliang.han.database/files", 整個數據庫的完整路徑是 :"data/data/shuliang.han.database/files/news.db";

      //打開或者創建數據庫, 這里是創建數據庫

      db = SQLiteDatabase.openOrCreateDatabase(this.getFilesDir().toString() + "/news.db", null);

      db.execSQL("create table news_table (" +

      "_id integer primary key autoincrement, " +

      "news_tittle varchar(50), " +

      "news_content varchar(5000))");

      db.execSQL("insert into news_table values(null, ?, ?)", new String[]{tittle, content});

      Cursor cursor = db.rawQuery("select * from news_table", null);

      @Override

      protected void onDestroy() {

      super.onDestroy();

      //在Activity銷毀的時候, 如果沒有

      if(db != null && db.isOpen())

      db.close();

      }

      (2) ListView相關操作

      創建SimpleCursorAdapter適配器 :

      參數解析 :

      -- 參數① context : 上下文對象;

      -- 參數② resource : ListView條目的布局;

      -- 參數③ cursor : 從數據庫表中查詢出來的記錄;

      -- 參數④ string[]: 數據庫中表的字段名稱;

      -- 參數⑤ int[]: 將數據庫中每行的字段 按照對應順序 放入到該數組對應組件中;

      SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(

      getApplicationContext(),

      R.layout.item,

      cursor,

      new String[]{"news_tittle", "news_content"},

      new int[]{R.id.tittle, R.id.content});

      listView.setAdapter(cursorAdapter);

      2. 詳細代碼

      SQLiteDataBase示例程序- :

      -- GirHub - https://github.com/han1202012/SQLite_NewsList.git.

      (1) MainActivity代碼

      package shuliang.han.database;

      import android.app.Activity;

      import android.database.Cursor;

      import android.database.sqlite.SQLiteDatabase;

      import android.database.sqlite.SQLiteException;

      import android.os.Bundle;

      import android.view.View;

      import android.widget.EditText;

      import android.widget.ListView;

      import android.widget.SimpleCursorAdapter;

      public class MainActivity extends Activity {

      private SQLiteDatabase db; //數據庫對象

      private ListView listView; //列表

      private EditText et_tittle; //輸入的新聞標題

      private EditText et_content; //輸入的新聞內容

      @Override

      protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      setContentView(R.layout.activity_main);

      //打開或者創建數據庫, 這里是創建數據庫

      db = SQLiteDatabase.openOrCreateDatabase(this.getFilesDir().toString() + "/news.db", null);

      System.out.println(this.getFilesDir().toString() + "/news.db");

      //初始化組件

      listView = (ListView) findViewById(R.id.lv_news);

      et_tittle = (EditText) findViewById(R.id.et_news_tittle);

      et_content = (EditText) findViewById(R.id.et_news_content);

      }

      /*

      * 插入數據到數據庫中的觸發點擊事件

      * 如果數據庫存在就能正常訪問數據庫, 如果不存在訪問數據庫的時候就會出現 SQLiteException 異常

      * 正常訪問 : 獲取輸入的新聞標題 和 新聞內容, 將標題 和 內容插入到數據庫, 重新獲取Cursor, 使用Cursor刷新ListView內容

      * 異常訪問 : 如果訪問出現了SQLiteException異常, 說明數據庫不存在, 這時就需要先創建數據庫

      */

      public void insertNews(View view) {

      String tittle = et_tittle.getText().toString();

      String content = et_content.getText().toString();

      try{

      insertData(db, tittle, content);

      Cursor cursor = db.rawQuery("select * from news_table", null);

      inflateListView(cursor);

      }catch(SQLiteException exception){

      db.execSQL("create table news_table (" +

      "_id integer primary key autoincrement, " +

      "news_tittle varchar(50), " +

      "news_content varchar(5000))");

      insertData(db, tittle, content);

      Cursor cursor = db.rawQuery("select * from news_table", null);

      inflateListView(cursor);

      }

      }

      /*

      * 向數據庫中插入數據

      * 參數介紹 :

      * -- 參數① : SQL語句, 在這個語句中使用 ? 作為占位符, 占位符中的內容在后面的字符串中按照順序進行替換

      * -- 參數② : 替換參數①中占位符中的內容

      */

      private void insertData(SQLiteDatabase db, String tittle, String content) {

      db.execSQL("insert into news_table values(null, ?, ?)", new String[]{tittle, content});

      }

      /*

      * 刷新數據庫列表顯示

      * 1. 關聯SimpleCursorAdapter與數據庫表, 獲取數據庫表中的最新數據

      * 2. 將最新的SimpleCursorAdapter設置給ListView

      */

      private void inflateListView(Cursor cursor) {

      SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(

      getApplicationContext(),

      R.layout.item,

      cursor,

      new String[]{"news_tittle", "news_content"},

      new int[]{R.id.tittle, R.id.content});

      listView.setAdapter(cursorAdapter);

      }

      @Override

      protected void onDestroy() {

      super.onDestroy();

      //在Activity銷毀的時候, 如果沒有

      if(db != null && db.isOpen())

      db.close();

      }

      }

      (2) XML布局文件

      主布局文件 :

      xmlns:tools="http://schemas.android.com/tools"

      android:layout_width="match_parent"

      android:layout_height="match_parent"

      android:paddingBottom="@dimen/activity_vertical_margin"

      android:paddingLeft="@dimen/activity_horizontal_margin"

      android:paddingRight="@dimen/activity_horizontal_margin"

      android:paddingTop="@dimen/activity_vertical_margin"

      tools:context=".MainActivity"

      android:orientation="vertical">

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="新聞標題" />

      android:id="@+id/et_news_tittle"

      android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:singleLine="true"

      android:hint="點擊此處輸入新聞標題"/>

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="新聞內容" />

      android:id="@+id/et_news_content"

      android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:lines="2"

      android:hint="點擊此處輸入新聞內容"/>

      android:id="@+id/bt_add_news"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:onClick="insertNews"

      android:text="添加新聞" />

      android:id="@+id/lv_news"

      android:layout_width="fill_parent"

      android:layout_height="fill_parent"/>

      android:layout_width="match_parent"

      android:layout_height="match_parent"

      android:orientation="vertical" >

      android:id="@+id/tittle"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:textSize="15dp"

      android:textColor="#FFFF00"/>

      android:id="@+id/content"

      android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:textSize="10dp"

      android:textColor="#00FF00"/>

      效果圖 :

      三. SQLiteOpenHelper類操作數據庫

      單獨使用SQLiteDataBase操作數據庫的弊端: 對數據庫的表進行操作的時候, 我們不知道數據庫中表是否存在, 首先要進行表操作, 在出現異常之后, 在異常捕獲的try catch 代碼塊中創建表, 這樣操作很繁瑣;

      SQLiteOpenHelper作用 : 該類用來管理數據庫的創建 和版本更新, 通常使用其子類, 實現onCreate() 和 onUpgrade()方法;

      1. 類中的方法介紹

      (1) 讀寫打開數據庫

      以讀寫的方式打開數據庫 :先以讀寫方式打開數據庫, 如果磁盤滿了, 就會打開失敗,然后會嘗試以只讀的方式打開數據庫;

      public SQLiteDatabase getReadableDatabase ()

      (2) 寫方式打開數據庫

      以寫的方式打開數據庫 :先以讀寫方式打開數據庫, 如果磁盤滿了, 就會出錯,不推薦使用這種方法, 使用 getReadableDatabase()方法即可;

      public SQLiteDatabase getWritableDatabase ()

      (3) 創建數據庫

      創建數據庫 : 第一次創建數據庫的時候回調該方法, 一般在該方法中 創建數據庫表;

      public abstract void onCreate (SQLiteDatabase db)

      -- 調用時機: 當使用getReadableDatabase()方法 獲取數據庫 實例 的時候, 如果數據庫不存在, 就會調用這個方法;

      -- 方法內容 : 重寫該方法一般 將 創建數據庫表的 execSQL()方法 和 初始化表數據的一些 insert()方法寫在里面;

      (4) 更新數據庫

      更新數據庫 : 升級軟件的時候更新數據庫表結構, 在數據庫版本發生變化的時候調用;

      public abstract void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion)

      -- 調用時機 : 數據庫版本發生變化的時候回調, newVersion是當前數據庫版本號, oldVersion是舊的版本號;

      -- 識別版本 : 創建SQLiteOpenHelper子類對象的時候,必須傳入一個version參數, 該參數就是當前數據庫版本, 只要這個版本高于之前的版本, 就會觸發這個onUpgrade()方法;

      (5) 關閉數據庫

      關閉打開的數據庫 :

      public synchronized void close ()

      2. 示例程序要點解析

      (1) 在onCreate()方法中創建表

      創建數據庫表 : 定義一個數據庫SQL語句, 之后在onCreate()方法中 execSQL()執行該語句;

      final String SQL_CREATE_TABLE = "create table news_table (" +

      "_id integer primary key autoincrement, " +

      "news_tittle varchar(50), " +

      "news_content varchar(5000))";

      @Override

      public void onCreate(SQLiteDatabase db) {

      db.execSQL(SQL_CREATE_TABLE);

      }

      (2) 插入數據

      插入內容 : 打開數據庫,如果存在直接插入內容, 如果不存在就創建表在插入內容;

      helper.getReadableDatabase().execSQL("insert into news_table values(null, ?, ?)",

      new String[]{tittle, content});

      (3) 查詢數據庫

      查詢數據 : 使用SQLiteOpenHelper子類對象打開數據庫, 并且執行查詢語句;

      Cursor cursor = helper.getReadableDatabase().rawQuery("select * from news_table", null);

      (4) 解析Cursor記錄

      將Cursor中的數據轉為?ArrayList> 類型數據 :

      -- 遍歷條件 : Cursor的moveToNext()方法, 如果成功移到下一個記錄, 就執行循環內容;

      -- 獲取表中數據 : Cursor的getString(1) 就是獲取 這一樣記錄中的 第二列的數據, 第一列是 "_id" 主鍵;

      private ArrayList> cursor2list(Cursor cursor) {

      ArrayList> list = new ArrayList>();

      //遍歷Cursor

      while(cursor.moveToNext()){

      Map map = new HashMap();

      map.put("tittle", cursor.getString(1));

      map.put("content", cursor.getString(2));

      list.add(map);

      }

      return list;

      }

      (5) 開啟一個Activity并傳遞數據

      流程 :

      -- ① 創建Bundle對象 : 該對象可以存放數據, 并可以放到Intent對象中, 傳遞給另外的組件;

      -- ② Bundle存數據 : 使用putSerializable()方法, 可以存放對象, 將?ArrayList> 存入里面;

      -- ③ 創建Intent對象 : 傳入要跳轉的Activity的Class對象;

      -- ④ Bundle加入Intent對象 : 將存放好數據的Bundle對象加入到Intent對象中;

      -- ⑤ 開啟Activity : 使用startActivity(intent)方法跳轉Activity;

      Bundle bundle = new Bundle();

      bundle.putSerializable("news", cursor2list(cursor));

      Intent intent = new Intent(this, SearchResultActivity.class);

      intent.putExtras(bundle);

      startActivity(intent);

      (6) 在Activity中獲取Intent傳遞的數據

      執行流程 :

      -- 獲取Intent對象: 調用 getIntent()方法, 可以獲取Activity跳轉到額Intent對象;

      -- 獲取Bundle對象 : Intent對象調用 getExtras()方法, 可以獲取存放數據的Bundle對象;

      -- 將數據從Bundle對象取出 : 調用getSerializable()方法, 并將返回值轉換成?List> 類型;

      //獲取跳轉到該Activity的intent對象

      Intent intent = getIntent();

      //獲取Intent對象所攜帶的數據

      Bundle bundle = intent.getExtras();

      //從Bundle中取出List>數據

      @SuppressWarnings("unchecked")

      List> list = (List>)bundle.getSerializable("news");

      (7) 適配器轉化

      將?List> 類型數據轉為 SimpleAdapter類型適配器 :

      參數介紹 :

      -- 參數① context : 上下文對象;

      -- 參數②List>?: 數據源;

      -- 參數③ id : ListView元素條目布局文件;

      -- 參數④ string[] : 數據源中Map對象的鍵;

      -- 參數⑤ int[]: 數據源中Map每個鍵對應的值 存放的組件 id;

      SimpleAdapter adapter = new SimpleAdapter(

      getApplicationContext(), //上下文對象

      list, //數據源

      R.layout.item, //List顯示布局

      new String[]{"tittle", "content"}, //List中map的鍵值

      new int[]{R.id.tittle, R.id.content}); //填充到的布局文件

      3. 實例程序源碼

      (1) SQLiteOpenHelper源碼

      package shuliang.han.newssearch;

      import android.content.Context;

      import android.database.sqlite.SQLiteDatabase;

      import android.database.sqlite.SQLiteOpenHelper;

      public class NewsSearchDatabaseHelper extends SQLiteOpenHelper {

      final String SQL_CREATE_TABLE = "create table news_table (" +

      "_id integer primary key autoincrement, " +

      "news_tittle varchar(50), " +

      "news_content varchar(5000))";

      /*

      * 構造方法 :

      * 參數介紹 :

      * 參數① : 上下文對象

      * 參數② : 數據庫名稱

      * 參數③ : 數據庫版本號

      */

      public NewsSearchDatabaseHelper(Context context, String name, int version) {

      super(context, name, null, version);

      }

      @Override

      public void onCreate(SQLiteDatabase db) {

      db.execSQL(SQL_CREATE_TABLE);

      }

      @Override

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

      System.out.println("call update");

      }

      }

      (2) MainActivity源碼

      package shuliang.han.newssearch;

      import java.util.ArrayList;

      import java.util.HashMap;

      import java.util.Map;

      import android.app.Activity;

      import android.content.Intent;

      import android.database.Cursor;

      import android.os.Bundle;

      import android.view.View;

      import android.widget.EditText;

      import android.widget.ListView;

      import android.widget.SimpleCursorAdapter;

      public class MainActivity extends Activity {

      private NewsSearchDatabaseHelper helper; //數據庫幫助類

      private EditText et_tittle; //輸入新聞標題

      private EditText et_content; //輸入新聞內容

      private ListView listView; //顯示新聞列表

      @Override

      protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      setContentView(R.layout.activity_main);

      helper = new NewsSearchDatabaseHelper(getApplicationContext(), "news", 1);

      //初始化控件

      et_tittle = (EditText) findViewById(R.id.et_news_tittle);

      et_content = (EditText) findViewById(R.id.et_news_content);

      listView = (ListView) findViewById(R.id.lv_news);

      }

      /*

      * 按鈕點擊事件

      * 通過判斷被點擊的組件, 執行不同的操作

      */

      public void onClick(View view) {

      int id = view.getId();

      switch (id) {

      case R.id.bt_add_news:

      insertNews();

      break;

      case R.id.bt_query_news:

      queryNews();

      break;

      default:

      break;

      }

      }

      /*

      * 插入新聞數據

      * 1. 從EditText組件中獲取新聞的標題 和 新聞內容

      * 2. 獲取數據庫并從將 新聞標題 和 內容 插入到數據庫中

      * 3. 重新查詢數據庫 獲得Cursor對象

      * 4. 根據cursor對象創建SimpleCursorAdapter對象

      * 5. 將SimpleCursorAdapter設置給ListView, 顯示新聞列表

      */

      private void insertNews() {

      String tittle = et_tittle.getText().toString();

      String content = et_content.getText().toString();

      helper.getReadableDatabase().execSQL("insert into news_table values(null, ?, ?)",

      new String[]{tittle, content});

      Cursor cursor = helper.getReadableDatabase().rawQuery("select * from news_table", null);

      inflateListView(cursor);

      }

      /*

      * 刷新數據庫列表顯示

      * 1. 關聯SimpleCursorAdapter與數據庫表, 獲取數據庫表中的最新數據

      * 2. 將最新的SimpleCursorAdapter設置給ListView

      */

      private void inflateListView(Cursor cursor) {

      SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(

      getApplicationContext(),

      R.layout.item,

      cursor,

      new String[]{"news_tittle", "news_content"},

      new int[]{R.id.tittle, R.id.content});

      listView.setAdapter(cursorAdapter);

      }

      /*

      * 查詢新聞

      * 1. 獲取要查詢的新聞標題 和 新聞內容

      * 2. 查詢數據庫 獲取 Cursor, 并將Cursor轉化為List>類型的集合

      * 3. 將集合放入bundle, Intent開啟另一個Activity, 將bundle放入intent對象, 跳轉Activity

      *

      */

      private void queryNews() {

      String tittle = et_tittle.getText().toString();

      String content = et_content.getText().toString();

      【Android 應用開發】Android 數據存儲 之 SQLite數據庫詳解

      Cursor cursor = helper.getReadableDatabase().rawQuery(

      "select * from news_table where news_tittle like ? or news_content like ?",

      new String[]{"%" + tittle + "%", "%" + content + "%"});

      Bundle bundle = new Bundle();

      bundle.putSerializable("news", cursor2list(cursor));

      Intent intent = new Intent(this, SearchResultActivity.class);

      intent.putExtras(bundle);

      startActivity(intent);

      }

      /*

      * 返回一個ArrayList集合, 這個集合中每個元素是一個Map集合, 每個Map集合有兩個元素

      * 解析Cursor對象 :

      * 1. cursor光標向下移動一格;

      * 2. 創建一個HashMap對象

      * 3. 使用 cursor.getString(列標號)獲取該行中某列值, 將這個值放入map中

      * 4. 將Map對象放入

      */

      private ArrayList> cursor2list(Cursor cursor) {

      ArrayList> list = new ArrayList>();

      //遍歷Cursor

      while(cursor.moveToNext()){

      Map map = new HashMap();

      map.put("tittle", cursor.getString(1));

      map.put("content", cursor.getString(2));

      list.add(map);

      }

      return list;

      }

      @Override

      protected void onDestroy() {

      super.onDestroy();

      //釋放數據庫資源

      if(helper !=null)

      helper.close();

      }

      }

      (3) SearchResultActivity源碼

      package shuliang.han.newssearch;

      import java.util.List;

      import java.util.Map;

      import android.app.Activity;

      import android.content.Intent;

      import android.os.Bundle;

      import android.widget.ListView;

      import android.widget.SimpleAdapter;

      public class SearchResultActivity extends Activity {

      private ListView listView;

      @Override

      protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      //設置布局文件

      setContentView(R.layout.news_search_result);

      //初始化組件

      listView = (ListView) findViewById(R.id.lv_search_result);

      //獲取跳轉到該Activity的intent對象

      Intent intent = getIntent();

      //獲取Intent對象所攜帶的數據

      Bundle bundle = intent.getExtras();

      //從Bundle中取出List>數據

      @SuppressWarnings("unchecked")

      List> list = (List>)bundle.getSerializable("news");

      SimpleAdapter adapter = new SimpleAdapter(

      getApplicationContext(), //上下文對象

      list, //數據源

      R.layout.item, //List顯示布局

      new String[]{"tittle", "content"}, //List中map的鍵值

      new int[]{R.id.tittle, R.id.content}); //填充到的布局文件

      listView.setAdapter(adapter);

      }

      }

      (4) XML文件

      主界面布局 :

      xmlns:tools="http://schemas.android.com/tools"

      android:layout_width="match_parent"

      android:layout_height="match_parent"

      android:paddingBottom="@dimen/activity_vertical_margin"

      android:paddingLeft="@dimen/activity_horizontal_margin"

      android:paddingRight="@dimen/activity_horizontal_margin"

      android:paddingTop="@dimen/activity_vertical_margin"

      tools:context=".MainActivity"

      android:orientation="vertical">

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="新聞標題" />

      android:id="@+id/et_news_tittle"

      android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:singleLine="true"

      android:hint="點擊此處輸入新聞標題"/>

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:text="新聞內容" />

      android:id="@+id/et_news_content"

      android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:lines="2"

      android:hint="點擊此處輸入新聞內容"/>

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:orientation="horizontal"

      android:layout_gravity="center_horizontal">

      android:id="@+id/bt_add_news"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:onClick="onClick"

      android:text="添加新聞" />

      android:id="@+id/bt_query_news"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:onClick="onClick"

      android:text="查找新聞" />

      android:id="@+id/lv_news"

      android:layout_width="fill_parent"

      android:layout_height="fill_parent"/>

      android:layout_width="match_parent"

      android:layout_height="match_parent"

      android:orientation="vertical" >

      android:id="@+id/tittle"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:textSize="15dp"

      android:textColor="#FFFF00"/>

      android:id="@+id/content"

      android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:textSize="10dp"

      android:textColor="#00FF00"/>

      android:layout_width="match_parent"

      android:layout_height="match_parent"

      android:orientation="vertical" >

      android:id="@+id/lv_search_result"

      android:layout_height="wrap_content"

      android:layout_width="wrap_content"/>

      SQLiteOpenHelper示例程序- :

      -- GitHub : https://github.com/han1202012/NewsSearch.git?.

      效果圖 :

      .

      轉載請注明出處?:?http://blog.csdn.net/shulianghan/article/details/19028665

      .

      SQL SQLite 數據庫

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:育人用人,不止于物聯網
      下一篇:ASR項目實戰-架構設計
      相關文章
      久久久综合亚洲色一区二区三区| 国产午夜亚洲精品不卡| AV在线播放日韩亚洲欧| 色噜噜亚洲男人的天堂| 亚洲国产成人资源在线软件| 亚洲成在人天堂在线| 亚洲午夜在线一区| 久久亚洲成a人片| 亚洲中文字幕无码久久2017 | 亚洲网红精品大秀在线观看| 亚洲成AV人片在线播放无码| 亚洲成a人片77777kkkk| 国产成A人亚洲精V品无码| 国产精品亚洲一区二区三区在线 | 亚洲人成色7777在线观看| 亚洲一区二区三区自拍公司| 国产综合亚洲专区在线| 亚洲熟女一区二区三区| 亚洲va久久久噜噜噜久久| 久久久久亚洲精品美女| 亚洲视频中文字幕在线| 亚洲视频在线观看地址| 亚洲国产最大av| 亚洲区日韩精品中文字幕| 亚洲精品又粗又大又爽A片| 亚洲色自偷自拍另类小说| 亚洲精品第五页中文字幕| 精品亚洲成a人片在线观看少妇 | 亚洲天堂免费在线视频| 久久精品亚洲乱码伦伦中文| 中文字幕亚洲一区二区va在线| 亚洲午夜久久久久久噜噜噜| 亚洲国产成人一区二区精品区 | 亚洲国产午夜精品理论片在线播放 | 亚洲AV永久无码精品一百度影院 | 久久久无码精品亚洲日韩蜜臀浪潮 | 亚洲精品WWW久久久久久| 国产AV无码专区亚洲AWWW | 亚洲日韩一中文字暮| 亚洲AV永久无码精品一区二区国产| 亚洲毛片网址在线观看中文字幕|