CursorAdpter的使用

关于adapter 经常使用的是BaseApapter

而对于要在数据库中获取数据显示出来 我们要用CursorAdpter(当数据发生变化 能自动刷新数据)

class ContactAdapter extends CursorAdapter {
public ContactAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return View.inflate(context, R.layout.contact_item, null);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {

}
@Override
public CharSequence convertToString(Cursor cursor) {
// TODO Auto-generated method stub
return super.convertToString(cursor);
}

}

}

这里有三个方法

1.newView 

2.bindView

3.convertToString

关于newView  bindView 

public abstract class CursorAdapter extends BaseAdapter implements Filterable,

可以看到CursorAdapter  继承于BaseAdapter 

我们知道BaseAdapter 在是调用getView 和getCount方法来生成view的

来看看CursorAdapter 

 public View getView(int position, View convertView, ViewGroup parent) {
        if (!mDataValid) {
            throw new IllegalStateException("this should only be called when the cursor is valid");
        }
        if (!mCursor.moveToPosition(position)) {
            throw new IllegalStateException("couldn't move cursor to position " + position);
        }
        View v;
        if (convertView == null) {
            v = newView(mContext, mCursor, parent);
        } else {
            v = convertView;
        }
        bindView(v, mContext, mCursor);

        return v;
    }

可以看到在CursorAdapter 的getview方法中调用了newView()和bindView()方法

这里的getView方法中已经对其做出了优化

而我们可以对齐进一步优化 原理与baseAdpter优化原理相同 都是通过一个holder对象来减少findviewbyid的次数

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
ConversationDetailHolderView mHolder = new ConversationDetailHolderView();
View view = View.inflate(context, R.layout.conversation_detail_item, null);

view.setTag(mHolder);
return view;
}


@Override
public void bindView(View view, Context context, Cursor cursor) {
ConversationDetailHolderView mHolder = (ConversationDetailHolderView) view.getTag();

}

public class ConversationDetailHolderView {

}


再来看convertToString()方法

在工作中我们经常会碰到需求 就是在输入框有自动提示的功能

这里我们通过AutoCompleteTextView来实现 

这个view相当于listview和editview的结合体

我们可以为其.setAdapter() 就像listview一样

而通常自动提示是去本地数据库查询数据 也就用到CursorAdapter

//在输入时 去数据库查询

mAdapter.setFilterQueryProvider(new FilterQueryProvider() {
/**
* 当自动提示文本框开始过滤查询时回调
* @param constraint 自动提示文本框输入的内容
*/
@Override
public Cursor runQuery(CharSequence constraint) {
// 根据constraint字段查询联系人的数据, 返回cursor
Cursor cursor = getContentResolver().query(Phone.CONTENT_URI, 
projection, selection, selectionArgs, null);
return cursor;
}
});

当出现提示框时 我们想要点击提示框 来返回所需要的数据 如电话号码

这时就要用到convertToString()方法 来返回所需数据

//当点击提示框时 回调该方法

//@return 返回所需数据

//@param cursor 当前点击项对应的cursor

@Override
public CharSequence convertToString(Cursor cursor) {
return super.convertToString(cursor);
}



对于CursorAdapter 因为涉及到数据库查找 所以不要放在主线程中查找

这里提供一个类AsyncQueryHandler 来实现子线程查询数据库操作

CommonAsyncQuery mAdapter = new ConversationDetailAdapter(this,null);//因为cursor的获得在子线程中 所以这里先传入null 
CommonAsyncQuery asyncQuery = new CommonAsyncQuery(getContentResolver());

asyncQuery.startQuery(0, mAdapter, Sms.CONVERSATION_URI, projection, null, null, "date desc");
//mAdapter传入进去 让AsyncQueryHandler 来更新adapter!!

public class CommonAsyncQuery extends AsyncQueryHandler{


private static final String TAG = "CommonAsyncQuery";

//自定义的监视器 当完成查询操作时调用onPreNotify方法来执行一些操作

//模仿AsyncTask
private OnQueryNotifyCompleteListener mOnQueryNotifyCompleteListener;


public CommonAsyncQuery(ContentResolver cr) {
super(cr);
}


/**
* 当数据库数据发生变化时 会自动调用
* 当调用startQuery开始异步查询数据时, 查询完毕后查询出来的游标结果集cursor会传递到此方法

* 执行在主线程中(更新数据)
* @param token startQuery传进来的token (对应startQuery的第一个参数)
* @param cookie startQuery传进来的cookie(CursorAdapter)  对应startQuery的第二个参数
* @param cursor 查询出来的最新结果集
*/
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
//Log.i(TAG, "onQueryComplete is calling : token = " + token + ", cookie = " + cookie);


// 在刷新之前, 让用户做一些准备操作
if(mOnQueryNotifyCompleteListener != null) {
mOnQueryNotifyCompleteListener.onPreNotify(token, cookie, cursor);
}

// 刷新数据
if(cookie != null) {
notifyAdapter((CursorAdapter) cookie, cursor);
}

// 通知用户刷新完成, 用户可以操作一些事情
if(mOnQueryNotifyCompleteListener != null) {
mOnQueryNotifyCompleteListener.onPostNotify(token, cookie, cursor);
}
}

/**
* 更新数据
* @param adapter
* @param cursor
*/
private void notifyAdapter(CursorAdapter adapter, Cursor cursor) {
// 给adapter刷新数据, 类似BaseAdapter中的notifyDataSetchange
adapter.changeCursor(cursor);//内部调用了notifyDataSetchange来更新数据
}
}




CursorAdapter自动刷新过程:

//Notify registered observers that a row was updated. To register, call registerContentObserver(). By default,CursorAdapter objects will get this notification.


ContentResolver().notifyChange()        会被CursorAdapter接收到 而CursorAdapter中注册了一个ContentObserver

所以当notifyChange()时 会调用ContentObserver.onChange()方法

-> ChangeObserver.onChange


-> CursorAdapter.onContentChanged  关键步骤: 此方法会调用cursor.reQuery方法查询最新的结果


-> DataSetObserver.onChanged     当查询出数据发生变化 会调用此方法


-> BaseAdapter.notifyDataSetChanged 开始刷新数据



总结:

1.通过notifyChange通知内容观察者 内容已发生变化

2.内容观察者 调用CursorAdapter.onContentChanged()方法 来处理(cursor.reQuery重新查询数据库)

3. 当发现数据库数据发生变化时 响应DataSetObserver.onChanged()方法 默认执行BaseAdapter.notifyDataSetChanged刷新数据

观察者模式的应用 


由此可知 provider中必须当数据库内容发生变化时 必须调用notifyChange()方法

 否则CursorAdapter不会自动刷新数据





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值