編輯:關於Android編程
Android中有許多的數據存儲方式,如果我們有少量的數據需要存儲,那麼使用:SharedPreferences、文件存儲就可以了。但是如果有大量數據需要進行讀寫,那麼就需要使用到數據庫了。Android中內置了SQLite數據庫,而SQLite數據庫是一個真正輕量級的數據庫,它並沒有後台進程,整個數據庫就對應於一個文件。Android也給我們提供了大量的API,使用起來很方便。
Android提供了SQLiteDatabase對象來管理數據庫,SQLiteDatabase有提供方法來創建,刪除,執行SQL命令,並執行常見的數據庫管理任務。
SQLiteDatabase提供了如下靜態方法來打開一個文件對應的數據庫:
SQLiteDatabase openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags):當我們獲取到SQLiteDatabase對象之後,就可以調用SQLiteDatabase如下的方法來對數據庫進行操作了:
Android提供了上面的方法,來幫助開發者更“簡便”的對數據庫進行增刪改查。但是其實這些方法完全可以通過SQL語句來完成。而用記上面復雜的參數的時間,就可以來掌握SQL語句了。
上面的方法,都是返回了一個Cursor接口,該接口提供對由數據庫查詢返回的結果集的隨機讀寫訪問,而Cursor同樣提供了如下方法來移動查詢結果的記錄指針:
一旦通過以上方法移動到指定行後,就可以調用Cursor的getXXX()方法來獲取指定列的數據了。
// 判斷數據庫文件存放的文件夾是否存在,不存在則創建 String mPath = Environment.getExternalStorageDirectory() + "/db/"; File file = new File(mPath); if(!file.exists() && !file.isDirectory()){ // 創建目錄 file.mkdirs(); } // 使用靜態方法打開數據庫(不存在則創建),第二個參數用於返回Course工廠,null則表示使用默認工廠。 SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(mPath + "blog.db", null);創建表:
// 執行創建表SQL語句,創建了一個名為blog_info的表 String createSql = "create table blog_info(blog_id integer primary key, blog_name varchar(255), blog_link varchar(255))"; database.execSQL(createSql);
注意:由於數據庫創建在SD卡中,所以需要加上寫入SD卡權限
在創建好數據庫和表之後就可以對表中的數據進行管理和操作了。我們可以直接通過execSQL()方法執行SQL語句來操作,也可以使用Android給我們直接提供的增刪改查方法。
往剛剛上面創建的數據庫blog_info表中插入一條數據:
ContentValues contentValues = new ContentValues(); contentValues.put("blog_name", "Airsaid"); contentValues.put("blog_link", "http://blog.csdn.net/airsaid"); // line為新添加的行號,該行號是一個內部值,與主鍵id無關,當發生錯誤時,返回-1。 long line = mDatabase.insert("blog_info", null, contentValues);
刪除和”Airsaid”相關的數據:
int num = mDatabase.delete("blog_info", "blog_name like ?", new String[]{"Airsaid"}); Toast.makeText(this, "一共刪除了:" + num + "條數據", Toast.LENGTH_SHORT).show();
將所有主鍵大於5的blog_name改為周游:
ContentValues contentValues = new ContentValues(); contentValues.put("blog_name", "周游"); int num = mDatabase.update("blog_info", contentValues, "_id > ?", new String[]{"5"});
由於查詢條件的不確定性,所以query()方法的參數真的是比較長。。感覺建議在寫查詢語句的時候,可以直接使用rawQuery()方法進行查詢。
下面寫一個實例,用戶分別輸入博客名和博客鏈接,點插入後,將數據存儲到數據庫,並用列表展示出來:
* 布局:
代碼:
public class MainActivity extends AppCompatActivity { private String mPath = Environment.getExternalStorageDirectory() + "/db/"; private static final String DB_NAME = "blog.db"; private EditText mEdtName; private EditText mEdtLink; private ListView mListView; private SQLiteDatabase mDatabase; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mEdtName = (EditText) findViewById(R.id.edt_blog_name); mEdtLink = (EditText) findViewById(R.id.edt_blog_link); mListView = (ListView) findViewById(R.id.listView); // 判斷數據庫文件存放的文件夾是否存在,不存在則創建 File file = new File(mPath); if(!file.exists() && !file.isDirectory()){ // 創建目錄 file.mkdirs(); } // 使用靜態方法打開數據庫(不存在則創建),第二個參數用於返回Course工廠,null則表示使用默認工廠。 mDatabase = SQLiteDatabase.openOrCreateDatabase(mPath + DB_NAME, null); // 執行創建表SQL語句,創建了一個名為blog_info的表 String createSql = "create table blog_info(_id integer primary key, blog_name varchar(255), blog_link varchar(255))"; mDatabase.execSQL(createSql); } /** * 插入數據 */ public void insert(View v){ // 獲取用戶輸入信息 String name = mEdtName.getText().toString(); String link = mEdtLink.getText().toString(); // 執行SQL語句插入數據 mDatabase.execSQL("insert into blog_info values(null, ?, ?)", new String[]{name, link}); // 填充數據到ListView Cursor cursor = mDatabase.rawQuery("select * from blog_info", null); SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item_listview_blog, cursor , new String[]{"blog_name", "blog_link"}, new int[]{R.id.txt_name, R.id.txt_link} , CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); mListView.setAdapter(adapter); } }Item布局:
運行結果:
數據庫操作,事務是少不了的,而SQLiteDatabase也提供了如下幾個方法來操作事務:
* beginTransaction():開始事務。
* endTransaction():結束事務。
* inTransaction():判斷當前上下文是否處於事務中。
當調用endTransaction()方法結束事務的時候,那麼到底是提交事務還是進行回滾事務呢?這取決於SQLiteDatabase是否調用了:setTransactionSuccessful()方法來設置事務標志,如果在執行事務的時設置了,當事務成功則提交事務,否則程序將回滾事務。
其實在真實項目開發中,很少使用SQLiteDatabase的方法來打開數據庫,而是通過繼承Android給我們提供的SQLiteOpenHelper抽象類來創建。
SQLiteOpenHelper是一個輔助類,用於來幫助我們建立和管理數據庫。我們只需要繼承它,並實現兩個抽象方法:
* onCreate(SQLiteDatabase db):在初次生成數據庫的時候會被調用,用於生成表結構。
* onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):在數據庫版本發生更新時會被調用,oldVersion為舊數據庫版本號,newVersion為新版本數據庫版本號。
SQLiteOpenHelper有如下方法:
public class MyDatabaseHelper extends SQLiteOpenHelper { public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { // 創建表結構 db.execSQL("create table dict(_id integer primary key autoincrement, word, detail)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }布局很簡單,分別為單詞輸入框和釋義輸入框,輸入完成後點擊按鈕保存到數據庫,保存數據後,用戶可以輸入要查詢的生詞進行查詢,點擊查詢將結果作為dialog展示出來。添加生詞的方法如下:
public void add(View v) { // 添加生詞 String word = mEdtWord.getText().toString(); String detail = mEdtDetail.getText().toString(); if(TextUtils.isEmpty(word) || TextUtils.isEmpty(detail)){ Toast.makeText(this, "輸入的數據不能為空", Toast.LENGTH_SHORT).show(); return; } SQLiteDatabase database = mDb.getReadableDatabase(); database.execSQL("insert into dict values(null, ? , ?)", new String[]{word, detail}); Toast.makeText(this, "添加成功", Toast.LENGTH_SHORT).show(); }
主要是通過SQLiteOpenHelper的 getReadableDatabase()方法獲取了SQLiteDatabase對象。這裡需要注意的是:
getReadableDatabase()方法會先以讀寫方式打開數據庫,如果數據庫的磁盤空間已經滿了,那麼就會打開失敗,然後再嘗試以只讀的方式打開數據庫。
而通過getWritableDatabase()方法,如果磁盤空間已滿,打開時就會出錯。
public void seek(View v) { // 查看生詞 String dict = mEdtInput.getText().toString(); SQLiteDatabase database = mDb.getReadableDatabase(); Cursor cursor = database.rawQuery("select * from dict where word like ? or detail like ?" , new String[]{"%" + dict + "%", "%" + dict + "%"}); List將結果展示:dicts = new ArrayList<>(); while (cursor.moveToNext()){ String word = cursor.getString(1); String detail = cursor.getString(2); dicts.add("生詞:" + word + " 解釋:" + detail); } showData(dicts); }
private void showData(Listdicts) { if(dicts.size() < 1) { Toast.makeText(this, "沒有找到到該生詞數據", Toast.LENGTH_SHORT).show(); return; } String[] strings = dicts.toArray(new String[dicts.size()]); for (String string : strings) { Log.e("test", string); } new AlertDialog.Builder(this) .setTitle("查詢出來的單詞結果") .setItems(dicts.toArray(new String[dicts.size()]), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }).create().show(); }
運行結果:
如今很多Android手機新品都已經預裝或可升級到Android 4.4.x版本了,而該版本最大特色就是引入了ART模式。那麼,如何才能啟動這個模式呢?AR
(未給Fragment的布局設置BackGound)之前關於Android中Fragment的概念以及創建方式,我專門寫了一篇博文《詳解Android中Fragment的
1、把aar復制到項目中的 libs 裡面 2、在module 裡面的build.gradle 的根目錄添加repositories{ flatDir {
Android實現功能:Listview嵌套viewpager仿淘寶搜狐視頻主頁面,和listview的下拉刷新。直接上圖下面給出我源碼的主要文件構成:MyListVie
今天調試一個bug的時候,情景如下:一個Activity A,需要用st