很久没有写东西了,一来是因为项目紧,没有多少时间,二来是因为最近越来越懒了。。。。 今天说说数据库的分页显示问题,都是些自己在项目中碰到的问题,写在这里,留作以后复习用。。。。 所谓数据库的分页显示,必须先要有一个数据库,先创建一个数据库。我这里用的是继承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 }
代码中的注释写的比较清楚,记性不太好,留作以后复习用。