RecyclerView does not update after deleting an item from sqlite? [duplicate] - android

This question already has answers here:
How to update RecyclerView Adapter Data
(16 answers)
Closed 2 years ago.
I have populated recyclerview from sqlite .when clicking each row ,row will delete from sqlite but recyclerview not showing updated list after delete. Recycler view show updated list only after launching activity once again. My question is how to update the recycler view soon after deleting an item from the recylcerview without refresh.
following are my code
SecondActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import java.util.ArrayList;
import java.util.List;
public class SecondActivity extends AppCompatActivity {
DatabaseHelpher helpher;
List<DatabaseModel> dbList;
RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
helpher = new DatabaseHelpher(this);
dbList= new ArrayList<DatabaseModel>();
dbList = helpher.getDataFromDB();
mRecyclerView = (RecyclerView)findViewById(R.id.recycleview);
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
// specify an adapter (see also next example)
mAdapter = new RecyclerAdapter(this,dbList);
mRecyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged ();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_second, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
DatabaseHelpher.java
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class DatabaseHelpher extends SQLiteOpenHelper {
private static final String DATABASE_NAME="student";
private static final int DATABASE_VERSION = 1;
private static final String STUDENT_TABLE = "stureg";
private static final String STU_TABLE = "create table "+STUDENT_TABLE +"(name TEXT,email TEXT primary key,roll TEXT,address TEXT,branch TEXT)";
Context context;
public DatabaseHelpher(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(STU_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + STUDENT_TABLE);
// Create tables again
onCreate(db);
}
/* Insert into database*/
public void insertIntoDB(String name,String email,String roll,String address,String branch){
Log.d("insert", "before insert");
// 1. get reference to writable DB
SQLiteDatabase db = this.getWritableDatabase();
// 2. create ContentValues to add key "column"/value
ContentValues values = new ContentValues();
values.put("name", name);
values.put("email", email);
values.put("roll", roll);
values.put("address", address);
values.put("branch", branch);
// 3. insert
db.insert(STUDENT_TABLE, null, values);
// 4. close
db.close();
Toast.makeText(context, "insert value", Toast.LENGTH_LONG);
Log.i("insert into DB", "After insert");
}
/* Retrive data from database */
public List<DatabaseModel> getDataFromDB(){
List<DatabaseModel> modelList = new ArrayList<DatabaseModel>();
String query = "select * from "+STUDENT_TABLE;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query,null);
if (cursor.moveToFirst()){
do {
DatabaseModel model = new DatabaseModel();
model.setName(cursor.getString(0));
model.setEmail(cursor.getString(1));
model.setRoll(cursor.getString(2));
model.setAddress(cursor.getString(3));
model.setBranch(cursor.getString(4));
modelList.add(model);
}while (cursor.moveToNext());
}
Log.d("student data", modelList.toString());
return modelList;
}
/*delete a row from database*/
public void deleteARow(String email){
SQLiteDatabase db= this.getWritableDatabase();
db.delete(STUDENT_TABLE, "email" + " = ?", new String[] { email });
db.close();
}
}
DatabaseModel.java
public class DatabaseModel {
private String name;
private String roll;
private String address;
private String branch;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRoll() {
return roll;
}
public void setRoll(String roll) {
this.roll = roll;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getBranch() {
return branch;
}
public void setBranch(String branch) {
this.branch = branch;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
RecyclerAdapter.java
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
static List<DatabaseModel> dbList;
static Context context;
static DatabaseHelper dh;
RecyclerAdapter(Context context, List<DatabaseModel> dbList ){
this.dbList = new ArrayList<DatabaseModel>();
this.context = context;
this.dbList = dbList;
dh=new DatabaseHelper(context);
}
#Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_row, null);
// create ViewHolder
ViewHolder viewHolder = new ViewHolder(itemLayoutView);
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerAdapter.ViewHolder holder, int position) {
holder.name.setText(dbList.get(position).getName());
holder.email.setText(dbList.get(position).getEmail());
}
#Override
public int getItemCount() {
return dbList.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView name,email;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
name = (TextView) itemLayoutView
.findViewById(R.id.rvname);
email = (TextView)itemLayoutView.findViewById(R.id.rvemail);
itemLayoutView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
dh.delete(dbList.get(getAdapterPosition()).getEmail);
Toast.makeText(RecyclerAdapter.context, "you have clicked Row " + getAdapterPosition(), Toast.LENGTH_LONG).show();
}
}
}
i have tried to update recyclerview using mAdapter.notifyDataSetChanged (); but it doesn't working for me.please sugget me.Thank you

Remove data from both from your arraylist and from database and than notify your list will update.
or
Delete data from database and after delete get data from database and reload your arraylist with new data will do your work
dbList.remove(getAdapterPosition());
notifyDataSetChanged();
//or use this for better perfomance.
notifyItemRemoved(getAdapterPosition());
Pass position in remove method

You just need to notify adapter that one item is removed, inside onClick method
#Override
public void onClick(View v) {
notifyItemRemoved(this.getLayoutPosition());
}

You are deleting data from DB but not from list in which you have fetch all data so untill you delete data from list, it will show you even if it is deleted. So you need to change your delete method and also need to remove data from list also.
Check below updated method of deletion.
#Override
public void onClick(View v) {
dh.delete(dbList.get(getAdapterPosition()).getEmail);
// These two lines added for remove data from adapter also.
dbList.remove(getAdapterPosition());
notifyDataSetChanged();
Toast.makeText(RecyclerAdapter.context, "you have clicked Row " + getAdapterPosition(), Toast.LENGTH_LONG).show();
}

Try reloading the info.
Change this
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
To this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
dbList = helpher.getDataFromDB();
mAdapter = new RecyclerAdapter(this,dbList);
mRecyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged ();
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
That will reload the information at your Recycler Vuew with every click.

//Define an interface in the Adapter class
private static ItemClickListener itemClickListener;
public interface ItemClickListener {
void onItemClick(int position, View v);
}
and a method
public void setOnItemClickListener(ItemClickListener myClickListener) {
RecyclerAdapter.itemClickListener = myClickListener;
}
in onClick method of viewHolder
#Override
public void onClick(View v) {
dh.delete(dbList.remove(getAdapterPosition()).getEmail);
itemClickListener.onItemClick(getLayoutPosition(), v);
Toast.makeText(RecyclerAdapter.context, "you have clicked Row " + getAdapterPosition(), Toast.LENGTH_LONG).show();
}
In your Activity's onCreate() or onResume() method
mAdapter.setOnItemClickListener(new RecyclerAdapter.ItemClickListener() {
#Override
public void onItemClick(int position, View v) {
mAdapter.notifyDataSetChanged();
}
});

