Android使用之CursorAdapter
CursorAdapter使用说明
运用场景
主要用于在ListView或者GridView等中动态显示数据库中创建的数据,功能与AdapterView相似。
CursorAdapter具体实现步骤
实现步骤
- 创建XML文件用于将来Item显示样式
- 新建Class创建其相应的构造函数
- 继承CursorAdapter并重写相应的子方法
- 创建对应Activity的XML文件实现相应的显示控件
- 在Activity中实现LoaderManager.LoaderCallbacks获得该Content中的Cursor,用于将来Adapter的数据读取
- 在Activity中的相应控件中载入Adapter
1.1 Item显示样式
在Layout文件夹下创建一个XML文件用于实现将来在ListView中的Item需要显示的样式。这些并定义将来需要更改数据的id。
代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="10"
android:orientation="vertical">
<!--显示第一行-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/the_first_line">
<!--用于显示编号-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/display_number"
android:layout_weight="1">
<TextView
style="@style/DisplayItemBriefText"
android:text="编号:" />
<TextView
style="@style/DisplayItemBriefText"
android:id="@+id/number_text_view"
android:text="223" />
</LinearLayout>
<!--显示体重-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/display_weight"
android:layout_toRightOf="@+id/display_number"
android:layout_weight="1">
<TextView
style="@style/DisplayItemBriefText"
android:text="体重:"
/>
<TextView
style="@style/DisplayItemBriefText"
android:text="20"
android:id="@+id/weight_text_view"/>
<TextView
style="@style/DisplayItemBriefText"
android:text="Kg" />
</LinearLayout>
</LinearLayout>
<!--显示第二行-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/the_second_line">
<!--用于显示品种-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/display_breed"
android:layout_weight="1">
<TextView
style="@style/DisplayItemBriefText"
android:text="品种:" />
<TextView
style="@style/DisplayItemBriefText"
android:id="@+id/breed_text_view"
android:text="家猪" />
</LinearLayout>
<!--显示吃食次数-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/display_eat_times"
android:layout_weight="1">
<TextView
style="@style/DisplayItemBriefText"
android:text="吃食次数:" />
<TextView
style="@style/DisplayItemBriefText"
android:text="2"
android:id="@+id/eat_times_text_view"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<ImageView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/ic_keyboard_arrow_right_black_48dp"
android:layout_gravity="center"/>
</LinearLayout>
XML结果
1.2 创建Class
构造方法
public BriefInformationAdapter(Context context, Cursor cursor)
创建该构造方法是为了将来在Activity中实现的时候能够将curosr中的数据传输进该Adapter,即其中的cursor就包含了需要的所有数据
代码
public class BriefInformationAdapter extends CursorAdapter {
/**
* 构造函数{@link BriefInformationAdapter}
* @param context 显示的环境
* @param cursor 显示的数据
*/
public BriefInformationAdapter(Context context, Cursor cursor){
super(context,cursor,0/*flag*/);
}
}
1.3 在Class中继承CurosrAdapter
重写子方法
继承CurosrAdapter后需要重写两个方法,分别是:
- public View newView(Context context, Cursor cursor, ViewGroup parent)
- public void bindView(View view, Context context, Cursor cursor)
newView方法用于实现创建新的View,将前文创建的Item样式在这里扩展显示。
bindView方法用于实现在新创建的View中将数据库中对应的数据显示到对应的id控件上。
代码
/**
*用于适配显示在{@link EditPetInformationActivity}中的宠物的简略信息
*/
public class BriefInformationAdapter extends CursorAdapter {
/**
* 构造函数{@link BriefInformationAdapter}
* @param context 显示的环境
* @param cursor 显示的数据
*/
public BriefInformationAdapter(Context context, Cursor cursor){
super(context,cursor,0/*flag*/);
}
/**
* 创建一个新的View用于显示
* @param context 显示环境
* @param cursor 从中获取显示的数据
* @param parent 新的View是依附在那个环境中
* @return 返回新的listView
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
/**膨胀显示的item的样式display_item**/
return LayoutInflater.from(context).inflate(R.layout.display_item,parent,false);
}
/**
* 用于将cursor中的数据匹配到相对应的标签中
* @param view newView方法中创建的view
* @param context 显示环境
* @param cursor 从该cursor中提取数据
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
/**
* 确定需要显示的TextView
*/
TextView numberTextView=(TextView) view.findViewById(R.id.number_text_view);
TextView breedTextView=(TextView) view.findViewById(R.id.breed_text_view);
TextView weightTextView=(TextView) view.findViewById(R.id.weight_text_view);
TextView eatTimesTextView=(TextView) view.findViewById(R.id.eat_times_text_view);
/**
* 找到各个内容的列标签
*/
int numberColumnIndex=cursor.getColumnIndex(PetInforamtionDatabase.COLUMN_PET_INIT_NUMBER);
int breedColumnIndex=cursor.getColumnIndex(PetInforamtionDatabase.COLUMN_PET_BRRED);
int weightColumnIndex=cursor.getColumnIndex(PetInforamtionDatabase.COLUMN_PET_WEIGHT);
int eatTimesColumnIndex=cursor.getColumnIndex(PetInforamtionDatabase.COLUMN_PET_EAT_TIMES);
/**
*读取对应标签的信息
*/
int number=cursor.getInt(numberColumnIndex);
String breed=cursor.getString(breedColumnIndex);
int weight=cursor.getInt(weightColumnIndex);
int eatTimes=cursor.getInt(eatTimesColumnIndex);
/**
* 设置显示Cursor中读取的内容
*/
numberTextView.setText(String.valueOf(number));
breedTextView.setText(breed);
weightTextView.setText(String.valueOf(weight));
eatTimesTextView.setText(String.valueOf(eatTimes));
}
}
1.4 Activity对应的显示控件
显示控件
这里采用的是ListView用于显示。
代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.android.kimhlo.smartfeed.ui.EditPetInformationActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/brief_information_list_view">
</ListView>
<!--当没有ListView没有内容显示的时候,显示如下内容-->
<RelativeLayout
android:id="@+id/brief_empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/empty_information"
android:gravity="center"
android:text="没有宠物信息,请加入宠物。"
android:textSize="20sp"
android:textColor="#A2AAB0"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/empty_information"
android:text="点击右下角的浮动按钮添加"
android:textSize="20sp"
android:textColor="#A2AAB0"/>
</RelativeLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/add_Pet_floating_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
app:srcCompat="@drawable/ic_add_white_24dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_marginEnd="30dp"
android:layout_marginBottom="30dp"/>
</RelativeLayout>
XML结果
1.5 在Activity中实现LoaderManager.LoaderCallbacks
实现该接口主要为了获得在content下对应projection的cursor,用于Adapter的创建。采用Loader的原因在于不必每次旋转屏幕的时候重新执行onCreate的时候都重新创建新的Curosr从而防止内存泄露等各种问题。
实现该接口就必须要实现三个子方法:
- public Loader onCreateLoader(int id, Bundle args)
- public void onLoadFinished(Loader loader, Cursor data)
- public void onLoaderReset(Loader loader)
其中,onCreateLoader方法用于检测是否需要创建新的Loader,即不会每次都去创建新的curosr。onLoadFinished方法是当创建完成后的操作,有数据更改后用新的Cursor去更新BriefInformationAdapter。onLoaderReset是Loader重置后的操作,当数据需要被删除的时候回调该函数。
在onCreate函数中通过getLoaderManager().initLoader(PET_LOADER,null,this)来初始化Loader,PET_LOADER是该Loader的标号。(实现在1.6中代码部分见)
代码
//创建Loader
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
//在cursor中需要显示的信息
String[] projection ={
PetInforamtionDatabase._ID,
PetInforamtionDatabase.COLUMN_PET_INIT_NUMBER,
PetInforamtionDatabase.COLUMN_PET_WEIGHT,
PetInforamtionDatabase.COLUMN_PET_HEAD_TEMPERATURE,
PetInforamtionDatabase.COLUMN_PET_BODY_TEMPERATURE,
PetInforamtionDatabase.COLUMN_PET_EAT_TIMES,
PetInforamtionDatabase.COLUMN_PET_BRRED
};
//Loader将会在后台执行ContentProvider的query方法
return new CursorLoader(
this,//显示该信息的环境就是该Activity
PetInforamtionDatabase.CONTENT_URI,//查询的地址
projection,//查询的信息内容
null,//没有选择的条件
null,//没有选择的条件值
null//默认的方式排序
);
}
//载入Loader完成后
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
//用新的Cursor去更新{@link BriefInformationAdapter}
mCursorAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
//当数据需要被删除的时候回掉
mCursorAdapter.swapCursor(null);
}
1.6 在Activity中载入Adapter
相应控件载入Adapter
在对应的Activity中的onCreate函数中确定相应的显示控件,这里采用的是该Activity的XML中对应的ListView控件。找到相应的控件后用setAadapter方法设置实例化后的Adapter就可以完成显示
代码
public class EditPetInformationActivity extends AppCompatActivity
implements LoaderManager.LoaderCallbacks<Cursor>{
/**该Activity的Loader的编号**/
private static final int PET_LOADER=0;
/**ListView对应的适配器**/
BriefInformationAdapter mCursorAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_pet_information);
//设置浮动按钮的触发Activity
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.add_Pet_floating_button);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent addPet=new Intent(EditPetInformationActivity.this,AddPetActivity.class);
startActivity(addPet);
}
});
//确定显示用来显示宠物详细信息的ListView
ListView briefInformationListView=(ListView) findViewById(R.id.brief_information_list_view);
View emptyView=findViewById(R.id.brief_empty_view);
briefInformationListView.setEmptyView(emptyView);
//设置Adapter
mCursorAdapter=new BriefInformationAdapter(this,null);
briefInformationListView.setAdapter(mCursorAdapter);
//设置ListView的元素点击事件
briefInformationListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//设置相应的Intent打开对应的Activity
Intent openDetail=new Intent(EditPetInformationActivity.this,ItemDetailInformationActivity.class);
//通过id去创建相应的Uri
Uri mCurrentUri= ContentUris.withAppendedId(PetInforamtionDatabase.CONTENT_URI,id);
//发送生成的Uri到Intent
openDetail.setData(mCurrentUri);
//打开相应的Activity
startActivity(openDetail);
}
});
getLoaderManager().initLoader(PET_LOADER,null,this);
}