很久没有写东西了,一来是因为项目紧,没有多少时间,二来是因为最近越来越懒了。。。。
今天说说数据库的分页显示问题,都是些自己在项目中碰到的问题,写在这里,留作以后复习用。。。。
所谓数据库的分页显示,必须先要有一个数据库,先创建一个数据库。我这里用的是继承SQLiteOpenHelper的方法。具体如下:
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文件中做一些处理,如下所示:
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就可以生成数据库文件了,如下所示:
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的文件夹,里面就是生成的数据库文件,如下图:
数据库完成了,我们需要写一个单独的类用来显示页数和每一页上的个数,如图所示:
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 }
我们还需要一个服务来操作数据库,就是我们常说的业务逻辑层。
我们需要对数据库做什么操作,都可以写到这个类中:
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:
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,如下:
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的可用性:
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 }
代码中的注释写的比较清楚,记性不太好,留作以后复习用。
代码: