I have a list of recipes in a RecyclerView
and when an item is selected, an activity displays the details of that recipe (ie. yield, directions, ratings, favorites, etc.).
The general information of each recipe is on one table (Recipes) and the ingredients are in another table (Ingredients), a separate table (RecipeIngredients) is used to link the recipes with ingredients creating a many-to-many relationship.
I'm trying to retrieve a list of ingredients in another RecyclerView when the details activity is displayed by using an AsyncTaskLoader
on another thread. However, I just can't seem to figure out how to call the loader and return the list of ingredients for a specific recipe.
The SQL query I have does return a list of ingredients for a specified recipe item (checked in DB Browser for SQLite
via the "Execute SQL" tab).
I have the following:
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 class
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;
}
}
Let me know if you need any information I missed. Thanx in advance...