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 ...
随机推荐
- nginx访问502 gateway,*1 connect() failed (111: Connection refused) while connecting to upstream
安装好nginx,php环境后,配置虚拟主机,结果访问后就报502 gateway,查看日志文件后,显示错误如下: 2019/04/29 16:24:39 [error] 19433#19433: * ...
- nginx 添加response响应头
硬添
- Gitlab的安装
# GitLab Server 的搭建 参考 https://about.gitlab.com/installation ## 1. 准备工作 以Centos7为例,准备一台至少内存为4G的机器. # ...
- Spring Boot 异常处理
Spring Boot 异常处理 本节介绍一下 Spring Boot 启动时是如何处理异常的?核心类是 SpringBootExceptionReporter 和 SpringBootExcepti ...
- PPS--在download DN出现的问题注意:
1,DN的下载条件:(没有删除没有下载) PPSL=’N’(PPSL有两个值,N时是指这个DN还没有下载) DEL_FLAG<>’Y’(DEL_FLAG有两个值,Y时说明已经删除,不会下载 ...
- 移动APP测试入手点
- java中的 java.util.concurrent.locks.ReentrantLock类中的lockInterruptibly()方法介绍
在java的 java.util.concurrent.locks包中,ReentrantLock类实现了lock接口,lock接口用于加锁和解锁限制,加锁后必须释放锁,其他的线程才能进入到里面执行, ...
- python中print不换行
python中的print打印的结果总是进行了换行,如果不想换行显示可以在print中添加“end ='' ” 一般print显示: for i in range(3): print(i) #显示结果 ...
- PHP常用180函数总结【初学者必看】
数学函数 1.abs(): 求绝对值 <span style="font-size: 14px;">$abs = abs(-4.2); //4.2<br>& ...
- 第七周助教工作总结——NWNU李泓毅
本周应批改作业0,实批改作业0 因本周开始软工团队项目,故本周几位助教正在制定团队项目题目并且处理相关工作. 这一次的作业将于4月17日前进行提交,作业为软件研发团队的组建.