3.CursorAdapter

会话页面
点击菜单时编辑的按钮显示,其余的时候gone

ConversationUI 
  1. public class ConversationUI extends Activity implements OnItemClickListener, OnClickListener{
  2. private ListView listView;
  3. private Button btnNewMessage;
  4. private Button btnSelectAll;
  5. private Button btnSelectNull;
  6. private Button btnDeleteMsg;
  7. @Override
  8. protected void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. setContentView(R.layout.activity_conversation);
  11. this.ctx = this;
  12. init();
  13. flushState();
  14. prepareData();
  15. }
  16. /**
  17. * 要查询的列
  18. */
  19. private String[] projection={
  20. "sms.body AS snippet",
  21. "sms.thread_id AS _id",//需要主键可是没有,可以起个别名
  22. "groups.msg_count AS msg_count",
  23. "address as address",
  24. "date as date"
  25. };
  26. /**
  27. * 短信内容所在列的索引值 为 0
  28. */
  29. private final int INDEX_BODY = 0;
  30. /**
  31. * 会话ID所在列的索引值 为 1
  32. */
  33. private final int INDEX_THREAD_ID = 1;
  34. /**
  35. * 短信数量所在列的索引值 为 2
  36. */
  37. private final int INDEX_MSG_COUNT = 2;
  38. /**
  39. * 短信联系人电话所在列的索引值 为 3
  40. */
  41. private final int INDEX_ADDRESS = 3;
  42. /**
  43. * 短信日期所在列的索引值 为 4
  44. */
  45. private final int INDEX_DATE = 4;
  46. /**
  47. * 给listView 准备数据
  48. */
  49. private void prepareData() {
  50. /*
  51. * 查询数据库,如果数据太多了,会造成ANR异常,所 以,一般都会开子线程,查询数据,然后,用handler将结果,回传
  52. */
  53. MyQueryHandler queryHandler = new MyQueryHandler(getContentResolver());
  54. queryHandler.startQuery(234, adapter, MyConstants.URI_CONVERSATION, projection, null, null, " date desc");//按日期倒序查询
  55. }
  56. private void init() {
  57. btnNewMessage = (Button) findViewById(R.id.btn_new_message_conversation);
  58. btnSelectAll = (Button) findViewById(R.id.btn_select_all_conversation);
  59. btnSelectNull = (Button) findViewById(R.id.btn_select_null_conversation);
  60. btnDeleteMsg = (Button) findViewById(R.id.btn_delete_message_conversation);
  61. btnNewMessage.setOnClickListener(this);
  62. btnSelectAll.setOnClickListener(this);
  63. btnSelectNull.setOnClickListener(this);
  64. btnDeleteMsg.setOnClickListener(this);
  65. listView = (ListView) findViewById(R.id.lv_conversation);
  66. adapter = new MyListAdapter(this, null);//可以先传个null
  67. listView.setAdapter(adapter);
  68. listView.setOnItemClickListener(this);
  69. selectItemSet = new HashSet<Integer>();//删除时选中的集合
  70. }
  71. private boolean isEditState = false;
  72. private void flushState() {
  73. if(isEditState){//编辑状态
  74. btnNewMessage.setVisibility(View.GONE);
  75. btnSelectAll.setVisibility(View.VISIBLE);
  76. btnSelectNull.setVisibility(View.VISIBLE);
  77. btnDeleteMsg.setVisibility(View.VISIBLE);
  78. }else{//非编辑状态
  79. btnNewMessage.setVisibility(View.VISIBLE);
  80. btnSelectAll.setVisibility(View.GONE);
  81. btnSelectNull.setVisibility(View.GONE);
  82. btnDeleteMsg.setVisibility(View.GONE);
  83. }
  84. //判断listview 的条目是否有被选中,如果没有被选中的,btnSelectNull 和 btnDeleteMsg 应该处于不可用的状态 否则,是可用的状态
  85. if(selectItemSet.size()==0){// listview条目没有被选择
  86. btnSelectNull.setEnabled(false);
  87. btnDeleteMsg.setEnabled(false);
  88. }else{
  89. btnSelectNull.setEnabled(true);
  90. btnDeleteMsg.setEnabled(true);
  91. }
  92. // 根据 selectItemSet 集合当中的内容数量,改变 全选按钮的状态
  93. // 判断 selectItemSet 的size 和listView的条目数量,是否相同,如果相同,全选按钮,就不可用。
  94. if(selectItemSet.size() == adapter.getCount()){
  95. btnSelectAll.setEnabled(false);
  96. }else{
  97. // 否则,是可用的
  98. btnSelectAll.setEnabled(true);
  99. }
  100. }
  101. private MyListAdapter adapter ;
  102. public Context ctx;
  103. class MyListAdapter extends CursorAdapter{
  104. public MyListAdapter(Context context, Cursor c) {
  105. super(context, c);
  106. }
  107. @Override
  108. /**
  109. * 当 conterView是null时,需要用户创建view 的时候调
  110. */
  111. public View newView(Context context, Cursor cursor, ViewGroup parent) {
  112. View view = View.inflate(ctx, R.layout.list_item_conversation,null);
  113. ViewHolder vh = new ViewHolder();
  114. vh.checkbox = (ImageView) view.findViewById(R.id.iv_checkbox_list_item);
  115. vh.face = (ImageView) view.findViewById(R.id.iv_face_list_item);
  116. vh.address = (TextView) view.findViewById(R.id.tv_address_list_item);
  117. vh.body = (TextView) view.findViewById(R.id.tv_body_list_item);
  118. vh.date = (TextView) view.findViewById(R.id.tv_date_list_item);
  119. view.setTag(vh);
  120. return view;
  121. }
  122. @Override
  123. /**
  124. * 为itemview设置内容时调用
  125. * view 即 newView 方法的返回值
  126. */
  127. public void bindView(View view, Context context, Cursor cursor) {
  128. ViewHolder vh = (ViewHolder) view.getTag();
  129. //显示短信内容
  130. vh.body.setText(cursor.getString(INDEX_BODY));
  131. //显示日期:
  132. long when = cursor.getLong(INDEX_DATE);
  133. String dateStr;
  134. //使用系统工具类,判断是否是今天
  135. if(DateUtils.isToday(when)){
  136. dateStr = DateFormat.getTimeFormat(ctx).format(when);
  137. }else{
  138. dateStr = DateFormat.getDateFormat(ctx).format(when);
  139. }
  140. vh.date.setText(dateStr);
  141. //显示联系人地址:
  142. String number = cursor.getString(INDEX_ADDRESS);
  143. int msgcount = cursor.getInt(INDEX_MSG_COUNT);// 获得短信的数量
  144. String name = Tools.findNameByNumber(ctx, number);
  145. if(name == null){//表明无此联系人
  146. vh.address.setText(number+"("+msgcount+")");
  147. }else{
  148. vh.address.setText(name+"("+msgcount+")");
  149. }
  150. //显示联系人的头像:
  151. // 根据电话号码,查询联系人ID
  152. int contactId = Tools.findIDByNumber(ctx, number);
  153. // 如果 ID = -1 表明,无此联系人,此时,应设置一个 未知的联系人头像
  154. if(contactId == -1){
  155. vh.face.setBackgroundResource(R.drawable.ic_unknow_contact_picture);
  156. }else{
  157. // 根据ID 获得联系人头像,
  158. Bitmap bitmap = Tools.getFaceById(ctx, ""+contactId);
  159. //如果 bitmpa == null 表明,此联系人,无头像,应设置,一个联系人的默认的头像
  160. if(bitmap == null){
  161. vh.face.setBackgroundResource(R.drawable.ic_contact_picture);
  162. }else{
  163. //否则,将bitmap 设置为联系人的头像
  164. vh.face.setBackgroundDrawable(new BitmapDrawable(bitmap));
  165. }
  166. }
  167. /*
  168. * 设置 checkBox
  169. */
  170. //如果是编辑状态,显示checkBox,
  171. if(isEditState){
  172. vh.checkbox.setVisibility(View.VISIBLE);
  173. // 该条目对应的会话ID
  174. int threadId = cursor.getInt(INDEX_THREAD_ID);
  175. //判断集合当中,是否有该条目对应的会话ID,如果有,表示是选中状态,如果没有,是没选中状态。
  176. if(selectItemSet.contains(threadId)){
  177. vh.checkbox.setEnabled(true);
  178. }else{
  179. vh.checkbox.setEnabled(false);
  180. }
  181. }else{
  182. //否则,隐藏
  183. vh.checkbox.setVisibility(View.GONE);
  184. }
  185. }
  186. }
  187. /**
  188. * 存储在编辑状态下,选中的listView的条目
  189. */
  190. private HashSet<Integer> selectItemSet;
  191. class ViewHolder{
  192. public ImageView checkbox;
  193. public ImageView face;
  194. public TextView address;
  195. public TextView body;
  196. public TextView date;
  197. }
  198. @Override
  199. /**
  200. * 第一次点击menu按键时,调用,用于创建菜单选 项
  201. */
  202. public boolean onCreateOptionsMenu(Menu menu) {
  203. menu.add(0, ID_SEARCH, 0, "搜索");
  204. menu.add(0, ID_EDIT, 0, "编辑");
  205. menu.add(0, ID_CANCEL_EDIT, 0, "取消编辑");
  206. return true;
  207. }
  208. private final int ID_SEARCH=100;
  209. private final int ID_EDIT=101;
  210. private final int ID_CANCEL_EDIT=102;
  211. @Override
  212. /**
  213. * 每次按menu按键的时候,调用,做一些准备工作
  214. */
  215. public boolean onPrepareOptionsMenu(Menu menu) {
  216. if(isEditState){//如果是编辑状态
  217. menu.findItem(ID_EDIT).setVisible(false);
  218. menu.findItem(ID_SEARCH).setVisible(false);
  219. menu.findItem(ID_CANCEL_EDIT).setVisible(true);
  220. }else{
  221. menu.findItem(ID_EDIT).setVisible(true);
  222. menu.findItem(ID_SEARCH).setVisible(true);
  223. menu.findItem(ID_CANCEL_EDIT).setVisible(false);
  224. }
  225. return true;
  226. }
  227. @Override
  228. /**
  229. * 当选择某一个菜单时,调用
  230. */
  231. public boolean onOptionsItemSelected(MenuItem item) {
  232. switch (item.getItemId()) {
  233. case ID_SEARCH:
  234. break;
  235. case ID_EDIT: // 编辑菜单
  236. isEditState = true;
  237. flushState();
  238. break;
  239. case ID_CANCEL_EDIT: //取消编辑
  240. isEditState = false;
  241. //清空集合
  242. selectItemSet.clear();
  243. flushState();
  244. break;
  245. }
  246. return true;
  247. }
  248. @Override
  249. /**
  250. * 响应listview的条目点击事件
  251. */
  252. public void onItemClick(AdapterView<?> parent, View view, int position,
  253. long id) {
  254. //通过adapter 获得cursor
  255. Cursor cursor = adapter.getCursor();
  256. //将cursor移动到对应的位置
  257. cursor.moveToPosition(position);
  258. //取得该位置对应的会话ID
  259. int threadId = cursor.getInt(INDEX_THREAD_ID);
  260. if (isEditState) {
  261. // 判断 集合中是否有该会话ID,如果有,就删除,如果没有,就添加
  262. if (selectItemSet.contains(threadId)) {
  263. selectItemSet.remove(threadId);
  264. } else {
  265. selectItemSet.add(threadId);
  266. }
  267. //刷新listview
  268. adapter.notifyDataSetChanged();
  269. //刷新按钮状态
  270. flushState();
  271. }else{
  272. String address = cursor.getString(INDEX_ADDRESS);
  273. Intent intent = new Intent(this,ConversationDetail.class);
  274. intent.putExtra("address", address);// 将当前条目对应的联系人电话号码,传递给会话详情页面
  275. startActivity(intent);
  276. }
  277. }
  278. @Override
  279. /**
  280. * 响应按钮的点击事件
  281. * @param v
  282. */
  283. public void onClick(View v) {
  284. switch (v.getId()) {
  285. case R.id.btn_delete_message_conversation:
  286. //显示确认删除的对话框
  287. showConfirmDeleteDialog();
  288. break;
  289. case R.id.btn_new_message_conversation:
  290. // 点击新建信息按钮时,响应
  291. Intent intent = new Intent(this,NewMessageUI.class);
  292. startActivity(intent);
  293. break;
  294. case R.id.btn_select_all_conversation: // 全选按钮
  295. Cursor cursor = adapter.getCursor();
  296. cursor.moveToPosition(-1);
  297. while(cursor.moveToNext()){
  298. int threadId = cursor.getInt(INDEX_THREAD_ID);
  299. selectItemSet.add(threadId); // set集合的特点:无序,不可重置,如果添加的内容之前已经有了,会覆盖。
  300. }
  301. //刷新listview
  302. adapter.notifyDataSetChanged();
  303. // 刷新状态
  304. flushState();
  305. break;
  306. case R.id.btn_select_null_conversation: // 取消选择的按钮
  307. //清空集合
  308. selectItemSet.clear();
  309. //刷新listview
  310. adapter.notifyDataSetChanged();
  311. // 刷新状态
  312. flushState();
  313. break;
  314. }
  315. }
  316. /**
  317. * 显示确认删除的对话框
  318. */
  319. private void showConfirmDeleteDialog() {
  320. AlertDialog.Builder adb = new AlertDialog.Builder(this);
  321. adb.setTitle("清除短信");
  322. adb.setMessage("确认删除这些回忆吗?");
  323. adb.setNegativeButton("确认", new DialogInterface.OnClickListener() {
  324. @Override
  325. public void onClick(DialogInterface dialog, int which) {
  326. // 开子线程,删除短信,
  327. new Thread(new DeleteMsgRunnable()).start();
  328. // 显示删除短信的进度对话框
  329. showDeleteProgressDialog();
  330. }
  331. });
  332. adb.setPositiveButton("取消", null);
  333. adb.show();
  334. }
  335. private ProgressDialog proDlg;
  336. /**
  337. * 显示删除短信的进度对话框
  338. */
  339. protected void showDeleteProgressDialog() {
  340. proDlg =new ProgressDialog(this);
  341. proDlg.setTitle("正在删除短信");
  342. //设置 进度框 为水平显示的样式,
  343. proDlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
  344. // 设置进度条的最大值 = 集合的大小。
  345. proDlg.setMax(selectItemSet.size());
  346. proDlg.setButton("取消", new DialogInterface.OnClickListener() {
  347. @Override
  348. public void onClick(DialogInterface dialog, int which) {
  349. isCancelDeleteMsg = true;
  350. }
  351. });
  352. // 给进度框添加,关闭时的回调 ,监听,监听的代码,会在UI线程中执行
  353. proDlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
  354. @Override
  355. public void onDismiss(DialogInterface dialog) {
  356. isEditState = false;
  357. flushState();// 刷新页面状态
  358. System.out.println(selectItemSet);
  359. adapter.notifyDataSetChanged();// 刷新listview
  360. System.out.println("222::"+selectItemSet);
  361. }
  362. });
  363. proDlg.show();
  364. }
  365. /**
  366. * 判断是否取消删除短信
  367. */
  368. private boolean isCancelDeleteMsg;
  369. class DeleteMsgRunnable implements Runnable{
  370. @Override
  371. public void run() {
  372. // 遍历 selectItemSet 集合,根据会话ID,删除短信
  373. for(Integer threadId : selectItemSet ){ // 用增强for循环 遍历 set集合
  374. SystemClock.sleep(1000); // 会为显示效果正好,在此休眠一秒,
  375. if(isCancelDeleteMsg){
  376. break; // 跳出 for 循环
  377. }
  378. Tools.deleteMsgByThreadId(ctx,threadId);
  379. proDlg.incrementProgressBy(1);//让 proDlg 的水平进度条,增加刻度
  380. }
  381. // 清空集合
  382. selectItemSet.clear();// 清空集合
  383. //关闭进度框
  384. proDlg.dismiss();
  385. // 将 isCancelDeleteMsg 复原
  386. isCancelDeleteMsg = false;
  387. // flushState();// 在子线程中不能更新UI
  388. }
  389. }
  390. }






posted @ 2015-11-25 15:20  梦和远方  阅读(201)  评论(0编辑  收藏  举报