3.CursorAdapter
会话页面




public class ConversationUI extends Activity implements OnItemClickListener, OnClickListener{private ListView listView;private Button btnNewMessage;private Button btnSelectAll;private Button btnSelectNull;private Button btnDeleteMsg;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_conversation);this.ctx = this;init();flushState();prepareData();}/*** 要查询的列*/private String[] projection={"sms.body AS snippet","sms.thread_id AS _id",//需要主键可是没有,可以起个别名"groups.msg_count AS msg_count","address as address","date as date"};/*** 短信内容所在列的索引值 为 0*/private final int INDEX_BODY = 0;/*** 会话ID所在列的索引值 为 1*/private final int INDEX_THREAD_ID = 1;/*** 短信数量所在列的索引值 为 2*/private final int INDEX_MSG_COUNT = 2;/*** 短信联系人电话所在列的索引值 为 3*/private final int INDEX_ADDRESS = 3;/*** 短信日期所在列的索引值 为 4*/private final int INDEX_DATE = 4;/*** 给listView 准备数据*/private void prepareData() {/** 查询数据库,如果数据太多了,会造成ANR异常,所 以,一般都会开子线程,查询数据,然后,用handler将结果,回传*/MyQueryHandler queryHandler = new MyQueryHandler(getContentResolver());queryHandler.startQuery(234, adapter, MyConstants.URI_CONVERSATION, projection, null, null, " date desc");//按日期倒序查询}private void init() {btnNewMessage = (Button) findViewById(R.id.btn_new_message_conversation);btnSelectAll = (Button) findViewById(R.id.btn_select_all_conversation);btnSelectNull = (Button) findViewById(R.id.btn_select_null_conversation);btnDeleteMsg = (Button) findViewById(R.id.btn_delete_message_conversation);btnNewMessage.setOnClickListener(this);btnSelectAll.setOnClickListener(this);btnSelectNull.setOnClickListener(this);btnDeleteMsg.setOnClickListener(this);listView = (ListView) findViewById(R.id.lv_conversation);adapter = new MyListAdapter(this, null);//可以先传个nulllistView.setAdapter(adapter);listView.setOnItemClickListener(this);selectItemSet = new HashSet<Integer>();//删除时选中的集合}private boolean isEditState = false;private void flushState() {if(isEditState){//编辑状态btnNewMessage.setVisibility(View.GONE);btnSelectAll.setVisibility(View.VISIBLE);btnSelectNull.setVisibility(View.VISIBLE);btnDeleteMsg.setVisibility(View.VISIBLE);}else{//非编辑状态btnNewMessage.setVisibility(View.VISIBLE);btnSelectAll.setVisibility(View.GONE);btnSelectNull.setVisibility(View.GONE);btnDeleteMsg.setVisibility(View.GONE);}//判断listview 的条目是否有被选中,如果没有被选中的,btnSelectNull 和 btnDeleteMsg 应该处于不可用的状态 否则,是可用的状态if(selectItemSet.size()==0){// listview条目没有被选择btnSelectNull.setEnabled(false);btnDeleteMsg.setEnabled(false);}else{btnSelectNull.setEnabled(true);btnDeleteMsg.setEnabled(true);}// 根据 selectItemSet 集合当中的内容数量,改变 全选按钮的状态// 判断 selectItemSet 的size 和listView的条目数量,是否相同,如果相同,全选按钮,就不可用。if(selectItemSet.size() == adapter.getCount()){btnSelectAll.setEnabled(false);}else{// 否则,是可用的btnSelectAll.setEnabled(true);}}private MyListAdapter adapter ;public Context ctx;class MyListAdapter extends CursorAdapter{public MyListAdapter(Context context, Cursor c) {super(context, c);}@Override/*** 当 conterView是null时,需要用户创建view 的时候调*/public View newView(Context context, Cursor cursor, ViewGroup parent) {View view = View.inflate(ctx, R.layout.list_item_conversation,null);ViewHolder vh = new ViewHolder();vh.checkbox = (ImageView) view.findViewById(R.id.iv_checkbox_list_item);vh.face = (ImageView) view.findViewById(R.id.iv_face_list_item);vh.address = (TextView) view.findViewById(R.id.tv_address_list_item);vh.body = (TextView) view.findViewById(R.id.tv_body_list_item);vh.date = (TextView) view.findViewById(R.id.tv_date_list_item);view.setTag(vh);return view;}@Override/*** 为itemview设置内容时调用* view 即 newView 方法的返回值*/public void bindView(View view, Context context, Cursor cursor) {ViewHolder vh = (ViewHolder) view.getTag();//显示短信内容vh.body.setText(cursor.getString(INDEX_BODY));//显示日期:long when = cursor.getLong(INDEX_DATE);String dateStr;//使用系统工具类,判断是否是今天if(DateUtils.isToday(when)){dateStr = DateFormat.getTimeFormat(ctx).format(when);}else{dateStr = DateFormat.getDateFormat(ctx).format(when);}vh.date.setText(dateStr);//显示联系人地址:String number = cursor.getString(INDEX_ADDRESS);int msgcount = cursor.getInt(INDEX_MSG_COUNT);// 获得短信的数量String name = Tools.findNameByNumber(ctx, number);if(name == null){//表明无此联系人vh.address.setText(number+"("+msgcount+")");}else{vh.address.setText(name+"("+msgcount+")");}//显示联系人的头像:// 根据电话号码,查询联系人IDint contactId = Tools.findIDByNumber(ctx, number);// 如果 ID = -1 表明,无此联系人,此时,应设置一个 未知的联系人头像if(contactId == -1){vh.face.setBackgroundResource(R.drawable.ic_unknow_contact_picture);}else{// 根据ID 获得联系人头像,Bitmap bitmap = Tools.getFaceById(ctx, ""+contactId);//如果 bitmpa == null 表明,此联系人,无头像,应设置,一个联系人的默认的头像if(bitmap == null){vh.face.setBackgroundResource(R.drawable.ic_contact_picture);}else{//否则,将bitmap 设置为联系人的头像vh.face.setBackgroundDrawable(new BitmapDrawable(bitmap));}}/** 设置 checkBox*///如果是编辑状态,显示checkBox,if(isEditState){vh.checkbox.setVisibility(View.VISIBLE);// 该条目对应的会话IDint threadId = cursor.getInt(INDEX_THREAD_ID);//判断集合当中,是否有该条目对应的会话ID,如果有,表示是选中状态,如果没有,是没选中状态。if(selectItemSet.contains(threadId)){vh.checkbox.setEnabled(true);}else{vh.checkbox.setEnabled(false);}}else{//否则,隐藏vh.checkbox.setVisibility(View.GONE);}}}/*** 存储在编辑状态下,选中的listView的条目*/private HashSet<Integer> selectItemSet;class ViewHolder{public ImageView checkbox;public ImageView face;public TextView address;public TextView body;public TextView date;}@Override/*** 第一次点击menu按键时,调用,用于创建菜单选 项*/public boolean onCreateOptionsMenu(Menu menu) {menu.add(0, ID_SEARCH, 0, "搜索");menu.add(0, ID_EDIT, 0, "编辑");menu.add(0, ID_CANCEL_EDIT, 0, "取消编辑");return true;}private final int ID_SEARCH=100;private final int ID_EDIT=101;private final int ID_CANCEL_EDIT=102;@Override/*** 每次按menu按键的时候,调用,做一些准备工作*/public boolean onPrepareOptionsMenu(Menu menu) {if(isEditState){//如果是编辑状态menu.findItem(ID_EDIT).setVisible(false);menu.findItem(ID_SEARCH).setVisible(false);menu.findItem(ID_CANCEL_EDIT).setVisible(true);}else{menu.findItem(ID_EDIT).setVisible(true);menu.findItem(ID_SEARCH).setVisible(true);menu.findItem(ID_CANCEL_EDIT).setVisible(false);}return true;}@Override/*** 当选择某一个菜单时,调用*/public boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case ID_SEARCH:break;case ID_EDIT: // 编辑菜单isEditState = true;flushState();break;case ID_CANCEL_EDIT: //取消编辑isEditState = false;//清空集合selectItemSet.clear();flushState();break;}return true;}@Override/*** 响应listview的条目点击事件*/public void onItemClick(AdapterView<?> parent, View view, int position,long id) {//通过adapter 获得cursorCursor cursor = adapter.getCursor();//将cursor移动到对应的位置cursor.moveToPosition(position);//取得该位置对应的会话IDint threadId = cursor.getInt(INDEX_THREAD_ID);if (isEditState) {// 判断 集合中是否有该会话ID,如果有,就删除,如果没有,就添加if (selectItemSet.contains(threadId)) {selectItemSet.remove(threadId);} else {selectItemSet.add(threadId);}//刷新listviewadapter.notifyDataSetChanged();//刷新按钮状态flushState();}else{String address = cursor.getString(INDEX_ADDRESS);Intent intent = new Intent(this,ConversationDetail.class);intent.putExtra("address", address);// 将当前条目对应的联系人电话号码,传递给会话详情页面startActivity(intent);}}@Override/*** 响应按钮的点击事件* @param v*/public void onClick(View v) {switch (v.getId()) {case R.id.btn_delete_message_conversation://显示确认删除的对话框showConfirmDeleteDialog();break;case R.id.btn_new_message_conversation:// 点击新建信息按钮时,响应Intent intent = new Intent(this,NewMessageUI.class);startActivity(intent);break;case R.id.btn_select_all_conversation: // 全选按钮Cursor cursor = adapter.getCursor();cursor.moveToPosition(-1);while(cursor.moveToNext()){int threadId = cursor.getInt(INDEX_THREAD_ID);selectItemSet.add(threadId); // set集合的特点:无序,不可重置,如果添加的内容之前已经有了,会覆盖。}//刷新listviewadapter.notifyDataSetChanged();// 刷新状态flushState();break;case R.id.btn_select_null_conversation: // 取消选择的按钮//清空集合selectItemSet.clear();//刷新listviewadapter.notifyDataSetChanged();// 刷新状态flushState();break;}}/*** 显示确认删除的对话框*/private void showConfirmDeleteDialog() {AlertDialog.Builder adb = new AlertDialog.Builder(this);adb.setTitle("清除短信");adb.setMessage("确认删除这些回忆吗?");adb.setNegativeButton("确认", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {// 开子线程,删除短信,new Thread(new DeleteMsgRunnable()).start();// 显示删除短信的进度对话框showDeleteProgressDialog();}});adb.setPositiveButton("取消", null);adb.show();}private ProgressDialog proDlg;/*** 显示删除短信的进度对话框*/protected void showDeleteProgressDialog() {proDlg =new ProgressDialog(this);proDlg.setTitle("正在删除短信");//设置 进度框 为水平显示的样式,proDlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 设置进度条的最大值 = 集合的大小。proDlg.setMax(selectItemSet.size());proDlg.setButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {isCancelDeleteMsg = true;}});// 给进度框添加,关闭时的回调 ,监听,监听的代码,会在UI线程中执行proDlg.setOnDismissListener(new DialogInterface.OnDismissListener() {@Overridepublic void onDismiss(DialogInterface dialog) {isEditState = false;flushState();// 刷新页面状态System.out.println(selectItemSet);adapter.notifyDataSetChanged();// 刷新listviewSystem.out.println("222::"+selectItemSet);}});proDlg.show();}/*** 判断是否取消删除短信*/private boolean isCancelDeleteMsg;class DeleteMsgRunnable implements Runnable{@Overridepublic void run() {// 遍历 selectItemSet 集合,根据会话ID,删除短信for(Integer threadId : selectItemSet ){ // 用增强for循环 遍历 set集合SystemClock.sleep(1000); // 会为显示效果正好,在此休眠一秒,if(isCancelDeleteMsg){break; // 跳出 for 循环}Tools.deleteMsgByThreadId(ctx,threadId);proDlg.incrementProgressBy(1);//让 proDlg 的水平进度条,增加刻度}// 清空集合selectItemSet.clear();// 清空集合//关闭进度框proDlg.dismiss();// 将 isCancelDeleteMsg 复原isCancelDeleteMsg = false;// flushState();// 在子线程中不能更新UI}}}
3.CursorAdapter的更多相关文章
- 在VFP6中模拟CursorAdapter的功能
这个是我在2002年做的一个VFP程序中实现的方法, 现在看来功能和VFP8,9中的CursorAdapter非常相似, 因为属性设置有许多相同的地方,我甚至怀疑CA就是就是在这样的基础上再包装出来的 ...
- AsyncQueryHandler 和 CursorAdapter的使用
AsyncQueryHandler A helper class to help make handling asynchronous ContentResolver queries easier. ...
- Android CursorAdapter
CursorAdapter 继承于BaseAdapter是个虚类,它为cursor和ListView提供了连接的桥梁. public abstract class Cur ...
- AutoCompleteTextView和自定义的CursorAdapter
用雅虎天气接口和AutoCompleteTextView开发天气应用(1) 2014/03/20 | 分类: ANDROID, 开发 | 2 条评论 | 标签: 天气, 安卓开发 分享到:5 jQue ...
- Android开发——利用Cursor+CursorAdapter实现界面实时更新
好久没有更新博客了.不是没时间写,而是太懒.而且感觉有些东西没有时间总结,之之后再想写,就想不起来了.晚上新发现一点东西,所以就及时写下来. 最近利用业余时间在看Android的Download模块, ...
- ContentProvider和Cursor以及CursorAdapter三者之间内部链接实现原理 解析
最近 在学习Android3.0中推出的 Loader 机制,其中CursorLoader 这个加载器说是可以实时监测数据和更新数据,为了一探究竟,就连带的将 ContentProvider和Curs ...
- 【Android】13.2 使用自定义的CursorAdapter访问SQLite数据库
分类:C#.Android.VS2015: 创建日期:2016-02-26 一.简介 SQliteDemo1的例子演示了SimpleCursorAdapter的用法,本节我们将使用用途更广的自定义的游 ...
- CursorAdapter中getView newView bindView异同
Adapter的作用是界面与数据之间的桥梁,通过设置适配器至ListView控件后(如调用ListView的 setAdapter(ListAdapter adapter) ...
- Android如果动态改变CursorAdapter Item个数
//adapter内部类 private class SearchAdapter extends CursorAdapter { @Override public View newView(Conte ...
随机推荐
- 推荐几个可以从google play(谷歌应用商店)直接下载原版APP的网站
http://apk-dl.com/ https://apkpure.com/ http://apk-downloaders.com
- 4.7做作业时发现,内联元素设置宽高背景以后正常不显示,但是设置了position:absolute;以后就可以显示了。起到了和display:block;一样的效果。然后查了一下知道了。
如果内联元素定位属性设置为:absolate,元素脱离文档,即使a元素中没有内容,设置的背景依然会显示!
- python、java读数据
python从txt文档中读数据有个特别神奇的函数 可以把txt文档中的数据直接读取成python数组 java用Scanner类读数据比较方便
- 微信小程序云端解决方案探索之路 - GITC 主题演讲
转自:https://github.com/tencentyun/blog/issues/1 在刚结束的全球互联网技术大会(GITC)里面,我在前端专场给大家分享了「微信小程序云端解决方案探索之路」, ...
- CentOSmini安装gcc8.2
一. 如果遇到类似问题: configure: error: in `/usr/local/src/gcc-8.2.0/temp': configure: error: no acceptable C ...
- java 判断null和空
判断null和空 org.apache.commons.lang3 if(StringUtils.isBlank(valuationMeasureUnitName)){ }
- 旅游类App的原型制作分享-Klook
Klook是一款旅游类App,它能探索和预订惊人的旅行活动.在世界各地以最优惠的价格畅玩. 这款原型中,用到了Mockplus的两种滚动方式,一种是把手机外壳拉长,另一种是使用滚动区组件,其中,滚动区 ...
- Quartz错过任务执行时间的处理机制(Misfire处理规则 )
调度(scheduleJob)或恢复调度(resumeTrigger,resumeJob)后不同的misfire对应的处理规则 CronTrigger withMisfireHandlingInstr ...
- Navicat Premium 修改MySQL密码(忘记密码的情况下)
Navicat Premium 修改MySQL密码 1,首先,Navicat Premium还能够连接MySQL. 2,选择数据库,右键单击,选择“命令行模式...”,下图示例 3,打开命令行模式, ...
- C++ STL库的总结以及实现原理
STL的容器可以分为以下几个大类:一:序列容器, 有vector, list, deque, string. 二 : 关联容器, 有set, multiset, map, mulmap has ...