You can call recreate() after performing the delete operation in your activity so you can refresh the activity. it works for me. Hope this will work you as well.

Remove the list data from arrayList using
arrayList.remove(position);
And update your Adapter using,
mAdapter.notifyDataSetChanged ();

use notifyItemRemoved() instead of notifyDataSetChanged()

Do It like this
builder.setNeutralButton("Delete", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
PersonDBHelper dbHelper = new PersonDBHelper(mContext);
dbHelper.deletePersonRecord(person.getId(), mContext);
mPeopleList.remove(position);
mRecyclerV.removeViewAt(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mPeopleList.size());
notifyDataSetChanged();
}
});
and Use the On restart method in the recycle list

Related

Android: Skipped 41 frames! The application may be doing too much work on its main thread

I'm really struggling to get my head round this thread thing. The below code is my mainactivity, I am just trying to test if my sqlite database is functioning by running a simple query to display a recipe.
Currently the app just runs the main screen but nothing else works. What can I do to get this working?
I can provide further code/snippets if requested. Thank you
package com.stu54259.plan2cook;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.bottomappbar.BottomAppBar;
import com.synnapps.carouselview.CarouselView;
import com.synnapps.carouselview.ImageListener;
public class MainActivity extends AppCompatActivity {
CarouselView carouselView;
int[] sampleImages = {R.drawable.avocado_salad, R.drawable.chicken_tikka_curry, R.drawable.turkey_taco_bowls};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpBottomAppBar();
carouselView = findViewById(R.id.recipeImage);
carouselView.setPageCount(sampleImages.length);
carouselView.setImageListener(imageListener);
findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "Create Recipe Clicked.", Toast.LENGTH_SHORT).show();
}
});
GridView gv = findViewById(R.id.gridview);
gv.setAdapter(new SetImageAdapter(this));
}
ImageListener imageListener = new ImageListener() {
#Override
public void setImageForPosition(int position, ImageView imageView) {
imageView.setImageResource(sampleImages[position]);
}
};
private void setUpBottomAppBar() {
BottomAppBar bottomAppBar = findViewById(R.id.bar);
setSupportActionBar(bottomAppBar);
Log.d("appbar setup", "yes");
bottomAppBar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.recipes:
Toast.makeText(MainActivity.this, "Recipes clicked.", Toast.LENGTH_LONG).show();
Log.d("Intent", "clicked ");
Intent intent = new Intent(MainActivity.this, Recipe.class);
startActivity(intent);
break;
case R.id.shoppingList:
Toast.makeText(MainActivity.this, "Shopping List clicked", Toast.LENGTH_SHORT).show();
break;
}
return false;
}
});
}
/* #Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.bottom_nav_primary, menu);
return super.onCreateOptionsMenu(menu);
}*/
}
Logcat
Skipped 41 frames! The application may be doing too much work on its main thread.
Recipe.java
package com.stu54259.plan2cook;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.tabs.TabLayout;
import com.stu54259.plan2cook.Model.RecipeList;
import com.stu54259.plan2cook.database.DatabaseManager;
import java.util.ArrayList;
import java.util.List;
public class Recipe extends MainActivity {
TabLayout tabLayout;
ImageView recipeImage;
TextView descriptionText, courseText, servingsText, costText, caloriesText, methodText;
RecyclerView listIngredient;
SQLiteDatabase db;
String search_name, selectQuery;
Cursor c;
RecyclerViewAdapter adapterRecipe;
List<RecipeList> itemRecipe = new ArrayList<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recipe);
//search_name = getIntent().getStringExtra("NAME");
search_name = "Speedy chicken couscous";
//recyclerview Recipe
adapterRecipe = new RecyclerViewAdapter(this, itemRecipe);
listIngredient = findViewById(R.id.listIngredient);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false);
listIngredient.setLayoutManager(mLayoutManager);
listIngredient.setItemAnimator(new DefaultItemAnimator());
listIngredient.setAdapter(adapterRecipe);
loadRecipe();
}
public void loadRecipe() {
itemRecipe.clear();
db = (new DatabaseManager(this).getWritableDatabase());
String selectQuery = "";
selectQuery = selectQuery + "SELECT A.ingredient_quantity, B.measurement_name, B.ingredient_name, B.description " +
"FROM TABLE_QUANTITY JOIN TABLE_INGREDIENT ON A.ingredient = B.ingredient_name";
c = db.rawQuery(selectQuery, new String[]{"%" + search_name + "%"});
if (c.moveToFirst()) {
do {
RecipeList recipeList = new RecipeList();
recipeList.setId(c.getInt(c.getColumnIndex("COL_ID")));
recipeList.setIngredient_amount(c.getString(c.getColumnIndex("COL_INGREDIENT_QUANTITY")));
recipeList.setMeasurement_name(c.getString(c.getColumnIndex("COL_MEASUREMENT_NAME")));
recipeList.setIngredient_name(c.getString(c.getColumnIndex("COL_INGREDIENT_NAME")));
recipeList.setDescription(c.getString(c.getColumnIndex("COL_DESCRIPTION")));
itemRecipe.add(recipeList);
} while (c.moveToNext());
c.close();
}
}
}
Recyclerview adapter
package com.stu54259.plan2cook;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.stu54259.plan2cook.Model.RecipeList;
import java.util.List;
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private List<RecipeList> itemRecipe;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
RecyclerViewAdapter(Context context, List<RecipeList> data) {
this.mInflater = LayoutInflater.from(context);
this.itemRecipe = data;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.fragment_item, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.myTextView.setText(itemRecipe.get(position).getIngredient_amount());
holder.myTextView.setText(itemRecipe.get(position).getMeasurement_name());
holder.myTextView.setText(itemRecipe.get(position).getIngredient_name());
holder.myTextView.setText(itemRecipe.get(position).getDescription());
}
// total number of rows
#Override
public int getItemCount() {
return itemRecipe.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView myTextView;
ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.listIngredient);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
You could try making the DB calls in an AsyncTask
AsyncTask getRecipesTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
loadRecipe();
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
//TODO update adapter with new items
}
};
And in onCreate
Replace the call to loadRecipe() with getRecipesTask.execute()
public class Recipe extends MainActivity {
TabLayout tabLayout;
ImageView recipeImage;
TextView descriptionText, courseText, servingsText, costText, caloriesText, methodText;
RecyclerView listIngredient;
SQLiteDatabase db;
String search_name, selectQuery;
Cursor c;
RecyclerViewAdapter adapterRecipe;
List<RecipeList> itemRecipe = new ArrayList<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recipe);
//search_name = getIntent().getStringExtra("NAME");
search_name = "Speedy chicken couscous";
//recyclerview Recipe
adapterRecipe = new RecyclerViewAdapter(this);
listIngredient = findViewById(R.id.listIngredient);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false);
listIngredient.setLayoutManager(mLayoutManager);
listIngredient.setItemAnimator(new DefaultItemAnimator());
listIngredient.setAdapter(adapterRecipe);
getRecipesTask.execute();
}
public void loadRecipe() {
itemRecipe.clear();
db = (new DatabaseManager(this).getWritableDatabase());
String selectQuery = "";
selectQuery = selectQuery + "SELECT A.ingredient_quantity, B.measurement_name, B.ingredient_name, B.description " +
"FROM TABLE_QUANTITY JOIN TABLE_INGREDIENT ON A.ingredient = B.ingredient_name";
c = db.rawQuery(selectQuery, new String[]{"%" + search_name + "%"});
if (c.moveToFirst()) {
do {
RecipeList recipeList = new RecipeList();
recipeList.setId(c.getInt(c.getColumnIndex("COL_ID")));
recipeList.setIngredient_amount(c.getString(c.getColumnIndex("COL_INGREDIENT_QUANTITY")));
recipeList.setMeasurement_name(c.getString(c.getColumnIndex("COL_MEASUREMENT_NAME")));
recipeList.setIngredient_name(c.getString(c.getColumnIndex("COL_INGREDIENT_NAME")));
recipeList.setDescription(c.getString(c.getColumnIndex("COL_DESCRIPTION")));
itemRecipe.add(recipeList);
} while (c.moveToNext());
c.close();
}
}
AsyncTask getRecipesTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
loadRecipe();
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
adapterRecipe.setItems(itemRecipe);
}
};
}
I'm not exactly sure what your adapter looks like but trying something like this:
Probably setItems could be something like in the Adapter
public void setItems(List<Recipe> items) {
this.items = items;
notifyDataSetChanged();
}

