我在RecyclerView
中有一份食谱列表,当选择一个项目时,活动会显示该食谱的详细信息(即产量,方向,评级,收藏等)。
每个食谱的一般信息在一个表(食谱)上,成分在另一个表(成分)中,一个单独的表(RecipeIngredients)用于将食谱与成分链接起来创建多对多关系。
当我在另一个线程上使用AsyncTaskLoader
显示详细信息活动时,我正在尝试检索另一个RecyclerView中的成分列表。但是,我似乎无法弄清楚如何调用加载器并返回特定配方的成分列表。
我的SQL查询确实返回了指定配方项的成分列表(通过“执行SQL”选项卡在数据库浏览器中检查SQLite
)。
我有以下内容:
RecipeDisplayActivity.java
public class RecipeDisplayActivity extends AppCompatActivity {
private ArrayList<Ingredient> _ingredientsInRecipe = new ArrayList();
private DBHandler _repository;
private ProgressBar _progressIngredient;
private ProgressBar _progressDirections;
private Recipe _recipe;
private RecipeIngredientAdapter _adapterIngredient;
private RecyclerView _rvIngredient;
private TextView _lblIngredientMessage;
private TextView _lblRecipeCategory;
private TextView _lblRecipeDirections;
TextView _lblRecipeTitle;
private static final int RECIPE_INFORMATION_LOADER_ID = 173281;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recipe_display);
initControls(savedInstanceState);
}
private void initControls(Bundle savedInstanceState) {
this._repository = DBHandler.getInstance(this);
int recipeId = getIntent().getIntExtra(UIConsts.Bundles.RECIPE_KEY_ID, -1);
if (recipeId > 0) {
this._recipe = this._repository.recipes.getById(recipeId);
} else {
throw new IllegalStateException("RECIPE_KEY_ID not provided.");
}
setTitle(this._recipe.getTitle());
this._lblRecipeTitle = (TextView) findViewById(R.id.lblRecipeTitle);
this._lblRecipeTitle.setText(this._recipe.getTitle());
this._lblRecipeCategory = (TextView) findViewById(R.id.lblRecipeCategory);
this._lblRecipeCategory.setText(this._recipe.getCategory());
this._lblRecipeDirections = (TextView) findViewById(R.id.lblRecipeDirections);
this._lblRecipeDirections.setText(this._recipe.getDirections());
final RatingBar ratingUser = (RatingBar) findViewById(R.id.ratingUser);
ratingUser.setRating(this._recipe.displayRating());
final ImageButton imgbtnFavoriteRecipe = (ImageButton) findViewById(R.id.imgbtnFavoriteRecipe);
if (this._recipe.isFavorite()) {
imgbtnFavoriteRecipe.setColorFilter(Utils.CustomColors.FAVORITE);
} else {
imgbtnFavoriteRecipe.setColorFilter(Color.rgb(80, 80, 80));
}
this._progressIngredient = (ProgressBar) findViewById(R.id.progressIngredient);
this._lblIngredientMessage = (TextView) findViewById(R.id.lblIngredientMessage);
this._rvIngredient = (RecyclerView) findViewById(R.id.rvIngredient);
this._rvIngredient.setHasFixedSize(true);
this._rvIngredient.setNestedScrollingEnabled(false);
this._rvIngredient.setLayoutManager(new LinearLayoutManager(this));
this._adapterIngredient = new RecipeIngredientAdapter(this._ingredientsInRecipe, this);
this._rvIngredient.setAdapter(this._adapterIngredient);
this._progressDirections = (ProgressBar) findViewById(R.id.progressDirections);
if (this._recipe.getId() != null) {
this._progressIngredient.setVisibility(View.GONE);
this._lblIngredientMessage.setText(R.string.recipe_no_ingredients);
this._lblIngredientMessage.setVisibility(View.GONE);
this._progressDirections.setVisibility(View.GONE);
loadFullRecipeInformation();
}
}
public void loadFullRecipeInformation() {
getSupportLoaderManager().initLoader(RECIPE_INFORMATION_LOADER_ID, null, new LoaderManager.LoaderCallbacks<Recipe>() {
public Loader<Recipe> onCreateLoader(int id, Bundle args) {
return new FullRecipeInformationLoader(RecipeDisplayActivity.this.getApplicationContext(), RecipeDisplayActivity.this._recipe.getId());
}
public void onLoadFinished(Loader<Recipe> loader, Recipe recipe) {
if (recipe == null) {
Exception exception = ((FullRecipeInformationLoader) loader).getException();
if (exception == null) {
return;
}
RecipeDisplayActivity.this._progressIngredient.setVisibility(View.GONE);
RecipeDisplayActivity.this._lblIngredientMessage.setText(R.string.general_msg_something_went_wrong);
RecipeDisplayActivity.this._lblIngredientMessage.setVisibility(View.VISIBLE);
Toast.makeText(RecipeDisplayActivity.this, R.string.general_msg_something_went_wrong, Toast.LENGTH_LONG).show();
return;
}
recipe.setId(RecipeDisplayActivity.this._recipe.getId());
recipe.setRating(RecipeDisplayActivity.this._recipe.getRating());
recipe.setFavorite(RecipeDisplayActivity.this._recipe.isFavorite());
recipe.setTimeAdded(RecipeDisplayActivity.this._recipe.getTimeAdded());
RecipeDisplayActivity.this._recipe = recipe;
RecipeDisplayActivity.this._adapterIngredient.notifyDataSetChanged();
RecipeDisplayActivity.this.displayListStateIngredients();
}
public void onLoaderReset(Loader<Recipe> loader) {
}
}).forceLoad();
}
private void displayListStateIngredients() {
this._progressIngredient.setVisibility(View.GONE);
if (this._ingredientsInRecipe.size() < 1) {
this._rvIngredient.setVisibility(View.GONE);
this._lblIngredientMessage.setText(R.string.recipe_no_ingredients);
this._lblIngredientMessage.setVisibility(View.VISIBLE);
return;
}
this._lblIngredientMessage.setVisibility(View.GONE);
this._rvIngredient.setVisibility(View.VISIBLE);
}
}
RecipeIngredientAdapter.java
public class RecipeIngredientAdapter extends RecyclerView.Adapter<RecipeIngredientAdapter.ViewHolder> {
private Activity _activity;
private ArrayList<Ingredient> _ingredient;
// Provide a direct reference to each of the views within a data item
// Used to cache the views within the item layout for fast access
public class ViewHolder extends RecyclerView.ViewHolder {
// Your holder should contain a member variable
// for any view that will be set as you render a row
private CardView cardIngredient;
private TextView lblIngredientName;
private Ingredient ingredient;
// We also create a constructor that accepts the entire item row
// and does the view lookups to find each subview
public ViewHolder(View itemView) {
super(itemView);
this.cardIngredient = (CardView) itemView.findViewById(R.id.cardIngredient);
this.lblIngredientName = (TextView) itemView.findViewById(R.id.lblIngredientName);
}
void bindViewHolder(Ingredient ingredient) {
this.ingredient = ingredient;
this.lblIngredientName.setText(ingredient.getName());
}
}
public RecipeIngredientAdapter(ArrayList<Ingredient> ingredientInRecipe, Activity activity) {
this._ingredient = ingredientInRecipe;
this._activity = activity;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row_ingredient, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.bindViewHolder((Ingredient) this._ingredient.get(position));
}
@Override
public int getItemCount() {
return this._ingredient.size();
}
public Context getContext() {
return this._activity.getApplicationContext();
}
}
FullRecipeInformationLoader.java
public class FullRecipeInformationLoader extends AsyncTaskLoader<Recipe> {
private Context _context;
private Exception _exception;
private int _recipeId;
private DBHandler _repository;
public FullRecipeInformationLoader(@NonNull Context context, int _recipeId) {
super(context);
this._context = context;
this._recipeId = _recipeId;
}
public Recipe loadInBackground() {
try {
// Return list of Ingredients
return this._repository.recipeIngredients.getIngredientForRecipeById(this._recipeId);
} catch (Exception e) {
this._exception = e;
return null;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
public Exception getException() {
return this._exception;
}
}
RecipeIngredients类
public class RecipeIngredients {
public ArrayList<Ingredient> getIngredientForRecipeById(int recipeId) {
if (recipeId < 1) {
throw new IllegalArgumentException("recipeId");
}
Cursor cursor = DBHandler.this._helper.getReadableDatabase().rawQuery("SELECT Ingredients.* FROM Recipes, Ingredients, RecipeIngredient WHERE RecipeIngredient._ingredient_id = Ingredients._ingredient_id AND Recipes._id = " + recipeId, null);
ArrayList<Ingredient> ingredients = new ArrayList();
while (cursor.moveToNext()) {
ingredients.add(createIngredientFromCursor(cursor));
}
cursor.close();
return ingredients;
}
private Ingredient createIngredientFromCursor(Cursor cursor) {
boolean z2 = true;
Ingredient ingredient = new Ingredient();
int id = cursor.getInt(cursor.getColumnIndex(DBConsts.Table_Ingredient.COLUMN_IngredientId));
ingredient.setId(Integer.valueOf(id));
ingredient.setName(cursor.getString(cursor.getColumnIndex(DBConsts.Table_Ingredient.COLUMN_IngredientName)));
return ingredient;
}
}
如果您需要我遗漏的任何信息,请告诉我。 Thanx提前...
答案 0 :(得分:0)
将cursorLoaders与recyclerView.Adapter一起使用
示例:
public class RecipeDisplayActivity extends AppCompatActivity {
Cursror bdCursor;
@Override
public void onCreate(Bundle savedInstanceState) {
RecyclerView newList = findViewById(android.R.id.list);
BottleDataAdapter adapter = new BottleDataAdapter(bdCursor);
LinearLayoutManager llm = new LinearLayoutManager(this);
newList.setLayoutManager(llm);
newList.setAdapter(adapter);
//next line call cursorLoader
//(CursorLoader is subclass of AsyncTaskLoader, so you can call ATL with next line)
//and next line you may use whenever you want e.g in onClick etc.
getSupportLoaderManager().restartLoader(id, null, this);
}
}
下一步是覆盖回调(在活动中)
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new SelectItems(this, i);
}
@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
adapter.changeCursor(cursor);//!!!!! This method was written manualy for changing cursor. You can see it in bottom
}
@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) { }
SelectItems的位置是:
public class SelectItems extends CursorLoader {
//you can give your params from activity to query here
public SelectItems(Context context, int param) {
super(context);
}
@Override
public Cursor loadInBackground() {
//ProxyManager is just class for db queries, so next line you must do db query
Cursor cursor = getProxyManager().getSectionsItems(mTypeSection);
return cursor;
}
}
和完成步骤是写我们的适配器
public class BottleDataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Bottle> bottles = new ArrayList<>();
private Cursor cursor;
//in constructor we set our cursor and init our data from this cursor
public BottleDataAdapter(Cursor cursor) {
this.cursor = cursor;
initData();
}
private void initData() {
if (cursor != null) {
for (int pos = 0; pos < cursor.getCount(); pos++) {
cursor.moveToPosition(pos);
bottles.add(new Bottle(cursor.getString(0)));
}
}
}
public void changeCursor(Cursor cursor) {
this.cursor = cursor;
initData();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {...}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {...}
@Override
public int getItemCount(){...}
}
此外,您可以在RecyclerViewAdapter中使用CursorAdapter而不是Cursor