7.数据库、Contentobserver

群组页是程序内部维护的一个数据库,其中一张表groups,用于存放创建的群组,还有一张表thread_group,用于关联群组和系统短信数据库中的会话。

数据库应该这样设计

MySqliteHelper

public class MySqliteHelper extends SQLiteOpenHelper{
 public MySqliteHelper(Context context, String name, int version) {
 super(context, name, null, version);
 }
 public static final String TABLE_GROUPS = "groups";
 public static final String TABLE_THREAD_GROUPS = "thread_groups";
 @Override
 public void onCreate(SQLiteDatabase db) {
		db.execSQL("create table groups(_id integer primary key autoincrement, group_name varchar(20));");
		db.execSQL("create table thread_groups(_id integer primary key autoincrement, group_id integer, thread_id integer);");
 }
 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 // TODO Auto-generated method stub
 }
}

DBUtils

public class DBUtils {
 /**
	 * 用于更新cursor 的URI
	 */
 private static final Uri uri = Uri.parse("content://www.itheima.com");
 private Context ctx;
 private MySqliteHelper sqlHelper;
 private DBUtils(Context ctx){
 this.ctx = ctx;
		sqlHelper = new MySqliteHelper(ctx, "heima39", 1);
 }
 private static DBUtils instance;
 public static synchronized DBUtils getInstance(Context ctx){
 if(instance == null){
			instance = new DBUtils(ctx);
 }
 return instance;
 }
 /**
	 * 创建新群组
	 * @param name 群组的名称
	 */
 public void createNewGroup(String name) {
 SQLiteDatabase db = sqlHelper.getWritableDatabase();
 ContentValues values = new ContentValues();
		values.put("group_name", name);
		db.insert(MySqliteHelper.TABLE_GROUPS, "_id", values);
		notifyCursor();
 }
 /**
	 * 查询所有的群组信息
	 * @return
	 */
 public Cursor getAllGroup() {
 SQLiteDatabase db = sqlHelper.getReadableDatabase();
 Cursor cursor = db.query(MySqliteHelper.TABLE_GROUPS, null, null, null, null, null, null);
 // android.database.sqlite.SQLiteCursor
 System.out.println(cursor);
 //为cursor 设置 通知提醒的URI 
		cursor.setNotificationUri(ctx.getContentResolver(), uri);
 return cursor;
 }
 /**
	 * 通知cursor 群组表中的内容已经发生变化
	 * @param cursor
	 */
 private void notifyCursor() {
 // 让内容处理者,根据URI 发出更新通知
		ctx.getContentResolver().notifyChange(uri, null);
 }
 /**
	 * 通过群组ID删除群组
	 * @param groupId
	 */
 public void deleteGroupById(int groupId) {
 SQLiteDatabase db = sqlHelper.getWritableDatabase();
		db.delete(MySqliteHelper.TABLE_GROUPS, " _id = "+groupId, null);
		notifyCursor();
 }
 /**
	 * 更新群组名称
	 * @param groupId 群组的ID
	 * @param name 群组的新名
	 */
 public void updateGroupById(int groupId, String name) {
 SQLiteDatabase db = sqlHelper.getWritableDatabase();
 ContentValues values = new ContentValues();
		values.put("group_name", name);
		db.update(MySqliteHelper.TABLE_GROUPS, values, " _id = "+groupId , null);
		notifyCursor();
 }
 /**
	 * 将会话ID和群组ID 插入到会话群组关系 表中
	 * @param threadId
	 * @param groupId
	 */
 public void insertThradIdAndGroupId(int threadId, int groupId) {
 SQLiteDatabase db = sqlHelper.getWritableDatabase();
 ContentValues values = new ContentValues();
		values.put("thread_id", threadId);
		values.put("group_id", groupId);
		db.insert(MySqliteHelper.TABLE_THREAD_GROUPS,null, values);
 }
 /**
	 * 返回所有的指定群组ID的会话信息
	 * @param groupId
	 * @return
	 */
 public Cursor getAllThreadIdByGroupId(int groupId) {
 SQLiteDatabase db = sqlHelper.getReadableDatabase();
 Cursor cursor = db.query(MySqliteHelper.TABLE_THREAD_GROUPS, null, " group_id = "+groupId, null, null, null, null);
 return cursor;
 }
}

在activity中不需要做任何操作,当数据库发生变化list条目也变化了,前提必须是CursorAdapter

源码:

curosr 注册监听:

* cursor.setNotificationUri(ctx.getContentResolver(), uri);

* SQLiteCursor --> AbstractWindowedCursor  --> AbstractCursor 

*  在AbstractCursor类中:

