標籤:sqlite android cursor 資料庫操作 adb
寫這篇文章主要是網上的對sqlite的操作太多且太雜,很多時候都不能很好的運用到自己的項目中,結構不清晰,我自己寫了一篇適合剛剛接觸的人看的操作方法。
近來用android時要將一些資料儲存起來,一開始用的是preferences,後來要儲存的東西多了,發現用preferences明顯不能滿足要求了,而且發現用這個的話代碼就變得有點亂了,所以才開始學習使用sqlite資料庫,一開始以為不就是個資料庫麼,和平時的mysql啊或者是sqlserver都一樣,都很簡單的,但後來真正在用的時候才發現困難一個接著一個,但還是在不斷的摸索中一步一步的不斷解決困難,後來發現學習安卓的話當自己實在找不到思路時看看網上的一些教學視頻也是個不錯的選擇。這裡推薦一個視頻不錯,我就是照這個視頻學的。http://www.tudou.com/programs/view/2qH5Am_3MsM/
寫一下android操作資料庫中的一些準備。
首先,配一下adb的環境變數,因為每次都要到adb的目錄下去啟動實在太麻煩了,下面是具體步驟,當然也可以該其他檔案,我習慣改這個,可以改完後可以source一下使它生效。
1、sudo gedit /etc/profile
2、將下面的兩句加到上面開啟的檔案裡
export ANDROID_HOME=/home/sdk檔案路徑
export PATH=$PATH:$ANDROID_HOME/platform-tools
3、重啟電腦,大功告成!!
adb配好以後,我們最好還要給手機裡的資料庫訪問的許可權,一般在/data/data/包名/database 裡面,用adb shell進入後su獲得手機root許可權,然後給許可權chmod。
要讀資料庫檔案的話就用命令 sqlite3 資料庫檔案 ,其中的資料庫可以直接在adb shell中運行sqlite3,但我按照網上弄的就是不能在adb shell中開啟sqlite3資料庫,說命令沒有找到,我該傳的檔案都傳了,沒辦法,只有在eclipse裡的ddms的file explore裡把資料庫檔案到處然後在linux終端裡運行sqlite3資料庫來看了。
還有要注意的是寫sql語句時一定要注意"select * from " +TABLE_NAME 中的from和引號要留有空格,不然的話就連在一起了。
下面的有一個知識要講一下,sqlite的增加,刪除等操作都挺簡單的,麻煩的就是查詢操作,一般都借用Cursor來儲存查詢資料,一開始我沒怎麼注意這是一個指標類型,指向資料庫裡的資料,而我一開始寫的時候把資料庫的關閉操作寫在了Cursor操作的前面,也就是說先把資料庫關閉了再對Cursor對象進行操作,這樣的話就造成了Cursor的null 指標,也就註定杯具了好久。。。
下面就貼一些關於sqlite資料庫操作的案例,這樣對一些還在困惑中的人有一些協助,同時有助於以後自己回顧。
SQLiteHelper.java(資料庫輔助類)
public class SQLiteHelper extends SQLiteOpenHelper{private static final String DATABASE_NAME="fpp.db";private static final int DATABASE_VERSION=17;//更改版本後資料庫將重新建立private static final String TABLE_NAME="test";/** * 在SQLiteOpenHelper的子類當中,必須有這個建構函式 * @param context 當前的Activity * @param name 表的名字(而不是資料庫的名字,這個類是用來操作資料庫的) * @param factory 用來在查詢資料庫的時候返回Cursor的子類,傳空值 * @param version 當前的資料庫的版本,整數且為遞增的數 */ public SQLitedata(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION);//繼承父類 // TODO Auto-generated constructor stub }/** * 該函數是在第一次建立資料庫時執行,只有當其調用getreadabledatebase() * 或者getwrittleabledatebase()而且是第一建立資料庫是才會執行該函數 */ public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub String sql = "CREATE TABLE " + TABLE_NAME + "(" + "id INTEGER," + "nid VARCHAR(11)," + "sid CHAR(1)," + "type INTEGER," + "stime DATETIME," + "locate_main VARCHAR(45)," + "locate_detail VARCHAR(45)," + "state INTEGER" + ")"; db.execSQL(sql); Log.e("create","資料庫建立成功"); }/***資料庫更新函數,當資料庫更新時會執行此函數*/ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = "DROP TABLE IF EXISTS " + TABLE_NAME; db.execSQL(sql); this.onCreate(db); // TODO Auto-generated method stub System.out.println("資料庫已經更新"); /** * 在此添加更新資料庫是要執行的操作 */ } }
MyOperator.java (資料庫操作類)
public class MyOperator {private static final String TABLE_NAME = "test";//要操作的資料表的名稱private SQLiteDatabase db=null;//資料庫操作//建構函式public MyOperator(SQLiteDatabase db){this.db=db;}////插入操作//public void insert(int id,String nid,String sid,int type,//String stime,String etime,String desc,String locate_main,String locate_detail,int state)//{//String sql = "INSERT INTO " + TABLE_NAME + " (id,nid,sid,type,stime,etime,desc,locate_main,locate_detail,state)"//+ " VALUES(?,?,?,?,?,?,?,?,?,?)";//Object args[]=new Object[]{id,nid,sid,type,stime,etime,desc,locate_main,locate_detail,state};//this.db.execSQL(sql, args);//this.db.close();//}//插入重載操作public void insert(int id,int state){String sql = "INSERT INTO " + TABLE_NAME + " (id,state)" +" VALUES(?,?)";Object args[]=new Object[]{id,state};this.db.execSQL(sql, args);this.db.close();}//更新操作public void update(int id,int state){String sql = "UPDATE " + TABLE_NAME + " SET state=? WHERE id=?";Object args[]=new Object[]{state,id};this.db.execSQL(sql, args);this.db.close();}//刪除操作,刪除public void delete(int id){String sql = "DELETE FROM " + TABLE_NAME +" WHERE id=?";Object args[]=new Object[]{id};this.db.execSQL(sql, args);this.db.close();}//查詢操作,查詢表中所有的記錄返回列表public List<String> find(){List<String> all = new ArrayList<String>();//此時只是StringString sql = "SELECT * FROM " + TABLE_NAME;Cursor result = this.db.rawQuery(sql, null); //執行查詢語句for(result.moveToFirst();!result.isAfterLast();result.moveToNext())//採用迴圈的方式查詢資料{all.add(result.getInt(0)+","+result.getString(1)+","+result.getString(2)+","+result.getInt(3)+","+result.getString(4)+","+result.getString(5)+","+result.getString(6)+","+result.getString(7)+","+result.getString(8));} this.db.close();return all;}//查詢操作蟲重載函數,返回指定ID的列表public int getstatebyID(int id){int num=-1;//錯誤狀態-1List<String> all = new ArrayList<String>();//此時只是StringString sql = "SELECT state FROM " + TABLE_NAME + " where id=?" ;String args[] = new String[]{String.valueOf(id)};Cursor result = this.db.rawQuery(sql, args);for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){num=result.getInt(0);}Log.e("database", "圖片狀態state"+ String.valueOf(num));this.db.close();return num;}//判斷插入資料的ID是否已經存在資料庫中。public boolean check_same(int id){String sql="SELECT id from " + TABLE_NAME + " where id = ?";String args[] =new String[]{String.valueOf(id)};Cursor result=this.db.rawQuery(sql,args);Log.e("database", "the sql has been excuate");Log.e("database","the hang count" + String.valueOf(result.getCount()));if(result.getCount()==0)//判斷得到的返回資料是否為空白{Log.e("database", "return false and not exist the same result" + String.valueOf(result.getCount()));this.db.close();return false;}else{Log.e("database", "return true and exist the same result"+ String.valueOf(result.getCount()));this.db.close();return true;}}}
隨便的一個項目中的activity(activity 類,操作開啟資料庫已經在裡面)
public class MainActivity extends Activity {private static LinkedList<Map<String, Object>> mListItems;private PullToRefreshListView pullToRefreshListView;private ProblemController problemController = ProblemController.getInstance();private SQLiteOpenHelper helper =null;private MyOperator mytab=null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.helper=new SQLitedata(this);//資料庫操作輔助類 setPullToRefreshView(); } @Override public boolean onCreateOptionsMenu(Menu _menu){ super.onCreateOptionsMenu(_menu); _menu.add(0, 0, 0, "設定"); return true; } @Override public boolean onOptionsItemSelected(MenuItem _item){ switch (_item.getItemId()) {case 0:{Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);startActivity(intent);break;}} return true; } private class GetDataTask extends AsyncTask<Void, Void, String[]> { @Override protected String[] doInBackground(Void... params) { if(listToShowData(problemController.getNewProblems())){ }else {Message message = new Message();handler.sendMessage(message); } return mStrings; } @Override protected void onPostExecute(String[] result) { pullToRefreshListView.onRefreshComplete(); super.onPostExecute(result); } } private String[] mStrings = {};/** * @param _newslist 需要顯示的訊息列表 */private boolean listToShowData(LinkedList<Problem> _problems) {if(_problems != null){mListItems.clear();for (Problem news : _problems) {//將資料插入資料庫進行初始化//這裡需要一個判斷重複的操作,如果資料的id已經在資料庫中就不需要進行插入資料mytab = new MyOperator(helper.getWritableDatabase());Log.e("database", "start check if id exists and insert the id,the id is "+String.valueOf(news.getID()));if(!mytab.check_same(news.getID())){Log.e("database", "the id is not exist,insert the new id now.....");mytab = new MyOperator(helper.getWritableDatabase());mytab.insert(news.getID(), 1);Log.e("database", "insert finished");}Map<String, Object> tmpMap = new HashMap<String, Object>();//用來儲存日誌名稱的MaptmpMap.put("id", news.getID());tmpMap.put("describe", "模組:" + news.getSid() + "出現故障!");tmpMap.put("time", news.getsTime());tmpMap.put("img", R.drawable.icon_important);Log.e("database", "start read database");//讀取資料庫判斷這個事件的狀態顯示對應的表徵圖,1表示預設狀態問號,2表示已察看,3表示事件已經完成勾mytab = new MyOperator(helper.getWritableDatabase());int state = mytab.getstatebyID(news.getID());switch(state){case 1:tmpMap.put("state_img", R.drawable.icon_question);break;case 2:tmpMap.put("state_img", R.drawable.icon_process);break;case 3:tmpMap.put("state_img", R.drawable.icon_correct);break;default:tmpMap.put("state_img", R.drawable.icon_correct);}mListItems.add(tmpMap);Log.e(news.toString(), news.toString());}return true;}else {return false;}}/** * @param 對下拉重新整理控制項進行設定 */private void setPullToRefreshView(){mListItems = new LinkedList<Map<String,Object>>();pullToRefreshListView = (PullToRefreshListView)findViewById(R.id.pullToRefreshListView1);pullToRefreshListView.setOnRefreshListener(new OnRefreshListener() { public void onRefresh() { new GetDataTask().execute();//拉資料的線程開啟 }});pullToRefreshListView.setOnItemClickListener(new OnItemClickListener() {public void onItemClick(AdapterView<?> arg0, View arg1, final int arg2,long arg3) {Log.e("Pull", String.valueOf(arg2));ShareData.showProblem = problemController.getOldProblems().get(arg2 - 1);Intent intent = new Intent(getApplicationContext(), DetailsActivity.class);//設定新的圖片,現在用資料庫的方法,所以這個操作就不需要了,到時候統一讀取圖片//ImageView tempImage=(ImageView)arg1.findViewById(R.id.imageView2);//tempImage.setImageResource(R.drawable.icon_correct);//把狀態存入資料庫,判斷圖片狀態,如果為1則說明沒有被訪問過,改變為2mytab = new MyOperator(helper.getWritableDatabase());if(mytab.getstatebyID(ShareData.showProblem.getID())==1){mytab = new MyOperator(helper.getWritableDatabase());mytab.update(ShareData.showProblem.getID(), 2);}//將故障ID傳入到選項介面,以便與判斷哪個頁面選了哪些選項。int id=ShareData.showProblem.getID();Bundle bd=new Bundle();bd.putInt("id", id);intent.putExtra("ID", bd);startActivity(intent);//傳入到了另一個介面}});pullToRefreshListView.setOnItemLongClickListener(new OnItemLongClickListener() {public boolean onItemLongClick(AdapterView<?> arg0, View arg1,int arg2, long arg3) {Log.e("PullLong", String.valueOf(arg2));return true;}});SimpleAdapter adapter = new SimpleAdapter(getApplicationContext(), mListItems, R.layout.layout_listitem, new String[]{"id", "img", "describe", "time" ,"state_img"}, new int[]{R.id.title_TV, R.id.imageView1, R.id.content_TV, R.id.date_TV, R.id.imageView2}); pullToRefreshListView.setAdapter(adapter); }private Handler handler = new Handler(){@Overridepublic void handleMessage(Message message) {Toast.makeText(getApplicationContext(), "網路狀況出現問題!", Toast.LENGTH_LONG).show();}};}