Sqlite 分頁(http://www.cnblogs.com/shang53880/archive/2011/03/11/1981749.html)

風的王子發表於2014-01-04
 資料庫Sqlite的分頁顯示。


  很久沒有寫東西了,一來是因為專案緊,沒有多少時間,二來是因為最近越來越懶了。。。。


  今天說說資料庫的分頁顯示問題,都是些自己在專案中碰到的問題,寫在這裡,留作以後複習用。。。。


  所謂資料庫的分頁顯示,必須先要有一個資料庫,先建立一個資料庫。我這裡用的是繼承SQLiteOpenHelper的方法。具體如下:


1 package com.android.database;
2
3  import android.content.ContentValues;
4  import android.content.Context;
5  import android.database.sqlite.SQLiteDatabase;
6  import android.database.sqlite.SQLiteOpenHelper;
7  import android.provider.BaseColumns;
8  /**
9 *
10 * @author shangzhenxiang
11 * 建立資料庫,繼承SQLiteOpenHelper。
12 *
13 */
14  public class DBHelper extends SQLiteOpenHelper {
15
16 private static final String DATABASE_NAME = "database.db";
17 private static final int DATABASE_VERSION = 1;
18 private static final String TABLE_NAME = "database";
19 public static final String FIELD_TITLE = "title";
20
21 public DBHelper(Context context) {
22 super(context, DATABASE_NAME, null, DATABASE_VERSION);
23 }
24
25 /**
26 * 建立表,寫一個建立表的sql語句,然後呼叫db.execSQL(sql);之後向表中新增幾條資料。
27 */
28 @Override
29 public void onCreate(SQLiteDatabase db) {
30 String sql="Create table "+TABLE_NAME+"("+BaseColumns._ID+" integer primary key autoincrement,"
31 + FIELD_TITLE + " text );";
32 db.execSQL(sql);
33
34 //初始化資料庫
35   initDatabase(db);
36 }
37
38 //向資料庫的表中插入一些資料。
39   private void initDatabase(SQLiteDatabase db) {
40 ContentValues cv = new ContentValues();
41 cv.put("title", "cctv1 news");
42 db.insert(TABLE_NAME, null, cv);
43
44 cv.clear();
45 cv.put("title", "cctv2 news");
46 db.insert(TABLE_NAME, null, cv);
47
48 cv.clear();
49 cv.put("title", "cctv3 news");
50 db.insert(TABLE_NAME, null, cv);
51
52 cv.clear();
53 cv.put("title", "cctv4 news");
54 db.insert(TABLE_NAME, null, cv);
55
56 cv.clear();
57 cv.put("title", "cctv5 news");
58 db.insert(TABLE_NAME, null, cv);
59
60 cv.clear();
61 cv.put("title", "cctv6 news");
62 db.insert(TABLE_NAME, null, cv);
63
64 cv.clear();
65 cv.put("title", "cctv7 news");
66 db.insert(TABLE_NAME, null, cv);
67
68 cv.clear();
69 cv.put("title", "cctv8 news");
70 db.insert(TABLE_NAME, null, cv);
71
72 cv.clear();
73 cv.put("title", "cctv9 news");
74 db.insert(TABLE_NAME, null, cv);
75
76 cv.clear();
77 cv.put("title", "cctv10 news");
78 db.insert(TABLE_NAME, null, cv);
79
80 cv.clear();
81 cv.put("news_title", "guangshui tv");
82 db.insert(TABLE_NAME, null, cv);
83 }
84
85 //這裡是用於更新資料庫的。
86   @Override
87 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
88 String sql=" DROP TABLE IF EXISTS "+TABLE_NAME;
89 db.execSQL(sql);
90 onCreate(db);
91 }
92 }


  程式碼註釋的比較清楚,資料庫很簡單,只有一個id 和 title鍵值,id是自動增長的,是系統自動的,在建立資料庫的時候,我在裡面加了9跳資料,用作測試用。


  資料庫寫完了,那好,我們要測試一下,到底生成了資料庫檔案沒有呢?


  這時我們要寫一個測試程式,來生成資料庫檔案,這需要在 manifest檔案中做一些處理,如下所示:


1 <?xml version="1.0" encoding="utf-8"?>
2  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.android.sqlite"
4 android:versionCode="1"
5 android:versionName="1.0">
6 <uses-sdk android:minSdkVersion="8" />
7
8 <!-- android:targetPackage 是用來存放生成的資料庫的位置的,可以和manifest中的package相同 -->
9 <instrumentation
10 android:name="android.test.InstrumentationTestRunner"
11 android:targetPackage="com.android.sqlite"
12 android:label="test for my app"/>
13
14 <application android:icon="@drawable/icon" android:label="@string/app_name">
15 <!-- 這個是用來說明android測試的包 -->
16 <uses-library android:name="android.test.runner"/>
17 <activity android:name=".TestSqlite"
18 android:label="@string/app_name">
19 <intent-filter>
20 <action android:name="android.intent.action.MAIN" />
21 <category android:name="android.intent.category.LAUNCHER" />
22 </intent-filter>
23 </activity>
24
25 </application>
26  </manifest>


  首先要在manifest下建一個instrumentation的東西,裡面有名字,目標包:這個是存放生成的資料庫檔案的路徑,至於標籤,隨便寫寫就可以了。


  然後我們建立一個繼承自AndroidTestCase得類,在裡面寫一個方法。呼叫DBHelper裡面的getReadableDatabase或者getWritableDatabase就可以生成資料庫檔案了,如下所示:


1 package com.android.database;
2
3  import android.test.AndroidTestCase;
4  /**
5 *
6 * @author shangzhenxiang
7 *
8 */
9  public class DBTest extends AndroidTestCase {
10 public void testCreateRecordedDB() throws Exception {
11 DBHelper recordedDbHelper = new DBHelper(this.getContext());
12 /**
13 * 當我們呼叫recordedDbHelper的getWritableDatabase()或getReadableDatabase()的時候,
14 * 都會導致資料庫的生成
15 */
16 recordedDbHelper.getWritableDatabase();
17  // recordedDbHelper.getReadableDatabase();
18   }
19 }


  生成的資料庫檔案在哪裡呢?


  在data資料夾下的data資料夾中找到剛剛在manifest中的targetPackage:


  


  目標包中有個database的資料夾,裡面就是生成的資料庫檔案,如下圖:


  


  資料庫完成了,我們需要寫一個單獨的類用來顯示頁數和每一頁上的個數,如圖所示:


1 package com.android.domain;
2
3  public class Model {
4
5 /**
6 * @author shangzhenxiang
7 * index 用於顯示頁數
8 * View_Count 用於每一頁上顯示的個數
9 */
10 private int index;
11 private int View_Count;
12
13 public Model(int index, int View_Count) {
14 this.index = index;
15 this.View_Count = View_Count;
16 }
17
18 public int getIndex() {
19 return index;
20 }
21
22 public void setIndex(int index) {
23 this.index = index;
24 }
25
26 public int getView_Count() {
27 return View_Count;
28 }
29
30 public void setView_Count(int view_Count) {
31 View_Count = view_Count;
32 }
33
34
35 }


  我們還需要一個服務來運算元據庫,就是我們常說的業務邏輯層。


  我們需要對資料庫做什麼操作,都可以寫到這個類中:


1 package com.android.service;
2
3  import java.util.ArrayList;
4
5  import android.content.Context;
6  import android.database.Cursor;
7  import android.database.sqlite.SQLiteDatabase;
8
9 import com.android.database.DBHelper;
10 /**
11 *
12 * @author shangzhenxiang
13 *
14 */
15 public class DatabaseService {
16
17 private Context mContext;
18 private DBHelper dbHelper;
19
20 public DatabaseService(Context context) {
21 // TODO Auto-generated constructor stub
22 mContext = context;
23 dbHelper = new DBHelper(mContext);
24 }
25
26 //新增
27 public void insert(String title) {
28 SQLiteDatabase db = dbHelper.getWritableDatabase();
29 String sql = "insert into database(title) values(?)";
30 db.execSQL(sql, new String[]{title});
31 }
32
33 //刪除
34 public void delete(String title) {
35 SQLiteDatabase db = dbHelper.getWritableDatabase();
36 String sql = "delete from database where title = ?";
37 db.execSQL(sql, new String[]{title});
38 }
39
40 //查詢
41 public ArrayList<String> find(int id) {
42 SQLiteDatabase db = dbHelper.getWritableDatabase();
43 String sql = "select * from database where _id = ? ";
44 Cursor c = db.rawQuery(sql, new String[]{String.valueOf(id)});
45 ArrayList<String> titles = new ArrayList<String>();
46 if(c.moveToNext()) {
47 String title =c.getString(c.getColumnIndexOrThrow(DBHelper.FIELD_TITLE));
48 titles.add(title);
49 return titles;
50 }
51 //不用忘記關閉Cursor。
52 c.close();
53 return null;
54 }
55
56 //更新
57 public void upDate(int id, String title) {
58 SQLiteDatabase db = dbHelper.getWritableDatabase();
59 String sql = "update database set title =? where _id = ?";
60 db.execSQL(sql, new String[]{String.valueOf(title), String.valueOf(id)});
61 }
62
63 //查詢記錄的總數
64 public long getCount() {
65 SQLiteDatabase db = dbHelper.getWritableDatabase();
66 String sql = "select count(*) from database";
67 Cursor c = db.rawQuery(sql, null);
68 c.moveToFirst();
69 long length = c.getLong(0);
70 c.close();
71 return length;
72 }
73
74 /**
75 * 拿到所有的記錄條數
76 * @param firstResult 從第幾條資料開始查詢。
77 * @param maxResult 每頁顯示多少條記錄。
78 * @return 當前頁的記錄
79 */
80 public Cursor getAllItems(int firstResult, int maxResult) {
81 SQLiteDatabase db = dbHelper.getWritableDatabase();
82 String sql = "select * from database limit ?,?";
83 Cursor mCursor = db.rawQuery(sql, new String[]{String.valueOf(firstResult), String.valueOf(maxResult)});
84 return mCursor;
85 }
86 }


  寫一個佈局。裡面有一個ListView和2個Button:


1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 >
7 <ListView
8 android:id="@+id/testList"
9 android:layout_width="match_parent"
10 android:layout_height="0dip"
11 android:layout_weight="3"/>
12 <LinearLayout
13 android:orientation="horizontal"
14 android:layout_width="match_parent"
15 android:layout_height="0dip"
16 android:layout_weight="1">
17 <Button
18 android:id="@+id/leftButton"
19 android:layout_width="wrap_content"
20 android:layout_height="wrap_content"
21 android:text="@string/previous"/>
22 <Button
23 android:id="@+id/rightButton"
24 android:layout_width="wrap_content"
25 android:layout_height="wrap_content"
26 android:text="@string/next"/>
27 </LinearLayout>
28 </LinearLayout>


我們需要對這個ListView設定一個Adapter,如下:


1 package com.android.sqlite;
2
3 import android.content.Context;
4 import android.database.Cursor;
5 import android.view.LayoutInflater;
6 import android.view.View;
7 import android.view.ViewGroup;
8 import android.widget.CursorAdapter;
9 import android.widget.TextView;
10
11 import com.android.domain.Model;
12 /**
13 *
14 * @author shangzhenxiang
15 *
16 */
17 public class TestListAdapter extends CursorAdapter {
18
19 private Context mContext;
20 private Cursor mCursor;
21 private Model mModel;
22 private LayoutInflater mInflater;
23
24 public TestListAdapter(Context context, Cursor c, Model model) {
25 super(context, c);
26 System.out.println("c = " + c);
27 this.mContext = context;
28 this.mCursor = c;
29 this.mModel = model;
30 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
31 }
32
33 @Override
34 public View newView(Context context, Cursor cursor, ViewGroup parent) {
35 return mInflater.inflate(R.layout.listitem, parent, false);
36 }
37
38 @Override
39 public void bindView(View view, Context context, Cursor cursor) {
40 ViewHolder holder = null;
41
42 Object tag = view.getTag();
43 if(tag instanceof ViewHolder) {
44 holder = (ViewHolder) view.getTag();
45 }
46 if(holder == null) {
47 holder = new ViewHolder();
48 view.setTag(holder);
49 holder.title = (TextView) view.findViewById(R.id.listitemtitle);
50 }
51 //將從資料庫中查詢到的title設為ListView的Item項。
52 holder.title.setText(cursor.getString(cursor.getColumnIndexOrThrow("title")));
53 }
54
55 static class ViewHolder {
56 TextView title;
57 }
58 }


  傳進去一個Model的引數和一個Cursor。Model用於顯示每頁的個數和第幾頁,Cursor用於傳遞資料:


  在Activity中我們對Button做監聽:


  向左移的時候就將Model中的index減一,向右就加一,同時改變cursor中傳進去的Model的值,重新整理Adapter,重新整理介面,


  同時檢查Button的可用性:


1 package com.android.sqlite;
2
3 import android.app.Activity;
4 import android.database.Cursor;
5 import android.os.Bundle;
6 import android.view.View;
7 import android.view.View.OnClickListener;
8 import android.widget.Button;
9 import android.widget.ListView;
10
11 import com.android.domain.Model;
12 import com.android.service.DatabaseService;
13 /**
14 *
15 * @author shangzhenxiang
16 *
17 */
18 public class TestSqlite extends Activity implements OnClickListener {
19
20 private ListView mListView;
21 private TestListAdapter mTestListAdapter;
22 private DatabaseService mDatabaseService;
23 private Cursor mCursor;
24 private Model mModel;
25 private Button mLeftButton;
26 private Button mRightButton;
27
28 @Override
29 public void onCreate(Bundle savedInstanceState) {
30 super.onCreate(savedInstanceState);
31 setContentView(R.layout.main);
32 mListView = (ListView) findViewById(R.id.testList);
33 //建立一個DatabaseService的物件。
34 mDatabaseService = new DatabaseService(this);
35 //建立一個Model的物件,表面這是首頁,並且每頁顯示5個Item項
36 mModel = new Model(0, 5);
37 //mCursor查詢到的是第0頁的5個資料。
38 mCursor = mDatabaseService.getAllItems(mModel.getIndex()*mModel.getView_Count(), mModel.getView_Count());
39 System.out.println("mCursor = " + mCursor);
40 //根據引數建立一個TestListAdapter物件,並設給ListView。
41 mTestListAdapter = new TestListAdapter(this, mCursor, mModel);
42 mListView.setAdapter(mTestListAdapter);
43 mLeftButton = (Button) findViewById(R.id.leftButton);
44 mRightButton = (Button) findViewById(R.id.rightButton);
45 //設定Button的監聽
46 mLeftButton.setOnClickListener(this);
47 mRightButton.setOnClickListener(this);
48 checkButton();
49 }
50
51 //在Activity 銷燬的時候記得將Cursor關掉。
52 @Override
53 protected void onDestroy() {
54 // TODO Auto-generated method stub
55 super.onDestroy();
56 mCursor.close();
57 }
58
59 @Override
60 public void onClick(View v) {
61 // TODO Auto-generated method stub
62 int id = v.getId();
63 switch (id) {
64 case R.id.leftButton:
65 //頁數向前翻一頁,同時將Cursor重新查一遍,然後changeCursor,notifyDataSetChanged。
66 //檢查Button的可用性。
67 mModel.setIndex(mModel.getIndex() - 1);
68 mCursor = mDatabaseService.getAllItems(mModel.getIndex()*mModel.getView_Count(), mModel.getView_Count());
69 mTestListAdapter.changeCursor(mCursor);
70 mTestListAdapter.notifyDataSetChanged();
71 checkButton();
72 break;
73
74 //頁數向後翻一頁,同時將Cursor重新查一遍,然後changeCursor,notifyDataSetChanged。
75 //檢查Button的可用性。
76 case R.id.rightButton:
77 mModel.setIndex(mModel.getIndex() + 1);
78 mCursor = mDatabaseService.getAllItems(mModel.getIndex()*mModel.getView_Count(), mModel.getView_Count());
79 mTestListAdapter.changeCursor(mCursor);
80 mTestListAdapter.notifyDataSetChanged();
81 checkButton();
82 break;
83
84 default:
85 break;
86 }
87 }
88 /**
89 * 如果頁數小於或等於0,表示在第一頁,向左的按鈕設為不可用,向右的按鈕設為可用。
90 * 如果總數目減前幾頁的數目,得到的是當前頁的數目,如果比這一頁要顯示的少,則說明這是最後一頁,向右的按鈕不可用,向左的按鈕可用。
91 * 如果不是以上兩種情況,則說明頁數在中間,兩個按鈕都設為可用。
92 */
93 private void checkButton() {
94 if(mModel.getIndex() <= 0) {
95 mLeftButton.setEnabled(false);
96 mRightButton.setEnabled(true);
97 } else if(mDatabaseService.getCount() - mModel.getIndex()*mModel.getView_Count() <= mModel.getView_Count()) {
98 mRightButton.setEnabled(false);
99 mLeftButton.setEnabled(true);
100 } else {
101 mLeftButton.setEnabled(true);
102 mRightButton.setEnabled(true);
103 }
104 }
105 }

相關文章