How to add & update data in SqliteDatabase by using RecyclerView Adapter

I am just trying to make a list by using RecyclerView where each of the list Item will contain a checkbox button. So when user will click on checkbox, it will replace the value of a Table column such as column country get value "A", on the other hand, uncheck will replace the country column value from "A" to "B" or anything.
Can anyone please help me with this? any suggestion regarding this and other similar ways to add data in SQLite database by using Recyclable will be highly a lot helpful.
Below I have added my code for your reference and Thanks in advance.
My DatabaseHelper Class
package com.hfad.ressql;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.hfad.ressql.DatabaseContractor.*;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "workers.db";
private static final int DATABASE_VERSION =7;
SQLiteDatabase db;
public DatabaseHelper( Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
this.db=db;
final String SQL_CREATE_TBALE="CREATE TABLE " + EmployeeDetails.TABLE_NAME + "(" + EmployeeDetails._ID +" INTEGER PRIMARY KEY AUTOINCREMENT, "+
EmployeeDetails.COLUMN_FIRSTNAME+" TEXT, "+EmployeeDetails.COLUMN_LASTNAME+" TEXT, "+EmployeeDetails.COLUMN_COUNTRY+" TEXT)";
db.execSQL(SQL_CREATE_TBALE);
fillquestion();
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + EmployeeDetails.TABLE_NAME);
onCreate(db);
}
public void fillquestion(){
DataModel o4 = new DataModel("Earth","Soil","B");
IntertData(o4);
DataModel o5 = new DataModel("Sun","Light","B");
IntertData(o5);
DataModel o6 = new DataModel("Moon","Rock","B");
IntertData(o6);
}
public void IntertData (DataModel data){
ContentValues contentValues = new ContentValues();
contentValues.put(EmployeeDetails.COLUMN_FIRSTNAME, data.getFirstName());
contentValues.put(EmployeeDetails.COLUMN_LASTNAME, data.getLastName());
contentValues.put(EmployeeDetails.COLUMN_COUNTRY, data.country);
db.insert(EmployeeDetails.TABLE_NAME,null,contentValues);
}
public List<DataModel> object1() {
ArrayList<DataModel> details = new ArrayList<DataModel>();
db = getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM " + EmployeeDetails.TABLE_NAME, null );
if (cursor.moveToFirst()) {
do {
DataModel object2 = new DataModel();
object2.setFirstName(cursor.getString(cursor.getColumnIndex(EmployeeDetails.COLUMN_FIRSTNAME)));
object2.setLastName(cursor.getString(cursor.getColumnIndex(EmployeeDetails.COLUMN_LASTNAME)));
object2.setCountry(cursor.getString(cursor.getColumnIndex(EmployeeDetails.COLUMN_COUNTRY)));
details.add(object2);
} while (cursor.moveToNext());
}
cursor.close();
return details;
}
}
Here is my DataModel Class
package com.hfad.ressql;
public class DataModel {
public String FirstName;
public String LastName;
public String country;
public DataModel() {
}
public DataModel(String firstName, String lastName, String country) {
this.FirstName = firstName;
this.LastName = lastName;
this.country = country;
}
public String getFirstName() {
return FirstName;
}
public void setFirstName(String firstName) {
FirstName = firstName;
}
public String getLastName() {
return LastName;
}
public void setLastName(String lastName) {
LastName = lastName;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
Database Constructor
public final class DatabaseContractor {
private DatabaseContractor (){}
public static class EmployeeDetails implements BaseColumns {
public static final String TABLE_NAME="employy";
public static final String COLUMN_FIRSTNAME="First_Name";
public static final String COLUMN_LASTNAME="Last_Name";
public static final String COLUMN_COUNTRY="Country";
public static final String COLUMN_FAVO="mfav";
}
}
Recycler Adapter
Here I am struggling hard to sort it out. All I need is, if I click on check box, one pre-given value will be updated in the database, at the same time check box will be checked until user uncheck it. And when user will uncheck it, database will replace previous value with a new value. Actually, I have just trying to have values in a table column, so that I can use it as a favorite or bookmark list.
public class RecycAdapter extends
RecyclerView.Adapter<RecycAdapter.ViewHolder> {
List<DataModel> dotamodeldataArraylist;
Context context;
SQLiteDatabase db;
DatabaseHelper helper;
ContentValues contentValues;
Cursor cursor;
public RecycAdapter(List<DataModel> dotamodeldataArraylist,Context context) {
this.dotamodeldataArraylist=dotamodeldataArraylist;
this.context=context;
}
#Override
public ViewHolder onCreateViewHolder( ViewGroup parent, int ViewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.itemlist,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final RecycAdapter.ViewHolder holder, final int position) {
DataModel obj3= dotamodeldataArraylist.get(position);
holder.Fnam.setText(obj3.getFirstName());
holder.Lname.setText(obj3.getLastName());
holder.Country.setText(obj3.getCountry());
holder.fav.();
holder.fav.setChecked(fav);
final int currentPosition = position;
final boolean fav = 0==0;
holder.fav.setChecked(fav);
final int currentPosition = position;
holder.fav.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(holder.fav.isChecked()){
try {
contentValues = new ContentValues();
contentValues.put(DatabaseContractor.EmployeeDetails.COLUMN_COUNTRY, "B");
db.update("DRINK", contentValues, "id_=?", new String[]{Integer.toString(currentPosition)});
} catch (SQLException e){
Toast.makeText(context,"error" + position , Toast.LENGTH_LONG).show();
}
Toast.makeText(context,"checked " + position , Toast.LENGTH_LONG).show();
} if(!holder.fav.isChecked()){
Toast.makeText(context,"not checked" + position , Toast.LENGTH_LONG).show();
}
}
});
}
#Override
public int getItemCount() {
return dotamodeldataArraylist.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView Fnam,Lname,Country;
CheckBox fav;
RelativeLayout relativeLayout;
public ViewHolder(View itemView) {
super(itemView);
Fnam = itemView.findViewById(R.id.name1);
Lname = itemView.findViewById(R.id.city1);
Country = itemView.findViewById(R.id.country1);
fav=itemView.findViewById(R.id.chk);
relativeLayout = (RelativeLayout) itemView.findViewById(R.id.layout);
}
}
}
View Class
view all class
public class Viewall extends AppCompatActivity {
RecyclerView recyclerView;
DatabaseHelper databaseHelper;
RecycAdapter recycAdapter;
List<DataModel> dotamodeldataArraylist;
Context context;
Button show;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewall);
show = findViewById(R.id.view);
recyclerView=findViewById(R.id.recycle);
databaseHelper =new DatabaseHelper(this);
dotamodeldataArraylist = new ArrayList<DataModel>();
dotamodeldataArraylist=databaseHelper.object1();
recycAdapter =new RecycAdapter(dotamodeldataArraylist,this);
RecyclerView.LayoutManager reLayoutManager =new
LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(reLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(recycAdapter);
I believe the following will do as you wish.
The were quite a few issues with code. One of the major issues is that you expected the position to correlate with the id (aka your _id column).
The position of the first item in the list is 0, unless you force/specifically set the value of 0, an alias of the rowid column (your _id column is an alias of the rowid column), the first value assigned will be 1, then likely 2, then likely 3 ...........
So at best position will be 1 less than the id.
If a row is deleted, other than the last row then position will be one less except up until the deleted row is passed and then position will be 2 less than the rowid. More deletions and an even more complex correlation between position and id. I guess somebody could come up with a fool proof conversion BUT the simpe way is to ensure that the DataModel has the vale of the respective _id column.
As such DataModel.java should be changed to include a member/variable for the id therefore the following was used :-
public class DataModel {
public String FirstName;
public String LastName;
public String country;
public long id; //<<<<<<<<<< ADDED also added gettter and setter
public DataModel() {
}
public DataModel(String firstName, String lastName, String country) {
this(firstName,lastName,country,-1);
}
//<<<<<<<<<< ADDED so ID can be set
public DataModel(String firstName, String lastName, String country, long id) {
this.FirstName = firstName;
this.LastName = lastName;
this.country = country;
this.id = id;
}
public String getFirstName() {
return FirstName;
}
public void setFirstName(String firstName) {
FirstName = firstName;
}
public String getLastName() {
return LastName;
}
public void setLastName(String lastName) {
LastName = lastName;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
}
see comments for changes
As you need to extract the id from the database, the object1 method was changed in DatabaseHelper.java (a few other changes have also been made) the following was used :-
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "workers.db";
private static final int DATABASE_VERSION =7;
SQLiteDatabase db;
public DatabaseHelper( Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
db = this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
this.db=db; //<<<<<<< WRONG PLACE as onCreate only ever runs when there is no database
final String SQL_CREATE_TBALE="CREATE TABLE " + DatabaseContractor.EmployeeDetails.TABLE_NAME + "(" + DatabaseContractor.EmployeeDetails._ID +" INTEGER PRIMARY KEY AUTOINCREMENT, "+
DatabaseContractor.EmployeeDetails.COLUMN_FIRSTNAME+" TEXT, "+ DatabaseContractor.EmployeeDetails.COLUMN_LASTNAME+" TEXT, "+ DatabaseContractor.EmployeeDetails.COLUMN_COUNTRY+" TEXT)";
db.execSQL(SQL_CREATE_TBALE);
fillquestion();
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + DatabaseContractor.EmployeeDetails.TABLE_NAME);
onCreate(db);
}
public void fillquestion(){
IntertData(new DataModel("Earth","Soil","B"));
IntertData(new DataModel("Sun","Light","B"));
IntertData(new DataModel("Moon","Rock","B"));
}
public void IntertData (DataModel data){
ContentValues contentValues = new ContentValues();
contentValues.put(DatabaseContractor.EmployeeDetails.COLUMN_FIRSTNAME,data.getFirstName());
contentValues.put(DatabaseContractor.EmployeeDetails.COLUMN_LASTNAME,data.getLastName());
contentValues.put(DatabaseContractor.EmployeeDetails.COLUMN_COUNTRY,data.country);
db.insert(DatabaseContractor.EmployeeDetails.TABLE_NAME,null,contentValues);
}
public List<DataModel> object1() {
ArrayList<DataModel> details = new ArrayList<>();
//db = getReadableDatabase(); db has already been set when database was instantiated/constructed
Cursor cursor = db.rawQuery("SELECT * FROM " + DatabaseContractor.EmployeeDetails.TABLE_NAME, null );
while (cursor.moveToNext()) {
details.add(new DataModel(
cursor.getString(cursor.getColumnIndex(DatabaseContractor.EmployeeDetails.COLUMN_FIRSTNAME)),
cursor.getString(cursor.getColumnIndex(DatabaseContractor.EmployeeDetails.COLUMN_LASTNAME)),
cursor.getString(cursor.getColumnIndex(DatabaseContractor.EmployeeDetails.COLUMN_COUNTRY)),
cursor.getLong(cursor.getColumnIndex(DatabaseContractor.EmployeeDetails._ID)) //<<<<<<<<< Added so id is available
));
}
cursor.close();
return details;
}
}
Pretty extensive changes were made to RecycAdapter.java, the following was used :-
public class RecycAdapter extends RecyclerView.Adapter<RecycAdapter.ViewHolder> {
List<DataModel> dotamodeldataArraylist;
Context context;
SQLiteDatabase db;
DatabaseHelper helper;
ContentValues contentValues;
public RecycAdapter(List<DataModel> dotamodeldataArraylist,Context context) {
this.dotamodeldataArraylist=dotamodeldataArraylist;
this.context=context;
helper = new DatabaseHelper(context);
db = helper.getWritableDatabase();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int ViewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.itemlist,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final RecycAdapter.ViewHolder holder, final int position) {
//DataModel obj3= dotamodeldataArraylist.get(position); //<<<<<<<<<< NOT NEEDED
holder.Fnam.setText(dotamodeldataArraylist.get(position).getFirstName());
holder.Lname.setText(dotamodeldataArraylist.get(position).getLastName());
holder.Country.setText(dotamodeldataArraylist.get(position).getCountry());
holder.fav.setChecked(false); //<<<<<<<<< not stored so initially set to false
holder.fav.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String newcountry = "B";
if(holder.fav.isChecked()){
if (dotamodeldataArraylist.get(position).getCountry().equals("B")) {
newcountry = "A";
}
contentValues = new ContentValues();
contentValues.put(DatabaseContractor.EmployeeDetails.COLUMN_COUNTRY, newcountry);
if (db.update(
DatabaseContractor.EmployeeDetails.TABLE_NAME,
contentValues,
DatabaseContractor.EmployeeDetails._ID +"=?",
new String[]{String.valueOf(dotamodeldataArraylist.get(position).getId())}
) > 0) {
dotamodeldataArraylist.get(position).setCountry(newcountry);
notifyItemChanged(position);
Toast.makeText(context,
"checked and updated " +
position+ dotamodeldataArraylist.get(position).getFirstName() +
" ID is " + String.valueOf(dotamodeldataArraylist.get(position).getId()),
Toast.LENGTH_LONG
).show();
} else {
Toast.makeText(context,"error" + position , Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(context,"not checked" + position , Toast.LENGTH_LONG).show();
}
}
});
}
#Override
public int getItemCount() {
return dotamodeldataArraylist.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView Fnam,Lname,Country;
CheckBox fav;
public ViewHolder(View itemView) {
super(itemView);
Fnam = itemView.findViewById(R.id.name1);
Lname = itemView.findViewById(R.id.city1);
Country = itemView.findViewById(R.id.country1);
fav = itemView.findViewById(R.id.chk);
}
}
}
lastly a few minor changes were made to Viewall.java, the following was used :-
public class Viewall extends AppCompatActivity {
RecyclerView recyclerView;
DatabaseHelper databaseHelper;
RecycAdapter recycAdapter;
List<DataModel> dotamodeldataArraylist;
Button show;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewall);
show = findViewById(R.id.view);
recyclerView = findViewById(R.id.recycle);
databaseHelper = new DatabaseHelper(this);
dotamodeldataArraylist = databaseHelper.object1();
recycAdapter = new RecycAdapter(dotamodeldataArraylist, this);
RecyclerView.LayoutManager reLayoutManager = new
LinearLayoutManager(this);
recyclerView.setLayoutManager(reLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(recycAdapter);
}
}
Result
Note the layout(s) may be different, but your's should probably work and alter the presentation accordingly
When first run :-
After clicking the checkbox for Sun
Click again and back to Country B and so on.
Note the check box isn't flipped, that's a bit of an issue as to correctly display the changed data (country) notifyItemChanged is used, which will reprocess the list and thus set the checkbox to false. You'd need to store the checkbox value somewhere (in short you should really use checkboxes in this way).
Closing the app and restarting maintains the changes made, thus confirming that the changes to the database have been made.
On top of #MiKe's code, i have just made some changes in my RecyclerAdapter inside onClickListener to save checkbox Status and added isChecked as a boolean value inside dataModel class. now its working perfectly.
holder.chkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Values = new ContentValues();
Values.put(DatabaseContractor.EmployeeDetails.COLUMN_FAVORITE,holder.chkbox.isChecked());
try{ db.update(DatabaseContractor.EmployeeDetails.TABLE_NAME,
Values,
DatabaseContractor.EmployeeDetails._ID + "=?",
new String[]{String.valueOf(dotamodeldataArraylist.get(position).getId())});
} catch (SQLException e){
Toast.makeText(context,"Error"+position,Toast.LENGTH_LONG).show();
}
}
});
Thanks again mike for your awesome guideline. Now, i can directly save checkbox status in sqlite Database.