public void setNotificationUri(ContentResolver cr, Uri notifyUri) {

mNotifyUri = notifyUri;

mContentResolver = cr;

mSelfObserver = new SelfContentObserver(this);

// 将uri 和 mSelfObserver 在  mContentResolver 中注册 

mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);

}

}

发出通知:

ctx.getContentResolver().notifyChange(uri, null);

* 在 ContentResolver中发出通知:

notifyChange(uri, observer, true /* sync to network */);

*结论: 根据uri 找到 监听此URI 的Contentobserver ,即  AbstractCursor 类中的 mSelfObserver 然后,执行,mSelfObserver 中 onChange方法

* 那么 cursor 中的内容观察者执行onChange方法 时,如何刷新页面:

* CursorAdapter  init方法中为cursor注册了二个监听:

c.registerContentObserver(mChangeObserver); // 内容观察者

c.registerDataSetObserver(mDataSetObserver); // 数据观察者

* 当Contentobserver 根据URI 发送更新通知时,执行cursor的 内容观察者即:

* mChangeObserver.onChange()方法 :

   private class ChangeObserver extends ContentObserver {

public void onChange(boolean selfChange) {

onContentChanged();

}

}

* 在 onContentChanged方法 中 执行curosr.requery:

 protected void onContentChanged() {

...

mDataValid = mCursor.requery();

}

* 此时,cursor ,实际对象是 SQLiteCursor ,就执行 SQLiteCursor 中的requery方法 ,

* 在SQLiteCursor 中的requery方法中:

* 重新查询数据:

* 执行数据观察者的notify方法 :mDataSetObservable.notifyChanged();

* 即执行观察者的onChanged方法: observer.onChanged();

* CursorAdapter中已经为cursor 注册了一个数据观察者: mDataSetObserver 

