zoukankan      html  css  js  c++  java
  • 7.数据库、Contentobserver

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

    数据库应该这样设计

    MySqliteHelper 
    1. public class MySqliteHelper extends SQLiteOpenHelper{
    2. public MySqliteHelper(Context context, String name, int version) {
    3. super(context, name, null, version);
    4. }
    5. public static final String TABLE_GROUPS = "groups";
    6. public static final String TABLE_THREAD_GROUPS = "thread_groups";
    7. @Override
    8. public void onCreate(SQLiteDatabase db) {
    9. db.execSQL("create table groups(_id integer primary key autoincrement, group_name varchar(20));");
    10. db.execSQL("create table thread_groups(_id integer primary key autoincrement, group_id integer, thread_id integer);");
    11. }
    12. @Override
    13. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    14. // TODO Auto-generated method stub
    15. }
    16. }
    DBUtils 
    1. public class DBUtils {
    2. /**
    3. * 用于更新cursor 的URI
    4. */
    5. private static final Uri uri = Uri.parse("content://www.itheima.com");
    6. private Context ctx;
    7. private MySqliteHelper sqlHelper;
    8. private DBUtils(Context ctx){
    9. this.ctx = ctx;
    10. sqlHelper = new MySqliteHelper(ctx, "heima39", 1);
    11. }
    12. private static DBUtils instance;
    13. public static synchronized DBUtils getInstance(Context ctx){
    14. if(instance == null){
    15. instance = new DBUtils(ctx);
    16. }
    17. return instance;
    18. }
    19. /**
    20. * 创建新群组
    21. * @param name 群组的名称
    22. */
    23. public void createNewGroup(String name) {
    24. SQLiteDatabase db = sqlHelper.getWritableDatabase();
    25. ContentValues values = new ContentValues();
    26. values.put("group_name", name);
    27. db.insert(MySqliteHelper.TABLE_GROUPS, "_id", values);
    28. notifyCursor();
    29. }
    30. /**
    31. * 查询所有的群组信息
    32. * @return
    33. */
    34. public Cursor getAllGroup() {
    35. SQLiteDatabase db = sqlHelper.getReadableDatabase();
    36. Cursor cursor = db.query(MySqliteHelper.TABLE_GROUPS, null, null, null, null, null, null);
    37. // android.database.sqlite.SQLiteCursor
    38. System.out.println(cursor);
    39. //为cursor 设置 通知提醒的URI
    40. cursor.setNotificationUri(ctx.getContentResolver(), uri);
    41. return cursor;
    42. }
    43. /**
    44. * 通知cursor 群组表中的内容已经发生变化
    45. * @param cursor
    46. */
    47. private void notifyCursor() {
    48. // 让内容处理者,根据URI 发出更新通知
    49. ctx.getContentResolver().notifyChange(uri, null);
    50. }
    51. /**
    52. * 通过群组ID删除群组
    53. * @param groupId
    54. */
    55. public void deleteGroupById(int groupId) {
    56. SQLiteDatabase db = sqlHelper.getWritableDatabase();
    57. db.delete(MySqliteHelper.TABLE_GROUPS, " _id = "+groupId, null);
    58. notifyCursor();
    59. }
    60. /**
    61. * 更新群组名称
    62. * @param groupId 群组的ID
    63. * @param name 群组的新名
    64. */
    65. public void updateGroupById(int groupId, String name) {
    66. SQLiteDatabase db = sqlHelper.getWritableDatabase();
    67. ContentValues values = new ContentValues();
    68. values.put("group_name", name);
    69. db.update(MySqliteHelper.TABLE_GROUPS, values, " _id = "+groupId , null);
    70. notifyCursor();
    71. }
    72. /**
    73. * 将会话ID和群组ID 插入到会话群组关系 表中
    74. * @param threadId
    75. * @param groupId
    76. */
    77. public void insertThradIdAndGroupId(int threadId, int groupId) {
    78. SQLiteDatabase db = sqlHelper.getWritableDatabase();
    79. ContentValues values = new ContentValues();
    80. values.put("thread_id", threadId);
    81. values.put("group_id", groupId);
    82. db.insert(MySqliteHelper.TABLE_THREAD_GROUPS,null, values);
    83. }
    84. /**
    85. * 返回所有的指定群组ID的会话信息
    86. * @param groupId
    87. * @return
    88. */
    89. public Cursor getAllThreadIdByGroupId(int groupId) {
    90. SQLiteDatabase db = sqlHelper.getReadableDatabase();
    91. Cursor cursor = db.query(MySqliteHelper.TABLE_THREAD_GROUPS, null, " group_id = "+groupId, null, null, null, null);
    92. return cursor;
    93. }
    94. }
    在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 
    群组创建后,在会话页,长按某一个会话添加到群组中

    1. public class GroupUI extends ListActivity implements OnItemLongClickListener, OnItemClickListener{
    2. private ListView listView;
    3. private Context ctx;
    4. @Override
    5. protected void onCreate(Bundle savedInstanceState) {
    6. super.onCreate(savedInstanceState);
    7. ctx = this;
    8. listView = getListView();
    9. adapter = new GropListAdapter(this, null);
    10. listView.setAdapter(adapter);
    11. listView.setOnItemLongClickListener(this);
    12. listView.setOnItemClickListener(this);
    13. prepareData();
    14. }
    15. private void prepareData() {
    16. DBUtils dbu = DBUtils.getInstance(ctx);
    17. Cursor cursor = dbu.getAllGroup();
    18. adapter.changeCursor(cursor);
    19. }
    20. private GropListAdapter adapter;
    21. class GropListAdapter extends CursorAdapter{
    22. public GropListAdapter(Context context, Cursor c) {
    23. super(context, c);
    24. }
    25. @Override
    26. public View newView(Context context, Cursor cursor, ViewGroup parent) {
    27. View view = View.inflate(context, R.layout.list_item_group, null);
    28. TextView name = (TextView) view.findViewById(R.id.tv_name_group);
    29. view.setTag(name);
    30. return view;
    31. }
    32. @Override
    33. public void bindView(View view, Context context, Cursor cursor) {
    34. TextView name = (TextView) view.getTag();
    35. name.setText(cursor.getString(cursor.getColumnIndex("group_name")));
    36. }
    37. }
    38. @Override
    39. /**
    40. * 创建菜单
    41. */
    42. public boolean onCreateOptionsMenu(Menu menu) {
    43. // 将 资料ID对应的文件转换为 菜单条目 ,并添加至 menu 中
    44. getMenuInflater().inflate(R.menu.activity_group, menu);
    45. return true;
    46. }
    47. @Override
    48. /**
    49. * 响应菜单的点击事件
    50. */
    51. public boolean onOptionsItemSelected(MenuItem item) {
    52. switch (item.getItemId()) {
    53. case R.id.menu_new_group:
    54. showCreateGroupDialog();
    55. break;
    56. }
    57. return true;
    58. }
    59. private AlertDialog dialog;
    60. /**
    61. * 显示新建群组对话框
    62. */
    63. private void showCreateGroupDialog() {
    64. AlertDialog.Builder adb =new AlertDialog.Builder(ctx);
    65. dialog = adb.create();
    66. View view = View.inflate(ctx, R.layout.dialog_new_group, null);
    67. final EditText etInputName = (EditText) view.findViewById(R.id.et_input_new_group);
    68. Button btnOk = (Button) view.findViewById(R.id.btn_ok);
    69. btnOk.setOnClickListener(new OnClickListener() {
    70. @Override
    71. public void onClick(View v) {
    72. String name = etInputName.getText().toString();
    73. if(TextUtils.isEmpty(name)){
    74. Toast.makeText(ctx, "请输入群组名称", 0).show();
    75. return ;
    76. }
    77. // 将群组名称保存至数据库
    78. DBUtils dbu = DBUtils.getInstance(ctx);
    79. dbu.createNewGroup(name);
    80. dialog.dismiss();
    81. }
    82. });
    83. dialog.setView(view,0,0,0,0);
    84. dialog.show();
    85. }
    86. @Override
    87. /**
    88. * 响应listview条目的长按事件
    89. */
    90. public boolean onItemLongClick(AdapterView<?> parent, View view,
    91. int position, long id) {
    92. showEditGroupDialog(position);
    93. return true;
    94. }
    95. /**
    96. * 显示编辑群组对话框
    97. * @param position
    98. */
    99. private void showEditGroupDialog(final int position) {
    100. AlertDialog.Builder adb = new AlertDialog.Builder(ctx);
    101. String items[]=new String[]{"编辑","删除"};
    102. adb.setItems(items, new DialogInterface.OnClickListener() {
    103. @Override
    104. /**
    105. * which 是点击的条目的位置
    106. */
    107. public void onClick(DialogInterface dialog, int which) {
    108. if(which == 0){ // “编辑”
    109. showUpdateGroupDialog(position);
    110. }else{ // 删除
    111. showConfirmDeleteDialog(position);
    112. }
    113. }
    114. });
    115. adb.show();
    116. }
    117. /**
    118. * 显示确认删除的对话框
    119. * @param position
    120. */
    121. protected void showConfirmDeleteDialog(final int position) {
    122. AlertDialog.Builder adb = new AlertDialog.Builder(ctx);
    123. adb.setTitle("删除群组");
    124. adb.setMessage("确定要删除这个群吗?");
    125. adb.setNegativeButton("确定", new DialogInterface.OnClickListener() {
    126. @Override
    127. public void onClick(DialogInterface dialog, int which) {
    128. // 删除对应的群组
    129. DBUtils dbu = DBUtils.getInstance(ctx);
    130. Cursor cursor = adapter.getCursor();
    131. cursor.moveToPosition(position);
    132. int groupId = cursor.getInt(0); // 获得第0列的值,即,_id 这一列的值
    133. dbu.deleteGroupById(groupId);
    134. dialog.dismiss();
    135. }
    136. });
    137. adb.setPositiveButton("取消", null);
    138. adb.show();
    139. }
    140. /**
    141. * 显示更新群组的对话框
    142. * @param position
    143. */
    144. protected void showUpdateGroupDialog(final int position) {
    145. AlertDialog.Builder adb =new AlertDialog.Builder(ctx);
    146. dialog = adb.create();
    147. View view = View.inflate(ctx, R.layout.dialog_new_group, null);
    148. TextView title = (TextView) view.findViewById(R.id.tv_title_dialog);
    149. title.setText("更新群组名称");
    150. final EditText etInputName = (EditText) view.findViewById(R.id.et_input_new_group);
    151. Button btnOk = (Button) view.findViewById(R.id.btn_ok);
    152. btnOk.setOnClickListener(new OnClickListener() {
    153. @Override
    154. public void onClick(View v) {
    155. String name = etInputName.getText().toString();
    156. if(TextUtils.isEmpty(name)){
    157. Toast.makeText(ctx, "请输入群组名称", 0).show();
    158. return ;
    159. }
    160. // 将群组名称保存至数据库
    161. DBUtils dbu = DBUtils.getInstance(ctx);
    162. Cursor cursor = adapter.getCursor();
    163. cursor.moveToPosition(position);
    164. int groupId = cursor.getInt(0); // 获得群组ID
    165. dbu.updateGroupById(groupId,name);
    166. dialog.dismiss();
    167. }
    168. });
    169. dialog.setView(view,0,0,0,0);
    170. dialog.show();
    171. }
    172. @Override
    173. /**
    174. * 响应listview条目点击事件
    175. */
    176. public void onItemClick(AdapterView<?> parent, View view, int position,
    177. long id) {
    178. Cursor cursor = adapter.getCursor();
    179. cursor.moveToPosition(position);
    180. int groupId = cursor.getInt(0); // 返回群组ID
    181. DBUtils dbu =DBUtils.getInstance(ctx);
    182. Cursor cursor2 = dbu.getAllThreadIdByGroupId(groupId);
    183. if(cursor2.getCount() == 0){ // 该群组没有人
    184. Toast.makeText(ctx, "该群还没有人,快回点人气吧", 0).show();
    185. }else{
    186. // 如果有人的话,希望能过cursor2 拼凑出如: thread_id in (1,2);
    187. String subSql = convertCursor2Str(cursor2);
    188. System.out.println("subSql"+subSql);
    189. Intent intent = new Intent(this,ConversationUI.class);
    190. intent.putExtra("subSql", subSql);
    191. startActivity(intent);
    192. }
    193. }
    194. /**
    195. * 根据cursor中的内容,拼凑出 如 thread_id in (1,2); 的字符串
    196. * @param cursor2
    197. * @return
    198. */
    199. private String convertCursor2Str(Cursor cursor) {
    200. cursor.moveToPosition(-1);
    201. StringBuilder sb=new StringBuilder(" thread_id in ( ");
    202. while(cursor.moveToNext()){
    203. String threadId = cursor.getString(cursor.getColumnIndex("thread_id"));
    204. sb.append(threadId+","); // thread_id in (1,
    205. }
    206. // thread_id in (1,2,3,4,
    207. sb.replace(sb.lastIndexOf(","), sb.length(), ")");
    208. return sb.toString();
    209. }
    210. }





  • 相关阅读:
    Android 编程下 Eclipse 恢复被删除的文件
    Android 编程下背景图片适配工具类
    Android 编程下 Managing Your App's Memory
    Android 编程下代码之(QQ消息列表滑动删除)
    Android 编程下 Canvas and Drawables
    Android 编程下 AlarmManager
    Android 编程下去除 ListView 上下边界蓝色或黄色阴影
    Java 编程下字符串的 16 位、32位 MD5 加密
    C#枚举类型和int类型相互转换
    MVC和普通三层架构的区别
  • 原文地址:https://www.cnblogs.com/sixrain/p/4994973.html
Copyright © 2011-2022 走看看