【发布时间】:2017-09-02 21:16:17
【问题描述】:
关于如何在同一个活动中显示两个不同的列表视图中的光标结果有什么想法吗?一个例子来自 Whatsapp,他们有(我假设)一个“聊天”表和“消息”表。一旦我们在工具栏上键入关键字,我将查询两个表并在 1 个活动中显示在两个不同的列表视图中。有没有办法做到这一点?还是它们仅显示在 1 个列表视图中?请指教。
谢谢。
【问题讨论】:
关于如何在同一个活动中显示两个不同的列表视图中的光标结果有什么想法吗?一个例子来自 Whatsapp,他们有(我假设)一个“聊天”表和“消息”表。一旦我们在工具栏上键入关键字,我将查询两个表并在 1 个活动中显示在两个不同的列表视图中。有没有办法做到这一点?还是它们仅显示在 1 个列表视图中?请指教。
谢谢。
【问题讨论】:
是的,这可以做到。为了以简单的方式模拟上述内容,假设数据库有两个表聊天和消息。它们都有两列一个唯一标识符和一个文本列。
使用 SQLiteOpenHelper 的子类,我们可以有一个名为 DBHlpr.java 的文件:-
public class DBHlpr extends SQLiteOpenHelper {
static final String DBNAME = "mydb";
static final String CHATTABLE = "chats";
static final String MSGTABLE = "messages";
static final String TEXTCOL = "textdata";
static final String IDCOL = "_id";
DBHlpr(Context context) {
super(context,DBNAME,null,1);
}
public void onCreate(SQLiteDatabase db){
db.execSQL("CREATE TABLE " + CHATTABLE + " (" + IDCOL + " INTEGER PRIMARY KEY, " + TEXTCOL + " TEXT)");
db.execSQL("CREATE TABLE " + MSGTABLE + " (" + IDCOL + " INTEGER PRIMARY KEY, " + TEXTCOL + " TEXT)");
}
public void onUpgrade(SQLiteDatabase db, int oldversion, int newversion) {
}
public void insertRow(String table, String text) {
ContentValues cv = new ContentValues();
cv.put(TEXTCOL,text);
long id = this.getWritableDatabase().insert(table,null,cv);
Log.d("DBHLP-INSRT","Added row with ID=" + Long.toString(id));
}
public Cursor getRows(String table, String srchstr) {
SQLiteDatabase db = getWritableDatabase();
String whereclause = null;
if (srchstr.length() > 0) {
whereclause = TEXTCOL + " LIKE '%" + srchstr + "%' ";
}
return db.query(
table,
null,whereclause,null,null,null,null);
}
}
onCreate 方法将创建 2 个表,即 chats 和 messages(根据 CHATTABLE 和 MSGTABLE)。
onUpgrade is required but does nothing as yet.
insertRow 可用于向任一表添加一行(因为它们具有相同的结构)。请注意,它将写入日志,以便可以轻松地确认插入。
getRows 用于获取包含数据的光标(来自数据库的数据)。同样,这一种方法可用于两个表。它传递一个字符串(如果它的长度大于 0)来过滤表(根据在搜索字段中输入的数据)。
活动需要一个指定两个 ListView 的布局,在这种情况下它将是 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.so45787986.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Search" />
<EditText
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Chats" />
<ListView
android:id="@+id/chats"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</ListView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Messages" />
<ListView
android:id="@+id/messages"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</ListView>
</LinearLayout>
没有什么特别的,这是一个非常简单的布局,一个 EditText 作为搜索条件,一个 TextView 作为聊天列表的标题(以下 ListView),然后是另一个 TextView 和 ListView 用于消息。
MainActivity.java 可以是:-
public class MainActivity extends AppCompatActivity {
DBHlpr dbhlpr = new DBHlpr(this);
Cursor chatcursor;
Cursor msgcursor;
TextWatcher tx;
EditText search;
ListView chatlist;
ListView msglist;
SimpleCursorAdapter chat_sca;
SimpleCursorAdapter msg_sca;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
search = (EditText) findViewById(R.id.search);
chatlist = (ListView) findViewById(R.id.chats);
msglist = (ListView) findViewById(R.id.messages);
// Add some data for testing
dbhlpr.insertRow(DBHlpr.CHATTABLE, "This is my first chat");
dbhlpr.insertRow(DBHlpr.CHATTABLE, "This is my second chat");
dbhlpr.insertRow(DBHlpr.CHATTABLE, "This is my third chat");
dbhlpr.insertRow(DBHlpr.MSGTABLE, "First Message");
dbhlpr.insertRow(DBHlpr.MSGTABLE, "Second Message");
dbhlpr.insertRow(DBHlpr.MSGTABLE, "Third Message");
chatcursor = dbhlpr.getRows(DBHlpr.CHATTABLE,"");
chat_sca = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_1,
chatcursor,
new String[]{DBHlpr.TEXTCOL},
new int[]{android.R.id.text1},
0
);
chatlist.setAdapter(chat_sca);
msgcursor = dbhlpr.getRows(DBHlpr.MSGTABLE,"");
msg_sca = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_1,
msgcursor,
new String[]{DBHlpr.TEXTCOL},
new int[]{android.R.id.text1},
0
);
msglist.setAdapter(msg_sca);
search.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
refreshCursors();
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
private void refreshCursors() {
chatcursor = dbhlpr.getRows(DBHlpr.CHATTABLE,search.getText().toString());
chat_sca.swapCursor(chatcursor);
msgcursor = dbhlpr.getRows(DBHlpr.MSGTABLE,search.getText().toString());
msg_sca.swapCursor(msgcursor);
}
@Override
public void onDestroy() {
super.onDestroy();
chatcursor.close();
msgcursor.close();
}
}
首先定义了一些类变量:-
DBHlpr dbhlpr = new DBHlpr(this);
Cursor chatcursor;
Cursor msgcursor;
与数据库相关。第一个创建 DBHlpr 的实例,另外两个用于 2 个游标(聊天和消息)。
TextWatcher tx;
EditText search;
ListView chatlist;
ListView msglist;
用于处理视图。 TextWatcher 用于检测搜索的变化。
SimpleCursorAdapter chat_sca;
SimpleCursorAdapter msg_sca;
用于使数据库数据适应 ListViews。顾名思义,这些非常基本,但可以用于演示目的。
onCreate 的前 5 行非常标准。
接下来的 6 行基本相同,即 dbhlpr.insertRow(DBHlpr.CHATTABLE, "This is my first chat"); 并调用 insertRow 方法,传递相应的表和要存储的数据。应该注意的是,第一次运行的时间是创建数据库的时间。请注意,这些行的存在只是为了提供一些测试数据。
然后我们来(注意后面的代码基本上是重复的,只是针对消息表):-
chatcursor = dbhlpr.getRows(DBHlpr.CHATTABLE,"");
chat_sca = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_1,
chatcursor,
new String[]{DBHlpr.TEXTCOL},
new int[]{android.R.id.text1},
0
);
chatlist.setAdapter(chat_sca);
第一行获取一个带有相应数据的光标(所有聊天行,根据第二个参数)。 第 2-9 行是设置简单光标适配器的单个命令(第 1 个参数是上下文,第 2 个要使用的布局(我们作弊并使用一个简单的),第 3 个是保存数据的光标,第 4 个是要获取光标中数据的列,第 5 列是要放置数据的视图 ID,第 6 列应为 0)。 最后一行告诉 ListView 使用适配器。
在此之后,TextWatcher 被添加到搜索中。这里使用了 onTextChanged 方法,它调用了refreshCursors 方法。
refreshCursors 方法使用更改后的搜索数据从数据库中获取数据,并将其放入现有游标中,然后通过swapCursor 告诉适配器数据已更改。
最后onDestroy方法用于在Activity即将结束时关闭游标。
最初运行时:-
在搜索字段中输入 f 后:-
【讨论】: