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 ...
随机推荐
- inline, block, and inline-block
总体概念 block和inline这两个概念是简略的说法,完整确切的说应该是 block-level elements (块级元素) 和 inline elements (内联元素).block元素通 ...
- Div+CSS+JQuery实现选项卡,即通过点击不同的li跳转到不同的div中显示不同的内容或者执行不同的操作。
1.代码 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> ...
- log4j2.xml日志文件设置文件路径
笔者最近的项目里使用了spring,spring通过web.xml配置监听器,在web启动时web.root系统变量,以供其他变量使用,例如 在属性文件里使用${web.root}以取得完整路径,项目 ...
- Pyjwt ,python jwt ,jwt
pip install Pyjwt 不错的jwt 文章: https://www.cnblogs.com/wayneiscoming/p/7513487.html Sampleimport jwt i ...
- Vue element 分页
Vue单页面,有一个带分页的表格,表格内数据关联页码,套路如下: 代码如下: <div class="c-table-list auth-list m-bottom-20"& ...
- 炫酷MD风之dialog各种对话框
这个demo也是我从别人那里学来的,不是本人写的代码,我也是个MD初学者.把这个demo分享给看到的你,希望对你有帮助. 直接上图: demo地址:百度网盘:链接:https://pan.baidu. ...
- bottle源码
import sys __author__ = 'Marcel Hellkamp' __version__ = '0.13-dev' __license__ = 'MIT' ############# ...
- Maximum Width Ramp LT962
Given an array A of integers, a ramp is a tuple (i, j) for which i < j and A[i] <= A[j]. The ...
- node-sass 不能正常安装解决办法
web前端在安装node包时,总是报错,究其原因是node-sass没有被正常安装. 根本原因是国内网络的原因. 最终的解决方法是通过淘宝的npm镜像安装node-sass 首先安装cnpm npm ...
- 第九周助教工作总结——NWNU李泓毅
1.助教博客链接: https://www.cnblogs.com/NWNU-LHY/ 2.作业要求博客链接: https://www.cnblogs.com/nwnu-daizh/p/1072688 ...