上次讲的Android上的SQLite分页读取,只用文本框显示数据而已,这次就讲得深入一些,实现并封装一个SQL分页表格控件,不仅支持分页还是以表格的形式展示数据。先来看看本文程序运行的动画:
这个SQL分页表格控件主要分为“表格区”和“分页栏”这两部分,这两部分都是基于GridView实现的。网上介绍Android上实现表格的DEMO一般都用ListView。ListView与GridView对比,ListView最大的优势是格单元的大小可以自定义,可以某单元长某单元短,但是难于实现自适应数据表的结构;而GridView最大的优势就是自适应数据表的结构,但是格单元统一大小。。。对于数据表结构多变的情况,建议使用GridView实现表格。
本文实现的SQL分页表格控件有以下特点:
1、自适应数据表结构,但是格单元统一大小。
2、支持分页。
3、“表格区”有按键事件回调处理,“分页栏”有分页切换事件回调处理。
本文程序代码较多,可以到这里下载整个工程的源码:testSQLite.rar
items.xml的代码如下,它是“表格区”和“分页栏”的格单元实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
android:id
=
"@+id/LinearLayout01"
android:layout_width
=
"fill_parent"
android:background
=
"#555555"
android:layout_height
=
"wrap_content"
>
<
TextView
android:id
=
"@+id/ItemText"
android:layout_below
=
"@+id/ItemImage"
android:text
=
"TextView01"
android:bufferType
=
"normal"
android:singleLine
=
"true"
android:background
=
"#000000"
android:layout_width
=
"fill_parent"
android:layout_height
=
"wrap_content"
android:gravity
=
"center"
android:layout_margin
=
"1dip"
android:layout_gravity
=
"center"
/>
</
LinearLayout
>
|
main.xml的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
android:orientation
=
"vertical"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:id
=
"@+id/MainLinearLayout"
>
<
Button
android:id
=
"@+id/btnCreateDB"
android:layout_height
=
"wrap_content"
android:layout_width
=
"fill_parent"
android:text
=
"创建数据库"
/>
<
Button
android:id
=
"@+id/btnInsertRec"
android:layout_height
=
"wrap_content"
android:layout_width
=
"fill_parent"
android:text
=
"插入一串实验数据"
/>
<
Button
android:id
=
"@+id/btnClose"
android:layout_width
=
"fill_parent"
android:layout_height
=
"wrap_content"
android:text
=
"关闭数据库"
/>
</
LinearLayout
>
|
演示程序testSQLite.java的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
package
com.testSQLite;
import
android.app.Activity;
import
android.database.Cursor;
import
android.database.SQLException;
import
android.database.sqlite.SQLiteDatabase;
import
android.os.Bundle;
import
android.util.Log;
import
android.view.View;
import
android.widget.Button;
import
android.widget.LinearLayout;
import
android.widget.Toast;
public
class
testSQLite
extends
Activity {
GVTable table;
Button btnCreateDB, btnInsert, btnClose;
SQLiteDatabase db;
int
id;
// 添加记录时的id累加标记,必须全局
private
static
final
String TABLE_NAME =
"stu"
;
private
static
final
String ID =
"id"
;
private
static
final
String NAME =
"name"
;
private
static
final
String PHONE =
"phone"
;
private
static
final
String ADDRESS =
"address"
;
private
static
final
String AGE =
"age"
;
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnCreateDB = (Button)
this
.findViewById(R.id.btnCreateDB);
btnCreateDB.setOnClickListener(
new
ClickEvent());
btnInsert = (Button)
this
.findViewById(R.id.btnInsertRec);
btnInsert.setOnClickListener(
new
ClickEvent());
btnClose = (Button)
this
.findViewById(R.id.btnClose);
btnClose.setOnClickListener(
new
ClickEvent());
table =
new
GVTable(
this
);
table.gvSetTableRowCount(
8
);
// 设置每个分页的ROW总数
LinearLayout ly = (LinearLayout) findViewById(R.id.MainLinearLayout);
table.setTableOnClickListener(
new
GVTable.OnTableClickListener() {
@Override
public
void
onTableClickListener(
int
x,
int
y, Cursor c) {
c.moveToPosition(y);
String str = c.getString(x) +
" 位置:("
+ String.valueOf(x) +
","
+ String.valueOf(y) +
")"
;
Toast.makeText(testSQLite.
this
, str,
1000
).show();
}
});
table.setOnPageSwitchListener(
new
GVTable.OnPageSwitchListener() {
@Override
public
void
onPageSwitchListener(
int
pageID,
int
pageCount) {
String str =
"共有"
+ String.valueOf(pageCount) +
" 当前第"
+ String.valueOf(pageID) +
"页"
;
Toast.makeText(testSQLite.
this
, str,
1000
).show();
}
});
ly.addView(table);
}
class
ClickEvent
implements
View.OnClickListener {
@Override
public
void
onClick(View v) {
if
(v == btnCreateDB) {
CreateDB();
}
else
if
(v == btnInsert) {
InsertRecord(
16
);
// 插入16条记录
table.gvUpdatePageBar(
"select count(*) from "
+ TABLE_NAME, db);
table.gvReadyTable(
"select * from "
+ TABLE_NAME, db);
}
else
if
(v == btnClose) {
table.gvRemoveAll();
db.close();
}
}
}
/**
* 在内存创建数据库和数据表
*/
void
CreateDB() {
// 在内存创建数据库
db = SQLiteDatabase.create(
null
);
Log.e(
"DB Path"
, db.getPath());
String amount = String.valueOf(databaseList().length);
Log.e(
"DB amount"
, amount);
// 创建数据表
String sql =
"CREATE TABLE "
+ TABLE_NAME +
" ("
+ ID
+
" text not null, "
+ NAME +
" text not null,"
+ ADDRESS
+
" text not null, "
+ PHONE +
" text not null,"
+ AGE
+
" text not null "
+
");"
;
try
{
db.execSQL(
"DROP TABLE IF EXISTS "
+ TABLE_NAME);
db.execSQL(sql);
}
catch
(SQLException e) {
}
}
/**
* 插入N条数据
*/
void
InsertRecord(
int
n) {
int
total = id + n;
for
(; id < total; id++) {
String sql =
"insert into "
+ TABLE_NAME +
" ("
+ ID +
", "
+ NAME
+
", "
+ ADDRESS +
", "
+ PHONE +
", "
+ AGE +
") values('"
+ String.valueOf(id)
+
"', 'man','address','123456789','18');"
;
try
{
db.execSQL(sql);
}
catch
(SQLException e) {
}
}
}
}
|
分页表格控件GVTable.java的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
package
com.testSQLite;
import
java.util.ArrayList;
import
java.util.HashMap;
import
android.content.Context;
import
android.database.Cursor;
import
android.database.sqlite.SQLiteDatabase;
import
android.view.View;
import
android.widget.AdapterView;
import
android.widget.GridView;
import
android.widget.LinearLayout;
import
android.widget.SimpleAdapter;
import
android.widget.AdapterView.OnItemClickListener;
public
class
GVTable
extends
LinearLayout {
protected
GridView gvTable, gvPage;
protected
SimpleAdapter saPageID, saTable;
// 适配器
protected
ArrayList<HashMap<String, String>> srcPageID, srcTable;
// 数据源
protected
int
TableRowCount =
10
;
// 分页时,每页的Row总数
protected
int
TableColCount =
0
;
// 每页col的数量
protected
SQLiteDatabase db;
protected
String rawSQL =
""
;
protected
Cursor curTable;
// 分页时使用的Cursor
protected
OnTableClickListener clickListener;
// 整个分页控件被点击时的回调函数
protected
OnPageSwitchListener switchListener;
// 分页切换时的回调函数
public
GVTable(Context context) {
super
(context);
this
.setOrientation(VERTICAL);
// 垂直
// ----------------------------------------
gvTable =
new
GridView(context);
addView(gvTable,
new
LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
// 宽长式样
srcTable =
new
ArrayList<HashMap<String, String>>();
saTable =
new
SimpleAdapter(context, srcTable,
// 数据来源
R.layout.items,
// XML实现
new
String[] {
"ItemText"
},
// 动态数组与ImageItem对应的子项
new
int
[] { R.id.ItemText });
// 添加并且显示
gvTable.setAdapter(saTable);
gvTable.setOnItemClickListener(
new
OnItemClickListener() {
@Override
public
void
onItemClick(AdapterView<?> arg0, View arg1,
int
arg2,
long
arg3) {
int
y = arg2 / curTable.getColumnCount() -
1
;
// 标题栏的不算
int
x = arg2 % curTable.getColumnCount();
if
(clickListener !=
null
// 分页数据被点击
&& y != -
1
) {
// 点中的不是标题栏时
clickListener.onTableClickListener(x, y, curTable);
}
}
});
// ----------------------------------------
gvPage =
new
GridView(context);
gvPage.setColumnWidth(
40
);
// 设置每个分页按钮的宽度
gvPage.setNumColumns(GridView.AUTO_FIT);
// 分页按钮数量自动设置
addView(gvPage,
new
LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
// 宽长式样
srcPageID =
new
ArrayList<HashMap<String, String>>();
saPageID =
new
SimpleAdapter(context, srcPageID,
// 数据来源
R.layout.items,
// XML实现
new
String[] {
"ItemText"
},
// 动态数组与ImageItem对应的子项
new
int
[] { R.id.ItemText });
// 添加并且显示
gvPage.setAdapter(saPageID);
// 添加消息处理
gvPage.setOnItemClickListener(
new
OnItemClickListener() {
@Override
public
void
onItemClick(AdapterView<?> arg0, View arg1,
int
arg2,
long
arg3) {
LoadTable(arg2);
// 根据所选分页读取对应的数据
if
(switchListener !=
null
) {
// 分页切换时
switchListener.onPageSwitchListener(arg2, srcPageID.size());
}
}
});
}
/**
* 清除所有数据
*/
public
void
gvRemoveAll() {
if
(
this
.curTable !=
null
)
curTable.close();
srcTable.clear();
saTable.notifyDataSetChanged();
srcPageID.clear();
saPageID.notifyDataSetChanged();
}
/**
* 读取指定ID的分页数据,返回当前页的总数据 SQL:Select * From TABLE_NAME Limit 9 Offset 10;
* 表示从TABLE_NAME表获取数据,跳过10行,取9行
*
* @param pageID
* 指定的分页ID
*/
protected
void
LoadTable(
int
pageID) {
if
(curTable !=
null
)
// 释放上次的数据
curTable.close();
String sql = rawSQL +
" Limit "
+ String.valueOf(TableRowCount)
+
" Offset "
+ String.valueOf(pageID * TableRowCount);
curTable = db.rawQuery(sql,
null
);
gvTable.setNumColumns(curTable.getColumnCount());
// 表现为表格的关键点!
TableColCount = curTable.getColumnCount();
srcTable.clear();
// 取得字段名称
int
colCount = curTable.getColumnCount();
for
(
int
i =
0
; i < colCount; i++) {
HashMap<String, String> map =
new
HashMap<String, String>();
map.put(
"ItemText"
, curTable.getColumnName(i));
srcTable.add(map);
}
// 列举出所有数据
int
recCount = curTable.getCount();
for
(
int
i =
0
; i < recCount; i++) {
// 定位到一条数据
curTable.moveToPosition(i);
for
(
int
ii =
0
; ii < colCount; ii++)
// 定位到一条数据中的每个字段
{
HashMap<String, String> map =
new
HashMap<String, String>();
map.put(
"ItemText"
, curTable.getString(ii));
srcTable.add(map);
}
}
saTable.notifyDataSetChanged();
}
/**
* 设置表格的最多显示的行数
*
* @param row
* 表格的行数
*/
public
void
gvSetTableRowCount(
int
row) {
TableRowCount = row;
}
/**
* 取得表格的最大行数
*
* @return 行数
*/
public
int
gvGetTableRowCount() {
return
TableRowCount;
}
/**
* 取得当前分页的Cursor
*
* @return 当前分页的Cursor
*/
public
Cursor gvGetCurrentTable() {
return
curTable;
}
/**
* 准备分页显示数据
*
* @param rawSQL
* sql语句
* @param db
* 数据库
*/
public
void
gvReadyTable(String rawSQL, SQLiteDatabase db) {
this
.rawSQL = rawSQL;
this
.db = db;
}
/**
* 刷新分页栏,更新按钮数量
*
* @param sql
* SQL语句
* @param db
* 数据库
*/
public
void
gvUpdatePageBar(String sql, SQLiteDatabase db) {
Cursor rec = db.rawQuery(sql,
null
);
rec.moveToLast();
long
recSize = rec.getLong(
0
);
// 取得总数
rec.close();
int
pageNum = (
int
) (recSize / TableRowCount) +
1
;
// 取得分页数
srcPageID.clear();
for
(
int
i =
0
; i < pageNum; i++) {
HashMap<String, String> map =
new
HashMap<String, String>();
map.put(
"ItemText"
,
"No."
+ String.valueOf(i));
// 添加图像资源的ID
srcPageID.add(map);
}
saPageID.notifyDataSetChanged();
}
// ---------------------------------------------------------
/**
* 表格被点击时的回调函数
*/
public
void
setTableOnClickListener(OnTableClickListener click) {
this
.clickListener = click;
}
public
interface
OnTableClickListener {
public
void
onTableClickListener(
int
x,
int
y, Cursor c);
}
// ---------------------------------------------------------
/**
* 分页栏被点击时的回调函数
*/
public
void
setOnPageSwitchListener(OnPageSwitchListener pageSwitch) {
this
.switchListener = pageSwitch;
}
public
interface
OnPageSwitchListener {
public
void
onPageSwitchListener(
int
pageID,
int
pageCount);
}
}
|