* 当 mDataSetObserver 执行onChanged 方法时:

  private class MyDataSetObserver extends DataSetObserver {

public void onChanged() {

mDataValid = true;

notifyDataSetChanged(); // 刷新了listView的数据 

}


GroupUI

群组创建后,在会话页,长按某一个会话添加到群组中

public class GroupUI extends ListActivity implements OnItemLongClickListener, OnItemClickListener{
 private ListView listView;
 private Context ctx;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
		ctx = this;
		listView = getListView();
		adapter = new GropListAdapter(this, null);
		listView.setAdapter(adapter);
		listView.setOnItemLongClickListener(this);
		listView.setOnItemClickListener(this);
		prepareData();
 }
 private void prepareData() {
 DBUtils dbu = DBUtils.getInstance(ctx);
 Cursor cursor = dbu.getAllGroup();
		adapter.changeCursor(cursor);
 }
 private GropListAdapter adapter;
 class GropListAdapter extends CursorAdapter{
 public GropListAdapter(Context context, Cursor c) {
 super(context, c);
 }
 @Override
 public View newView(Context context, Cursor cursor, ViewGroup parent) {
 View view = View.inflate(context, R.layout.list_item_group, null);
 TextView name = (TextView) view.findViewById(R.id.tv_name_group);
			view.setTag(name);
 return view;
 }
 @Override
 public void bindView(View view, Context context, Cursor cursor) {
 TextView name = (TextView) view.getTag();
			name.setText(cursor.getString(cursor.getColumnIndex("group_name")));
 }
 }
 @Override
 /**
	 * 创建菜单
	 */
 public boolean onCreateOptionsMenu(Menu menu) {
 // 将 资料ID对应的文件转换为 菜单条目 ,并添加至  menu 中
		getMenuInflater().inflate(R.menu.activity_group, menu);
 return true;
 }
 @Override
 /**
	 * 响应菜单的点击事件
	 */
 public boolean onOptionsItemSelected(MenuItem item) {
 switch (item.getItemId()) {
 case R.id.menu_new_group:
			showCreateGroupDialog();
 break;
 }
 return true;
 }
 private AlertDialog dialog;
 /**
	 * 显示新建群组对话框
	 */
 private void showCreateGroupDialog() {
 AlertDialog.Builder adb =new AlertDialog.Builder(ctx);
		dialog = adb.create();
 View view = View.inflate(ctx, R.layout.dialog_new_group, null);
 final EditText etInputName = (EditText) view.findViewById(R.id.et_input_new_group);
 Button btnOk = (Button) view.findViewById(R.id.btn_ok);
		btnOk.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 String name = etInputName.getText().toString();
 if(TextUtils.isEmpty(name)){
 Toast.makeText(ctx, "请输入群组名称", 0).show();
 return ;
 }
 // 将群组名称保存至数据库
 DBUtils dbu = DBUtils.getInstance(ctx);
				dbu.createNewGroup(name);
				dialog.dismiss();
 }
 });
		dialog.setView(view,0,0,0,0);
		dialog.show();
 }
 @Override
 /**
	 * 响应listview条目的长按事件
	 */
 public boolean onItemLongClick(AdapterView<?> parent, View view,
 int position, long id) {
		showEditGroupDialog(position);
 return true;
 }
 /**
	 * 显示编辑群组对话框 
	 * @param position
	 */
 private void showEditGroupDialog(final int position) {
 AlertDialog.Builder adb = new AlertDialog.Builder(ctx);
 String items[]=new String[]{"编辑","删除"};
		adb.setItems(items, new DialogInterface.OnClickListener() {
 @Override
 /**
			 * which 是点击的条目的位置
			 */
 public void onClick(DialogInterface dialog, int which) {
 if(which == 0){ // “编辑”
					showUpdateGroupDialog(position);
 }else{ // 删除
					showConfirmDeleteDialog(position);
 }
 }
 });
		adb.show();
 }
 /**
	 * 显示确认删除的对话框
	 * @param position
	 */
 protected void showConfirmDeleteDialog(final int position) {
 AlertDialog.Builder adb = new AlertDialog.Builder(ctx);
		adb.setTitle("删除群组");
		adb.setMessage("确定要删除这个群吗?");
		adb.setNegativeButton("确定", new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 // 删除对应的群组
 DBUtils dbu = DBUtils.getInstance(ctx);
 Cursor cursor = adapter.getCursor();
				cursor.moveToPosition(position);
 int groupId = cursor.getInt(0); // 获得第0列的值,即,_id 这一列的值
				dbu.deleteGroupById(groupId);
				dialog.dismiss();
 }
 });
		adb.setPositiveButton("取消", null);
		adb.show();
 }
 /**
	 * 显示更新群组的对话框 
	 * @param position
	 */
 protected void showUpdateGroupDialog(final int position) {
 AlertDialog.Builder adb =new AlertDialog.Builder(ctx);
		dialog = adb.create();
 View view = View.inflate(ctx, R.layout.dialog_new_group, null);
 TextView title = (TextView) view.findViewById(R.id.tv_title_dialog);
		title.setText("更新群组名称");
 final EditText etInputName = (EditText) view.findViewById(R.id.et_input_new_group);
 Button btnOk = (Button) view.findViewById(R.id.btn_ok);
		btnOk.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 String name = etInputName.getText().toString();
 if(TextUtils.isEmpty(name)){
 Toast.makeText(ctx, "请输入群组名称", 0).show();
 return ;
 }
 // 将群组名称保存至数据库
 DBUtils dbu = DBUtils.getInstance(ctx);
 Cursor cursor = adapter.getCursor();
				cursor.moveToPosition(position);
 int groupId = cursor.getInt(0); // 获得群组ID
				dbu.updateGroupById(groupId,name);
				dialog.dismiss();
 }
 });
		dialog.setView(view,0,0,0,0);
		dialog.show();
 }
 @Override
 /**
	 * 响应listview条目点击事件
	 */
 public void onItemClick(AdapterView<?> parent, View view, int position,
 long id) {
 Cursor cursor = adapter.getCursor();
		cursor.moveToPosition(position);
 int groupId = cursor.getInt(0); // 返回群组ID
 DBUtils dbu =DBUtils.getInstance(ctx);
 Cursor cursor2 =  dbu.getAllThreadIdByGroupId(groupId);
 if(cursor2.getCount() == 0){ // 该群组没有人
 Toast.makeText(ctx, "该群还没有人,快回点人气吧", 0).show();
 }else{
 // 如果有人的话,希望能过cursor2 拼凑出如: thread_id in (1,2);
 String subSql = convertCursor2Str(cursor2);
 System.out.println("subSql"+subSql);
 Intent intent = new Intent(this,ConversationUI.class);
			intent.putExtra("subSql", subSql);
			startActivity(intent);
 }
 }
 /**
	 * 根据cursor中的内容,拼凑出 如   thread_id in (1,2); 的字符串
	 * @param cursor2
	 * @return
	 */
 private String convertCursor2Str(Cursor cursor) {
		cursor.moveToPosition(-1);
 StringBuilder sb=new StringBuilder("  thread_id in ( ");
 while(cursor.moveToNext()){
 String threadId = cursor.getString(cursor.getColumnIndex("thread_id"));
			sb.append(threadId+","); //  thread_id in (1,
 }
 //  thread_id in (1,2,3,4,
		sb.replace(sb.lastIndexOf(","), sb.length(), ")");
 return sb.toString();
 }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

扫码关注云+社区

领取腾讯云代金券