我正在实现内容提供程序和SQLite数据库。我已经能够向我的内容提供商添加内容,但现在我正在尝试使用Loader将该数据加载到片段的回收器视图中。
数据库定义(ClosetDbHelper.java):
public class ClosetDbHelper extends SQLiteOpenHelper
{
private static final String DATABASE_NAME="closetsnstuff.db";
private static final int DATABASE_VERSION = 1;
private static final String SQL_CREATE_TABLE_CLOSETS= String.format("CREATE TABLE %s"+" (%s INTEGER PRIMARY KEY AUTOINCREMENT, %s TEXT, %s TEXT, %s TEXT)",
DatabaseContract.TABLE_CLOSET_SHOES,
DatabaseContract.ClosetShoesColumns._ID,
DatabaseContract.ClosetShoesColumns.SHOE_IMAGE,
DatabaseContract.ClosetShoesColumns.SHOE_BRAND,
DatabaseContract.ClosetShoesColumns.SHOE_NAME);
private final Context mContext;
public ClosetDbHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(SQL_CREATE_TABLE_CLOSETS);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("DROP TABLE IF EXISTS " + DatabaseContract.TABLE_CLOSET_SHOES);
onCreate(db);
}
}
我的数据库合同(DatabaseContract.java):
public class DatabaseContract {
public static final String TABLE_CLOSET_SHOES = "shoe_closets";
public static final String AUTHORITY = "com.example.android.myshoecloset";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + AUTHORITY);
public static final String PATH_CLOSETS = "shoe_closets";
public static final class ClosetShoesColumns implements BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()
.appendPath(PATH_CLOSETS).build();
public static final String TABLE_NAME="shoe_closets";
//closet image
public static final String SHOE_IMAGE = "image";
//brand name
public static final String SHOE_BRAND = "brand";
//shoe name
public static final String SHOE_NAME = "name";
}
}
我的内容提供程序类(Provider.java):
public class Provider extends ContentProvider
{
public static final int CLOSETS=100;
public static final int CLOSETS_WITH_ID = 101;
private static final UriMatcher sUriMatcher = buildUriMatcher();
public static UriMatcher buildUriMatcher()
{
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(DatabaseContract.AUTHORITY, DatabaseContract.PATH_CLOSETS, CLOSETS);
uriMatcher.addURI(DatabaseContract.AUTHORITY, DatabaseContract.PATH_CLOSETS + "/#", CLOSETS_WITH_ID);
return uriMatcher;
}
private ClosetDbHelper mClosetDbHelper;
@Override
public boolean onCreate()
{
Context context = getContext();
mClosetDbHelper = new ClosetDbHelper(context);
return true;
}
@Override
public Uri insert(@NonNull Uri uri, ContentValues values)
{
final SQLiteDatabase db = mClosetDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
Uri returnUri;
switch(match)
{
case CLOSETS:
long id = db.insert(DatabaseContract.ClosetShoesColumns.TABLE_NAME, null, values);
if(id > 0)
{
returnUri = ContentUris.withAppendedId(CONTENT_URI, id);
} else
{
throw new android.database.SQLException("Failed to insert row into " + uri);
}
break;
default:
throw new UnsupportedOperationException("Unknown Uri: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return returnUri;
}
@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
final SQLiteDatabase db = mClosetDbHelper.getReadableDatabase();
int match = sUriMatcher.match(uri);
Cursor retCursor;
switch(match)
{
case CLOSETS:
retCursor = db.query(TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
default:
throw new UnsupportedOperationException("Unknown URI: " + uri);
}
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
return retCursor;
}
}
现在我的CustomAdapter类应该从内容提供程序获取数据并将其绑定到视图:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.TaskHolder> {
/* Callback for list item click events */
public interface OnItemClickListener {
void onItemClick(View v, int position);
void onItemToggled(boolean active, int position);
}
/* ViewHolder for each task item */
public class TaskHolder extends RecyclerView.ViewHolder {
public TextView shoeBrandName;
// public ImageView priorityView;
public TextView shoeName;
public TaskHolder(View itemView) {
super(itemView);
shoeBrandName = (TextView) itemView.findViewById(R.id.textBrandName);
// priorityView = (ImageView) itemView.findViewById(R.id.priority);
shoeName = (CheckBox) itemView.findViewById(R.id.textShoeName);
}
}
private Cursor mCursor;
private OnItemClickListener mOnItemClickListener;
private Context mContext;
public CustomAdapter(Context mContext) {
this.mContext = mContext;
}
@Override
public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mContext = parent.getContext();
View itemView = LayoutInflater.from(mContext)
.inflate(R.layout.text_row_item, parent, false);
return new TaskHolder(itemView);
}
@Override
public void onBindViewHolder(TaskHolder holder, int position) {
int idIndex = mCursor.getColumnIndex(DatabaseContract.ClosetShoesColumns._ID);
int shoeBrandName = mCursor.getColumnIndex(DatabaseContract.ClosetShoesColumns.SHOE_BRAND);
int shoeName = mCursor.getColumnIndex(DatabaseContract.ClosetShoesColumns.SHOE_NAME);
mCursor.moveToPosition(position);
final int id = mCursor.getInt(idIndex);
String brandNameStr = mCursor.getString(shoeBrandName);
String shoeNameStr = mCursor.getString(shoeName);
Log.d("TAG", brandNameStr + "" + shoeNameStr);
holder.itemView.setTag(id);
holder.shoeBrandName.setText(brandNameStr);
holder.shoeName.setText(shoeNameStr);
}
@Override
public int getItemCount() {
return (mCursor != null) ? mCursor.getCount() : 0;
}
public void swapCursor(Cursor cursor) {
if (mCursor != null) {
mCursor.close();
}
mCursor = cursor;
}
}
最后,我有我的ClosetFragment类,我希望显示内容提供程序内容。
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.RadioButton;
import com.example.android.myshoecloset.data.DatabaseContract;
public class ClosetFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>
{
private static final String TAG = "ClosetFragment";
protected RecyclerView mRecyclerView;
protected CustomAdapter mAdapter;
private static final int CUSTOM_LOADER_ID = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_closet, container, false);
rootView.setTag(TAG);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
mAdapter = new CustomAdapter(getActivity().getApplicationContext());
// Set CustomAdapter as the adapter for RecyclerView.
mRecyclerView.setAdapter(mAdapter);
getActivity().getSupportLoaderManager().initLoader(CUSTOM_LOADER_ID, null, (LoaderManager.LoaderCallbacks<Cursor>)this);
return rootView;
}
@Override
public void onResume()
{
super.onResume();
getActivity().getSupportLoaderManager().restartLoader(CUSTOM_LOADER_ID, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, final Bundle loaderArgs)
{
return new AsyncTaskLoader<Cursor>(getActivity().getApplicationContext()) {
Cursor mTaskData = null;
@Override
protected void onStartLoading()
{
if(mTaskData != null)
{
deliverResult(mTaskData);
}
else
{
forceLoad();
}
}
public Cursor loadInBackground()
{
try
{
Log.d("YES ", getActivity().getContentResolver().query(DatabaseContract.ClosetShoesColumns.CONTENT_URI, null, null, null, null)+"");
return getActivity().getApplicationContext().getContentResolver().query(DatabaseContract.ClosetShoesColumns.CONTENT_URI,
null,
null,
null,
null);
} catch(Exception e)
{
Log.e("", "Failed to asynchronously load data.");
e.printStackTrace();
return null;
}
}
public void deliverResult(Cursor data)
{
mTaskData = data;
super.deliverResult(data);
}
};
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
{
mAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader)
{
mAdapter.swapCursor(null);
}
}
对于代码密集的帖子感到抱歉,但对此有任何帮助将不胜感激!
答案 0 :(得分:0)
当您将新数据交换到RecyclerView.Adapter
时,您还需要调用notifyDataSetChanged()
,因此适配器知道无效并重新绑定视图。
public void swapCursor(Cursor c) {
mCursor = c;
notifyDataSetChanged();
}
此外,我强烈建议您使用CursorLoader
。它是专门为这个用例编写的。 CursorLoader
也将为您关闭光标。
编辑:您的RecyclerView
也缺少布局管理器。