Checking if a list view adapter contains a string

I wanna check my adapter before adding new item and if there is a duplicate item then ignore it.I tried this method but didn't work for me.
btnadd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (radioGroup.getCheckedRadioButtonId()){
case R.id.Tshirt:
radio="Tshirt";
break;
case R.id.Shoes:
radio="Shoes";
break;
default:
radio="Pants";
break;
}
if (!txtname.getText().toString().isEmpty() && !txtdes.getText().toString().isEmpty() )
list.add(new products(txtname.getText().toString(), radio, txtdes.getText().toString(), R.drawable.shop));
myadapter adapter = new myadapter(MainActivity.this, list);
lstCountries.setAdapter(adapter);
}
});
You can simply check whether your list contains a certain String and / or object already.
if(!list.contains(...) {
list.add(..);
}
You can check this thread for more information:
Check if a String is in an ArrayList of Strings
If order is not important , then you could use HashSet instead of a list, a type of SET, these are the collections that do not allow duplicate values but do not preserve insertion order too.
Java HashSet
Example usage:-
HashSet<String> set=new HashSet<String>();
set.add("Ravi");
set.add("Vijay");
set.add("Ravi");
set.add("Ajay");
//Traversing elements
Iterator<String> itr=set.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
Here is my code:
Mainactivity.java
package com.example.esi.shopapp;
import android.content.DialogInterface;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioGroup;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView lstCountries;
public Button btnadd;
private EditText txtname;
private EditText txtdes;
private RadioGroup radioGroup;
String radio = "";
private List<products> list = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lstCountries = (ListView) findViewById(R.id.lists);
btnadd = findViewById(R.id.button);
txtname =findViewById(R.id.txt_name);
txtdes =findViewById(R.id.txt_desc);
radioGroup = findViewById(R.id.categorize);
btnadd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (radioGroup.getCheckedRadioButtonId()){
case R.id.Tshirt:
radio="Tshirt";
break;
case R.id.Shoes:
radio="Shoes";
break;
default:
radio="Pants";
break;
}
if (!txtname.getText().toString().isEmpty() && !txtdes.getText().toString().isEmpty() )
if (!list.contains(txtname.getText().toString()))
list.add(new products(txtname.getText().toString(), radio, txtdes.getText().toString(), R.drawable.shop));
myadapter adapter = new myadapter(MainActivity.this, list);
lstCountries.setAdapter(adapter);
}
});
}
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.clear_form:
txtname.setText("");
txtdes.setText("");
break;
case R.id.clear_list:
lstCountries.setAdapter(null);
break;
case R.id.setting:
break;
case R.id.exit:
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("Are you sure to exit?");
builder.setCancelable(false);
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
MainActivity.this.finish();
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
break;
}
return super.onOptionsItemSelected(item);
}
}
myadapter.java
package com.example.esi.shopapp;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class myadapter extends BaseAdapter {
private Context context;
private List<products> list;
public myadapter(Context context, List<products> list) {
this.context = context;
this.list = list;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup root) {
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_item_layout, root, false);
}
TextView txtCountryName = convertView.findViewById(R.id.txt_product_name);
TextView txtCountryContinent = convertView.findViewById(R.id.txt_product_desc);
TextView txtype = convertView.findViewById(R.id.txt_product_type);
ImageView imgCountryFlag = convertView.findViewById(R.id.img_country_flag);
txtCountryName.setText(list.get(position).getName());
txtCountryContinent.setText(list.get(position).getDescribe());
txtype.setText(list.get(position).getType());
imgCountryFlag.setImageResource(list.get(position).getFlag());
return convertView;
}
}
products.java
package com.example.esi.shopapp;
public class products {
private String name;
private String describe;
private String type;
private int flag;
public products(String name, String describe, String type, int flag) {
this.name = name;
this.describe = describe;
this.type = type;
this.flag = flag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Your logic is wrong. You are creating a new instance of the adapter in each item click. You should move
myadapter adapter = new myadapter(MainActivity.this, list);
lstCountries.setAdapter(adapter);
to the onCreate method. Make adapter a global variable and
change your current code to this.
btnadd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (radioGroup.getCheckedRadioButtonId()) {
case R.id.Tshirt:
radio = "Tshirt";
break;
case R.id.Shoes:
radio = "Shoes";
break;
default:
radio = "Pants";
break;
}
if (!txtname.getText().toString().isEmpty() && !txtdes.getText().toString().isEmpty()) {
products product = new products(txtname.getText().toString(), radio, txtdes.getText().toString(), R.drawable.shop)
if (!list.contains(product)) {
list.add(product);
adapter.notifyDataSetChanged();
}
}
}
});

