Reputation: 13
My app layout apparently isn't a normal layout so I a having trouble setting my List Adapter to auto updated when an edit is made.
I make my edits to my database in this Java File which is controlled in its own activity and layout.
public void onClick(View view){
if (view == findViewById(R.id.addsave)) {
RecipeRepo repo = new RecipeRepo(this);
Recipe recipe = new Recipe();
if (editTextName.getText().toString().equals("")) {
editTextName.setError("Recipe name required!");
return;
} else {
recipe.name = editTextName.getText().toString();
}
if (textImagePath.getText().toString().equals("") ) {
recipe.image = ("");
}else{
recipe.image = textImagePath.getText().toString();
}
recipe.category = staticSpinner.getSelectedItem().toString();
if (editTextIngredients.getText().toString().equals("")) {
editTextIngredients.setError("Ingredient required!");
return;
} else {
recipe.ingredients = editTextIngredients.getText().toString();
}
if (editTextInstruct.getText().toString().equals("")) {
editTextIngredients.setError("Instruction required!");
return;
} else {
recipe.instructions = editTextInstruct.getText().toString();
}
recipe.cooktemp = editTextCookTemp.getText().toString();
recipe.cooktime = editTextCookTime.getText().toString();
recipe.serves = editTextServings.getText().toString();
recipe.recipe_Id = _Recipe_Id;
if (_Recipe_Id == 0) {
_Recipe_Id = repo.insert(recipe);
Toast.makeText(this, "New Recipe Added", Toast.LENGTH_SHORT).show();
finish();
it actually inserts and updates in this java file
int insert(Recipe recipe){
//Open connection to write data
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Recipe.KEY_SERVES, recipe.serves);
values.put(Recipe.KEY_COOKTIME, recipe.cooktime);
values.put(Recipe.KEY_COOKTEMP, recipe.cooktemp);
values.put(Recipe.KEY_INSTRUCT, recipe.instructions);
values.put(Recipe.KEY_INGREDIENTS, recipe.ingredients);
values.put(Recipe.KEY_CATEGORY, recipe.category);
values.put(Recipe.KEY_IMAGE, recipe.image);
values.put(Recipe.KEY_NAME, recipe.name);
//Inserting Row
long recipe_Id = db.insert(Recipe.TABLE, null, values);
db.close();// Closing database connection
return (int) recipe_Id;
}
void delete(int recipe_Id){
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete(Recipe.TABLE, Recipe.KEY_ID + "=?", new String[] {String.valueOf(recipe_Id)});
db.close();
}
void update(Recipe recipe){
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Recipe.KEY_SERVES, recipe.serves);
values.put(Recipe.KEY_COOKTIME, recipe.cooktime);
values.put(Recipe.KEY_COOKTEMP, recipe.cooktemp);
values.put(Recipe.KEY_INSTRUCT, recipe.instructions);
values.put(Recipe.KEY_INGREDIENTS, recipe.ingredients);
values.put(Recipe.KEY_CATEGORY, recipe.category);
values.put(Recipe.KEY_IMAGE, recipe.image);
values.put(Recipe.KEY_NAME, recipe.name);
db.update(Recipe.TABLE, values, Recipe.KEY_ID + "=?", new String[]{String.valueOf(recipe.recipe_Id)});
db.close();
}
and lastly it gets put into the list view from this Java file and separate layout. Which is where my adapters are but i cannot get the notifyDataSetChanged() to work here at all... as in it wont even come up.
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
RecipeRepo repo = new RecipeRepo(this);
if (id == R.id.nav_meat) {
final ArrayList<HashMap<String, String>> recipeList = repo.getRecipeMeat();
if(recipeList.size()!=0) {
ListView lv = (ListView) findViewById(R.id.list);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
recipe_Id = (TextView) view.findViewById(R.id.recipe_Id);
String recipeId = recipe_Id.getText().toString();
Intent objIndent = new Intent(getApplicationContext(), RecipeDetail.class);
objIndent.putExtra("recipe_Id", Integer.parseInt(recipeId));
startActivity(objIndent);
}
});
ListAdapter adapter = new SimpleAdapter(SousChef.this, recipeList, R.layout.view_recipe_entry, new String[]{"id", "category", "name"}, new int[]{R.id.recipe_Id, R.id.recipe_list_category, R.id.recipe_list_name});
lv.setAdapter(adapter);
}else {
Toast.makeText(this, "No recipe!", Toast.LENGTH_SHORT).show();
}
} else if (id == R.id.nav_veg) {
final ArrayList<HashMap<String, String>> recipeList = repo.getRecipeVeg();
if(recipeList.size()!=0) {
ListView lv = (ListView) findViewById(R.id.list);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
recipe_Id = (TextView) view.findViewById(R.id.recipe_Id);
String recipeId = recipe_Id.getText().toString();
Intent objIndent = new Intent(getApplicationContext(), RecipeDetail.class);
objIndent.putExtra("recipe_Id", Integer.parseInt(recipeId));
startActivity(objIndent);
}
});
ListAdapter adapter = new SimpleAdapter(SousChef.this, recipeList, R.layout.view_recipe_entry, new String[]{"id", "category", "name"}, new int[]{R.id.recipe_Id, R.id.recipe_list_category, R.id.recipe_list_name});
lv.setAdapter(adapter);
}else {
Toast.makeText(this, "No recipe!", Toast.LENGTH_SHORT).show();
}
So any advise on setting this up to automatically update would be a huge help. I have been racking my brain over this for a couple days now looking at different examples and what not, but no setup is quite like this one which doesnt allow me to have everything in one file.
And thank you in advance.
category picking image: Category picking Image
Upvotes: 0
Views: 61
Reputation: 2260
There are for sure more answers but this is one that might help,
Quick Example for the proposed solution
SHORT EXPLANATION
inside MainActivity
//create a public static adapter
public static ListAdapter adapter
inside onCreateView()
//Create your adapter and set it to the right ListView
ListView lv = findViewById(R.id.listView_in_xml);
adapter = new SimpleAdapter(...)
lv.setAdapter(adapter)
inside CustomAdapter
which in your case I assume is SimpleAdapter
//add a public method to be called so that the Adapter updates and displays the new data
public void updateMethod(){
//update your List<Recipe> that I would guess you have calling the database again
//if needed update your getCount() return value so that it returns the number of childs in your ListView which most of the cases is just the List<Recipe>.size()
//notifyDataSetChanged()
}
inside your DB HANDLER CLASS
//in every update, add, delete or any method that requires the ListView to Update just call the created method,
MainActivity.CustomAdapter.updateMethod();
PROBLEMS
You will have to make sure the public static adapter
has been initialized and is not null, or simply check whether the adapter
is not null
and update, because if the adapter is null
that activity has not launched yet thus no need to trigger the updateMethod()
.
OTHER SOLUTIONS
Instead of creating a public static adapter
create a public static boolean
, then whenever data changes set that boolean to true from the database.
Finally, whenever you resume your activity check against that boolean and update your ListViewAdapter if needed.
MORE COMPLICATED SOLUTIONS WHICH I KNOW WORK CAUSE I USE IT
Use TaskAsyncTaskLoader
which utilizes a Loader
in your MainActivity
and implements LoaderManager.LoaderCallbacks
.
Optionally, you can make the Loader
be, public static Loader
and inside your DBHandler
you trigger the loader to load the data again or use any other logic you want.
Proofs of Working suggested solution,
Upvotes: 1
Reputation: 1663
You can Broadcast Intent from the change database file after you get the response in the onCreate() of adapter loading class
Intent intent = new Intent("key_to_identify_the_broadcast");
Bundle bundle = new Bundle();
bundle.putString("edttext", "changed");
intent.putExtra("bundle_key_for_intent", bundle);
context.sendBroadcast(intent);
and then you can receive the bundle in your fragment by using the BroadcastReceiver class
private final BroadcastReceiver mHandleMessageReceiver = new
BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle =
intent.getExtras().getBundle("bundle_key_for_intent");
if(bundle!=null){
String edttext = bundle.getString("edttext");
}
//you can call any of your methods for using this bundle for your use case
}
};
in onCreate() of your adapter adding class you need to register the broadcast receiver first otherwise this broadcast receiver will not be triggered
IntentFilter filter = new IntentFilter("key_to_identify_the_broadcast");
getActivity().getApplicationContext().
registerReceiver(mHandleMessageReceiver, filter);
Finally you can unregister the receiver to avoid any exceptions
@Override
public void onDestroy() {
try {
getActivity().getApplicationContext().
unregisterReceiver(mHandleMessageReceiver);
} catch (Exception e) {
Log.e("UnRegister Error", "> " + e.getMessage());
}
super.onDestroy();
}
Upvotes: 0