Saving Object in SQLite Database, no exception - Android

I'm getting crazy right now with a problem, while saving an object in a SQLite database. I've got an UI in which you can insert some data in TextEdits and Checkboxes.
This is the BaseListFragment, which handles the UI for different types:
package de.financeplanner.ui.fragment;
import android.app.ListFragment;
import android.os.Bundle;
import android.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import java.util.ArrayList;
import de.financeplanner.R;
import de.financeplanner.constant.TabConstants;
import de.financeplanner.model.Category;
import de.financeplanner.model.Finance;
import de.financeplanner.model.Model;
import de.financeplanner.util.adapter.list.CategoryListAdapter;
import de.financeplanner.util.adapter.list.FinanceListAdapter;
import de.financeplanner.util.db.DBHelperCategory;
import de.financeplanner.util.db.DBHelperFinance;
/**
* Created by Christian on 20.01.2017.
*/
public class BaseListFragment extends ListFragment implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener {
private ArrayList<? extends Model> listData;
private short type;
public static BaseListFragment newInstance(short type){
BaseListFragment fragment = new BaseListFragment();
Bundle arguments = new Bundle();
arguments.putShort("type", type);
fragment.setArguments(arguments);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_base_list, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
type = getArguments().getShort("type");
listData = loadListData(type);
initList();
initAddButton();
// getListView().setOnItemClickListener(this);
}
private ArrayList<? extends Model> loadListData(short type){
switch (type) {
case TabConstants.OVERVIEW:
return loadFinances();
case TabConstants.REVENUE:
return loadRevenues();
case TabConstants.EXPENSE:
return loadExpenses();
case TabConstants.CATEGORY:
return loadCategories();
}
return null;
}
private ArrayList<Finance> loadFinances() {
DBHelperFinance dbHelper = new DBHelperFinance(getContext());
return dbHelper.getAll();
}
private ArrayList<Finance> loadRevenues() {
DBHelperFinance dbHelper = new DBHelperFinance(getContext());
return dbHelper.getRevenues();
}
private ArrayList<Finance> loadExpenses() {
DBHelperFinance dbHelper = new DBHelperFinance(getContext());
return dbHelper.getExpanse();
}
private ArrayList<Category> loadCategories() {
DBHelperCategory dbHelper = new DBHelperCategory(getContext());
return dbHelper.getAll();
}
private void initList() {
ArrayAdapter adapter = null;
if (listData != null) {
if (type != TabConstants.CATEGORY) {
adapter = new FinanceListAdapter(getContext(), (ArrayList<Finance>)listData);
}else{
adapter = new CategoryListAdapter(getContext(), (ArrayList<Category>)listData);
}
setListAdapter(adapter);
}
}
private void initAddButton() {
ImageButton addButton = (ImageButton) getActivity().findViewById(R.id.add_button);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentTransaction trans = getFragmentManager().beginTransaction();
if(type != TabConstants.CATEGORY){
trans.replace(R.id.fragment_container, AddFinanceFragment.newInstance());
trans.addToBackStack(null).commit();
}else{
trans.replace(R.id.fragment_container, AddCategoryFragment.newInstance());
trans.addToBackStack(null).commit();
}
}
});
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
}
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
return false;
}
}
For explanation:
You cann choose 4 different tabs (overview, revenue, expense and category). The UI is every time the same, only the data inside changes.
Now, when I click on the addButton inside the category tab and insert data, the data is saved inside the database and the listview is correctly updated.
This is the called method to save the category.
private void onSaveRequest(){
Category category = new Category();
category.setTitle(title.getText().toString());
category.setDescription(description.getText().toString());
DBHelperCategory dbHelper = new DBHelperCategory(getContext());
dbHelper.saveOrUpdate(category);
getFragmentManager().popBackStack();
}
And this is the DBHelper method, which is called to save the category:
public void saveOrUpdate(Category category){
ContentValues values = new ContentValues();
values.put("title", category.getTitle());
values.put("description", category.getDescription());
if(category.getId() == 0){
save(values);
} else {
update(values);
}
}
private void save(ContentValues values){
SQLiteDatabase db = getWritableDatabase();
db.insert("category", null, values);
}
This is the method, to get categories from the database:
public ArrayList<Category> getAll(){
ArrayList<Category> categories = new ArrayList<Category>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor rows = db.rawQuery(GET_ALL_QUERY, null);
rows.moveToFirst();
while(!rows.isAfterLast()){
Category category = new Category();
category.setId(rows.getInt(0));
category.setTitle(rows.getString(1));
category.setDescription(rows.getString(2));
categories.add(category);
rows.moveToNext();
}
return categories;
}
The problem is, when I click the addButton inside the overview, revenue or expense tab, no data is insert into database and the listview is not updated.
And this the method, which is called, when the saveButton is pressed:
private void onSaveRequest(){
Finance finance = new Finance();
finance.setTitle(title.getText().toString());
finance.setCategoryID(0);
finance.setDescription(description.getText().toString());
finance.setPayment(Double.parseDouble(payment.getText().toString()));
finance.setExpense(expense.isChecked());
finance.setDate(date.getText().toString());
DBHelperFinance dbHelper = new DBHelperFinance(getContext());
dbHelper.saveOrUpdate(finance);
getFragmentManager().popBackStack();
}
And this is the method inside the DBHelper, which should insert the data in the database:
public void saveOrUpdate(Finance finance){
ContentValues values = new ContentValues();
values.put("title", finance.getTitle());
values.put("categoryID", finance.getCategoryID());
values.put("description", finance.getDescription());
values.put("payment", finance.getPayment());
values.put("expense", finance.isExpense() ? 1 : 0);
values.put("date", finance.getDate());
if(finance.getId() == 0){
save(values);
} else {
update(values);
}
}
private void save(ContentValues values){
SQLiteDatabase db = getWritableDatabase();
db.insert("finance", null, values);
}
This are the methods, to get the finances from the database:
private ArrayList<Finance> getAll(short condition){
ArrayList<Finance> finances = new ArrayList<Finance>();
SQLiteDatabase db = this.getReadableDatabase();
String whereClause = new String();
final String join = " INNER JOIN CATEGORY ON FINANCE.categoryID = CATEGORY.ID ";
if(condition != 0){
whereClause = condition == 1 ? " WHERE EXPENSE = 0 " : "WHERE EXPENSE = 1";
}
String query = GET_ALL_QUERY + join + whereClause;
Cursor rows = db.rawQuery(query, null);
rows.moveToFirst();
while(!rows.isAfterLast()){
Finance finance = new Finance();
finance.setId(rows.getInt(0));
finance.setTitle(rows.getString(1));
finance.setCategoryID(rows.getInt(2));
finance.setCategory(rows.getString(3));
finance.setDescription(rows.getString(4));
finance.setPayment(rows.getDouble(5));
finance.setExpense(rows.getInt(6) == 1);
finance.setDate(rows.getString(7));
finances.add(finance);
rows.moveToNext();
}
return finances;
}
To complete this, here is the super class for every DBHelper:
package de.financeplanner.util.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by Christian on 20.01.2017.
*/
public class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "financeDB";
public DBHelper(Context context) {
super(context, DATABASE_NAME , null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("CREATE TABLE FINANCE " +
"(ID INTEGER PRIMARY KEY AUTOINCREMENT, TITLE VARCHAR(50), CATEGORYID INTEGER," +
"DESCRIPTION VARCHAR(240), PAYMENT DECIMAL(8,2), EXPENSE BOOLEAN," +
"DATE STRING); ");
db.execSQL("CREATE TABLE CATEGORY " +
"(ID INTEGER PRIMARY KEY AUTOINCREMENT, TITLE VARCHAR(50), DESCRIPTION VARCHAR(240));");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXISTS FINANCE");
db.execSQL("DROP TABLE IF EXISTS CATEGORY");
onCreate(db);
}
}
I've debugged the app and can't find anything wrong. (Just, that every ArrayList is empty, so nothing is insert into database). Even there is no exception or other error shown, so I think the Syntax and the fields for the database is also right. Strange is also, that in the morning everything worked and I really don't know, what I've changed that everything goes wrong right now.

RecyclerView does not update or refresh when calling notifyDataSetChanged()

I have an app that uses RecyclerView. When user selects "Add New Row" from the options menu, I output a test message to the screen, and some values get appended to two different ArrayLists. That part is working great, as I have confirmed these values are successfully added by looking at the ArrayList values using the debugger.
Anyhow I am not able to get the RecyclerView to redraw the screen and show the new information. My attempt to redraw / update the screen is by using this code (line 78 of MainActivity.java):
//call notify data set changed method for the adapter
adapter.notifyDataSetChanged();
Maybe I am not calling notifyDataSetChanged on the same adapter that actually is used for RecycleView??
Here is the complete code for MainActivity.java (see options menu code at end):
package com.joshbgold.ironmax;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final int ADD_ROW = 1; //used for case statement statement to select menu item
private RecyclerView recyclerView;
public Exercises exercises = new Exercises();
public ExerciseRow adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
assert getSupportActionBar() != null;
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setIcon(R.mipmap.barbell);
actionBar.setTitle(" " + "Iron Max");
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
//ExerciseRow adapter = new ExerciseRow(this);
adapter = new ExerciseRow(this);
recyclerView.setAdapter(adapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
/* MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.add_row, menu);
return super.onCreateOptionsMenu(menu);*/
menu.add(0, ADD_ROW, 0, "Add New Row");
menu.getItem(0).setIcon(R.drawable.plus);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.getItem(0).setIcon(R.drawable.plus);
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int length;
switch (item.getItemId()) {
case 1:
Toast msg = Toast.makeText(MainActivity.this, "Test code for adding an exercise", Toast.LENGTH_LONG);
msg.show();
exercises.addExercise("Some exercise");
exercises.addPersonalBest(500);
length = exercises.getExercisesArrayLength();
//call notify data set changed method for the adapter
adapter.notifyItemInserted(length - 1);
adapter.notifyDataSetChanged();
return super.onOptionsItemSelected(item);
default:
return super.onOptionsItemSelected(item);
}
}
}
Here is Exercises.java:
import android.support.v7.app.AppCompatActivity;
import java.util.ArrayList;
public class Exercises extends AppCompatActivity {
public ArrayList<String> exercisesArrayList = new ArrayList<>(); //stores all the lifts
private ArrayList<Integer> personalBestsArrayList = new ArrayList<>(); //stores personal bests in pounds
public ArrayList<String> getExercisesArray() { //returns the whole exercises arraylist
return exercisesArrayList;
}
public ArrayList<Integer> getPersonalBests() { //returns the whole personal bests arraylist
return personalBestsArrayList;
}
public String getExercise(int position) { //returns individual exercise from array
return exercisesArrayList.get(position);
}
public void addExercise(String exercise) {
exercisesArrayList.add(exercise);
}
public void removeExercise(int position) {
exercisesArrayList.remove(position);
}
public void editExercise(int position, String exercise) {
exercisesArrayList.set(position, exercise);
}
public int getExercisesArrayLength() {
return exercisesArrayList.size();
}
public Integer getPersonalBest(int position) { //returns individual personal best from array
return personalBestsArrayList.get(position);
}
public void addPersonalBest(int personalBest) {
personalBestsArrayList.add(personalBest);
}
public void removePersonalBest(int position) {
personalBestsArrayList.remove(position);
}
public void editPersonalBest(int position, int personalBest) {
personalBestsArrayList.set(position, personalBest);
}
public Exercises() {} //constructor
}
Here is ExerciseRow.java:
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class ExerciseRow extends RecyclerView.Adapter<ExerciseRow.ExerciseViewHolder> {
String exerciseName = "burpee";
String exercisePR = "100"; // user's personal record for this exercise in pounds
private Context context;
Exercises exercises = new Exercises();
public ExerciseRow(Context context) {
this.context = context;
}
#Override
public ExerciseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.exercise_list_item, parent, false);
return new ExerciseViewHolder(view);
}
#Override
public void onBindViewHolder(ExerciseViewHolder holder, int position) {
ArrayList<String> exercisesArray = exercises.getExercisesArray();
holder.bindExercises(exercisesArray.get(position));
}
#Override
public int getItemCount() {
return exercises.getExercisesArrayLength();
}
public class ExerciseViewHolder extends RecyclerView.ViewHolder {
public TextView exerciseNameTextView;
public TextView personalRecordTextView;
public ImageView edit_Icon;
public ImageView percentages_Icon;
public ImageView trash_Icon;
public ImageView plus_icon;
public ImageView facebook_icon;
public ImageView twitter_icon;
public ExerciseViewHolder(View itemView) {
super(itemView);
exerciseNameTextView = (TextView) itemView.findViewById(R.id.list_item_exercise_textview);
personalRecordTextView = (TextView) itemView.findViewById(R.id.list_item_amount_textview);
edit_Icon = (ImageView) itemView.findViewById(R.id.list_item_pencil);
percentages_Icon = (ImageView) itemView.findViewById(R.id.list_item_percent);
trash_Icon = (ImageView) itemView.findViewById(R.id.list_item_trash);
plus_icon = (ImageView) itemView.findViewById(R.id.list_item_plus);
facebook_icon = (ImageView) itemView.findViewById(R.id.list_item_facebook);
twitter_icon = (ImageView) itemView.findViewById(R.id.list_item_twitter);
View.OnClickListener plus = new View.OnClickListener() {
#Override
public void onClick(View view) {
// allow user to add a new exercise and personal best
exercises.addExercise("Some exercise");
exercises.addPersonalBest(500);
notifyDataSetChanged();
}
};
View.OnClickListener edit = new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = getLayoutPosition(); //use getAdapterPosition() if getLayoutPosition causes a problem
if (position == 0) { //prevent user from deleting the first row.
Toast.makeText(context, "Sorry, example row cannot be edited.", Toast.LENGTH_LONG).show();
}
else{
editRow(position); //edit the row at the current position
notifyDataSetChanged();
}
}
};
View.OnClickListener percentages = new View.OnClickListener() {
#Override
public void onClick(View view) {
//get exercise name
exerciseName = exerciseNameTextView.getText().toString();
exercisePR = personalRecordTextView.getText().toString();
//show percentages layout
startPercentagesActivity(exerciseName, exercisePR);
}
};
View.OnClickListener trash = new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = getLayoutPosition(); //use getAdapterPosition() if getLayoutPosition causes a problem
if (position == 0) { //prevent user from deleting the first row.
Toast.makeText(context, "Sorry, example row cannot be deleted.", Toast.LENGTH_LONG).show();
} else {
exercises.removeExercise(position);
exercises.removePersonalBest(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, exercises.getExercisesArrayLength());
}
}
};
plus_icon.setOnClickListener(plus);
edit_Icon.setOnClickListener(edit);
percentages_Icon.setOnClickListener(percentages);
trash_Icon.setOnClickListener(trash);
}
public void bindExercises(String exercises) {
Exercises exercisesObject = new Exercises();
exerciseNameTextView.setText(exercisesObject.getExercise(getAdapterPosition()));
personalRecordTextView.setText((exercisesObject.getPersonalBest(getAdapterPosition())).toString() + " pounds");
}
}
private void startPercentagesActivity(String some_exercise, String personal_record) {
Intent intent = new Intent(context, PercentagesActivity.class);
intent.putExtra("exerciseName", some_exercise);
intent.putExtra("personalRecord", personal_record);
context.startActivity(intent);
}
protected void editRow(final int position) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
//text_entry is an Layout XML file containing two text field to display in alert dialog
final View textEntryView = layoutInflater.inflate(R.layout.text_entry, null);
final EditText liftName = (EditText) textEntryView.findViewById(R.id.liftNameEditText);
final EditText PersonalBestInPounds = (EditText) textEntryView.findViewById(R.id.personalBestEditText);
final AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setIcon(R.mipmap.barbell)
.setTitle("Please make your changes:")
.setView(textEntryView)
.setPositiveButton("Save",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
//retrieve the user's input
String lift = liftName.getText().toString();
int personalBest = Integer.parseInt(PersonalBestInPounds.getText().toString());
//save the user's input to the appropriate arrays
exercises.editExercise(position, lift);
exercises.editPersonalBest(position, personalBest);
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
}
});
alert.show();
}
}
If you have read this far, I give you credit! Please understand I am completely new to RecyclerView, so whatever error(s) I have made could be something quite simple even.
The issue is that you have two different instances of ExercisesOne in MainActivity and another in ExerciseRow You are adding the data to the wrong one.
A few other things that may help you along your way.
Exercises Should not extend AppCompatActivity (or really anything as far as I can tell)
You should avoid saving a reference to the context (as you are doing in Exercises) it can great memory issues. Instead try one of the following.
A. Use the context to get the LayoutInflater in the constructor
B. Call parent.getContext() in onCreateViewHolder

Categories

Resources