concurrency in database opener - java

I have no idea how to do proper concurrent operations, so I just tried to adjust my code.
And totally lost in concurrency in constructor and concurrency with static, final fields...
public static class Connection {
private final CustomerDatabaseOpenHelper mHelper;
private SQLiteDatabase mDatabase;
private String mUserId;
private AtomicInteger mOpenCounter;
public Connection(Context context, String userId) {
mHelper = CustomerDatabaseOpenHelper.getInstance(context, DB_NAME, null, DB_VERSION);
mOpenCounter = mHelper.mOpenCounter;
mUserId = userId;
}
public void open() throws SQLException {
// open database in reading/writing mode
int value = mOpenCounter.incrementAndGet();
if(value == 1 || mDatabase==null || mUserId ==null) {
// Opening new database
Log.v("tugce","open new customer db");
mDatabase = mHelper.getWritableDatabase();
}
};
public void close() {
int value = mOpenCounter.decrementAndGet();
if(value == 0) {
// Closing database
if (mDatabase != null) {
try {
Log.v("tugce","close customer db");
mDatabase.close();
mDatabase = null;
mUserId = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//my openhelper class
public class CustomerDatabaseOpenHelper extends SQLiteOpenHelper{
public AtomicInteger mOpenCounter = new AtomicInteger();
public static CustomerDatabaseOpenHelper mInstance;
public static synchronized CustomerDatabaseOpenHelper getInstance(Context context, String name,
CursorFactory factory, int version) {
if (mInstance == null) {
mInstance = new CustomerDatabaseOpenHelper(context, name, factory, version);
}
return mInstance;
}
private CustomerDatabaseOpenHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
}
This is how I am using in threads:
class MyGetPlanedCallList extends
AsyncTask<Object, Object, List<MyPlannedCallListItem>> {
CustomerDatabase.Connection mDbCon = new CustomerDatabase.Connection(InstanceActivity.this, mUserId);
#Override
protected void onPreExecute() {
mDbCon.open();
}
#Override
protected List<MyPlannedCallListItem> doInBackground(Object... params) {
mDbCon.doSomeStuff();
}
#Override
protected void onPostExecute(List<MyPlannedCallListItem> result) {
mDbCon.close();
}
#Override
protected void onCancelled() {
if (mDbCon != null)
mDbCon.close();
}
}
What I want is, exactly same db shouldn't be closed if some other instance is working on it.
Any help would be appreciated.

Related

Implement AsyncTask when adding rows of data to multiple tables

I have created a screen that show a TextView and a ProgressBar. The ProgressBar represent to database creation and adding 1000++ data into SQLite using GSON. In order to achieve this, I have created three different files, LocalDBHelper (which is my db setup), GSONHandler (convert my JSON file into SQLite) and Loading (for my AsyncTask).
My problem is, that my ProgressBar is static, and it didn't show the progress of adding the data. I'm new to android development and clueless in proceeding with my code.
MainActivity.java
public class MainActivity extends AppCompatActivity implements Loading.LoadingTaskFinishedListener {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setupdb_delete);
LocalDBHelper mydb = LocalDBHelper.newInstance(this);
//check if db exist, delete db if exist
if (doesDatabaseExist(mydb.getDatabaseName()))
this.deleteDatabase(mydb.getDatabaseName());
ProgressBar progressBar = findViewById(R.id.progressBar);
new Loading(progressBar, this, this).execute("");
}
#Override
public void onTaskFinished() {
finish();
}
public boolean doesDatabaseExist(String databaseName) {
File dbFile = this.getDatabasePath(databaseName);
return dbFile.exists();
}
}
Loading.java
public class Loading extends AsyncTask<String, Integer, Integer> {
public interface LoadingTaskFinishedListener {
void onTaskFinished();
}
private LocalDBHelper mydb = null;
private final ProgressBar progressBar;
private Context mContext;
private final LoadingTaskFinishedListener finishedListener;
public Loading(ProgressBar progressBar, LoadingTaskFinishedListener finishedListener, Context context) {
this.progressBar = progressBar;
this.finishedListener = finishedListener;
this.mydb = LocalDBHelper.newInstance(context);
mContext = context;
}
#Override
protected Integer doInBackground(String... params) {
SQLiteDatabase sqLiteDatabase = mydb.getWritableDatabase();
GSONHandler.newInstance(mContext, sqLiteDatabase);
return 1234;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);
}
#Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
finishedListener.onTaskFinished();
}
}
GSONHandler.java
public class GSONHandler {
static final String TAG = GSONHandler.class.getSimpleName();
private Context context;
private LocalDBHelper mydb;
private SQLiteDatabase sqLiteDatabase;
private static GSONHandler mGsonHandler = null;
public static GSONHandler newInstance(Context context, SQLiteDatabase sqLiteDatabase){
if (mGsonHandler == null){
mGsonHandler = new GSONHandler(context.getApplicationContext(), sqLiteDatabase);
}
return mGsonHandler;
}
private GSONHandler(Context context, SQLiteDatabase sqLiteDatabase) {
this.context = context;
this.sqLiteDatabase = sqLiteDatabase;
onCreate();
}
//assign json data to tables
private void onCreate() {
//get local json and save it to db
premiseCategoryMasterSetup();
premiseCategorySetup();
inspcTypeSetup();
inspcStatusSetup();
stateSetup();
areaSetup();
districtSetup();
analysisGroupSetup();
analysisSubGroup();
parameterSetup();
subParameterSetup();
identificationSetup();
premiseCertliSetup();
txn_premiseSetup();
prosecutionOtherSetup();
txn_layoutSectionSetup();
txn_layoutCardSetup();
txn_layoutInputFieldSetup();
}
private void areaSetup() {
Log.d(TAG, "areaSetup");
InputStream inputStream = context.getResources().openRawResource(R.raw.ref_area);
String jsonString = readJsonFile(inputStream);
Gson gson = new Gson();
List<Area> areaList = Arrays.asList(gson.fromJson(jsonString, Area[].class));
for (Area area : areaList)
{
if(sqLiteDatabase != null) {
ContentValues values = new ContentValues();
values.put(Constants.COLUMN_AREA_ID, area.getAreaId());
values.put(Constants.COLUMN_AREA_CODE, area.getAreaCode());
values.put(Constants.COLUMN_AREA_NAME, area.getAreaName());
values.put(Constants.COLUMN_ACTIVE, area.getActive());
values.put(Constants.COLUMN_FK_STATE_ID, area.getFk_stateId());
long id = sqLiteDatabase.insertOrThrow(Constants.REF_AREA_TABLE,
null, values);
}
}
}
....
private String readJsonFile(InputStream inputStream) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte bufferByte[] = new byte[1024];
int length;
try {
while ((length = inputStream.read(bufferByte)) != -1) {
outputStream.write(bufferByte, 0 , length);
}
outputStream.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return outputStream.toString();
}
}
You are setting the progress of the progress bar inside onProgressUpdate method but it is never called. To call onProgressUpdate method, you need to call publishProgress method inside doInBackground method. The onProgressUpdate method is invoked on the UI thread after the call to publishProgress method.
In doInBackground() call publishProgress(); method to display and update progressbar. Hope this will Help.

Adding Data to SQLiteDatabase

I have a SQLite DB file in assets which is then imported in the application.
The select query works fine and shows the results but at the same time if I try to insert data into the table it does not work. I get no error so that I can identify the problem.
DatabaseHelper class: addProject() method is to insert data.
public class DatabaseHelper extends SQLiteOpenHelper {
private static final int DB_VERSION=1;
private static String DB_PATH="";
private static final String DB_NAME="AndroidProject.sqlite";
//Projects Table attrib
String TABLE_PROJECT="Project";
String KEY_PROJECT_ID = "_id";
String KEY_PROJECT_NAME = "project_name";
String KEY_PROJECT_DESC = "project_desc";
String KEY_PROJECT_TYPE = "project_type";
String KEY_PROJECT_START_DATE = "start_date";
String KEY_PROJECT_END_DATE = "end_date";
private SQLiteDatabase myDatabase;
private final Context myContext;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
if (Build.VERSION.SDK_INT>=15){
DB_PATH=context.getApplicationInfo().dataDir + "/databases/";
}
else {
DB_PATH= Environment.getDataDirectory() + "/data/" + context.getPackageName() + "/databases/";
}
this.myContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void checkAndCopyDatabase(){
boolean doExists=checkDatabase();
if (doExists){
Log.d("TAG", "Database alredy exists");
}
else{
this.getReadableDatabase();
}
try {
copyDatabase();
} catch (IOException e) {
e.printStackTrace();
Log.d("TAG", "Error Copying DATABASE");
}
}
public boolean checkDatabase(){
SQLiteDatabase checkDB=null;
try {
String myPath=DB_PATH+DB_NAME;
checkDB=SQLiteDatabase.openDatabase(myPath,null,SQLiteDatabase.OPEN_READWRITE);
}catch (SQLiteException e){
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
public void copyDatabase() throws IOException {
InputStream myInput = myContext.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length=myInput.read(buffer))>0){
myOutput.write(buffer,0,length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDatabase(){
String myPath = DB_PATH + DB_NAME;
myDatabase=SQLiteDatabase.openDatabase(myPath,null,SQLiteDatabase.OPEN_READWRITE);
}
public synchronized void close(){
if (myDatabase != null){
myDatabase.close();
}
super.close();
}
public Cursor QueryData(String query){
return myDatabase.rawQuery(query,null);
}
public void addProject(SqlProjects blog){
//SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_PROJECT_NAME, blog.get_project_name());
values.put(KEY_PROJECT_DESC, blog.get_project_desc());
values.put(KEY_PROJECT_TYPE, blog.get_project_type());
values.put(KEY_PROJECT_START_DATE, blog.get_project_start_date());
values.put(KEY_PROJECT_END_DATE, blog.get_project_end_date());
try {
Log.d("TAG", "Adding data");
myDatabase.insertOrThrow(TABLE_PROJECT, null, values);
} catch (SQLiteException e) {
e.printStackTrace();
}
myDatabase.close();
}
}
SqlProjects class Constructor, getters and setters
public class SqlProjects {
private DatabaseHelper helper;
int _id;
String _project_name, _project_desc,_project_type;
String _project_start_date,_project_end_date;
public SqlProjects() {
}
public SqlProjects(String _project_name, String _project_desc, String _project_type, String _project_start_date, String _project_end_date) {
this._project_name = _project_name;
this._project_desc = _project_desc;
this._project_type = _project_type;
this._project_start_date = _project_start_date;
this._project_end_date = _project_end_date;
}
public SqlProjects(int _id, String _project_name, String _project_desc, String _project_type, String _project_start_date, String _project_end_date) {
this._id = _id;
this._project_name = _project_name;
this._project_desc = _project_desc;
this._project_type = _project_type;
this._project_start_date = _project_start_date;
this._project_end_date = _project_end_date;
}
public int get_project_id() {
return _id;
}
public void set_project_id(int _project_id) {
this._id = _project_id;
}
public String get_project_name() {
return _project_name;
}
public void set_project_name(String _project_name) {
this._project_name = _project_name;
}
public String get_project_desc() {
return _project_desc;
}
public void set_project_desc(String _project_desc) {
this._project_desc = _project_desc;
}
public String get_project_type() {
return _project_type;
}
public void set_project_type(String _project_type) {
this._project_type = _project_type;
}
public String get_project_start_date() {
return _project_start_date;
}
public void set_project_start_date(String _project_start_date) {
this._project_start_date = _project_start_date;
}
public String get_project_end_date() {
return _project_end_date;
}
public void set_project_end_date(String _project_end_date) {
this._project_end_date = _project_end_date;
}
}
Main Class
final DatabaseHelper db = new DatabaseHelper(Add_Project.this);
btnAddProjects.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!(TextUtils.isEmpty(editName.getText().toString())) && !(TextUtils.isEmpty(editDesc.getText().toString())) && !(tvStartDate.getText().equals("")) && !(tvEndDate.getText().equals(""))) {
db.addProject(new SqlProjects(editName.getText().toString(), editDesc.getText().toString(), editType.getSelectedItem().toString(), tvStartDate.getText().toString(), tvEndDate.getText().toString()));
editName.setText("");
editDesc.setText("");
tvStartDate.setText("");
tvEndDate.setText("");
Toast.makeText(getApplicationContext(), "Added Successfully", Toast.LENGTH_SHORT).show();
onBackPressed();
}
}
});
I think you have forgot to open the database before insert operation.
btnAddProjects.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!(TextUtils.isEmpty(editName.getText().toString())) && !(TextUtils.isEmpty(editDesc.getText().toString())) && !(tvStartDate.getText().equals("")) && !(tvEndDate.getText().equals(""))) {
//open db before any operation
db.openDatabase();
db.addProject(new SqlProjects(editName.getText().toString(), editDesc.getText().toString(), editType.getSelectedItem().toString(), tvStartDate.getText().toString(), tvEndDate.getText().toString()));
editName.setText("");
editDesc.setText("");
tvStartDate.setText("");
tvEndDate.setText("");
Toast.makeText(getApplicationContext(), "Added Successfully", Toast.LENGTH_SHORT).show();
onBackPressed();
}
}
});
Seems like the issue anyways check it out!

how to pass Position wise object data one activity to another using recyclerview and databse in android

I have create the recycerview and this recycerview display the Person image ,person name and + button when i have press + button change the button image like true.and after recycerview bottom one button this button click all data show the next activity..
My Adapter
public class BuildCustomAdapter extends RecyclerView.Adapter<BuildCustomAdapter.MyViewHolder> implements Filterable {
private List<People> peopleList;
private List<People> peopleListCopy;
private ItemFilter mFilter = new ItemFilter();
public BuildCustomAdapter(List<People> buildList) {
this.peopleList = buildList;
this.peopleListCopy = new ArrayList<>();
peopleListCopy.addAll(buildList);
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.build_list_row, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
People people = peopleList.get(position);
byte[] decodedString = Base64.decode(people.getPeopleImage(), Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
holder.ivPeopleImage.setImageBitmap(decodedByte);
holder.tvPersonName.setText(people.getPeopleName());
holder.button.setSelected(people.isSelected());
holder.button.setOnClickListener(new onSelectListener(position));
}
#Override
public int getItemCount() {
return peopleList.size();
}
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ItemFilter();
}
return mFilter;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
// public ImageView ivPeopleImage;
public TextView tvPersonName;
public Button button;
public CircularImageView ivPeopleImage;
public MyViewHolder(View itemView) {
super(itemView);
ivPeopleImage = (CircularImageView) itemView.findViewById(R.id.ivPerson);
tvPersonName = (TextView) itemView.findViewById(R.id.tvPersonName);
button = (Button) itemView.findViewById(R.id.addbn);
}
}
private class ItemFilter extends Filter {
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
List<People> filterList = new ArrayList<>();
for (int i = 0; i < peopleListCopy.size(); i++) {
if ((peopleListCopy.get(i).getPeopleName().toUpperCase())
.contains(constraint.toString().toUpperCase())) {
People peopleName = peopleListCopy.get(i);
filterList.add(peopleName);
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = peopleListCopy.size();
results.values = peopleListCopy;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
peopleList = (List<People>) results.values;
notifyDataSetChanged();
}
}
private class onSelectListener implements View.OnClickListener {
int mPosition;
public onSelectListener(int position) {
mPosition = position;
}
#Override
public void onClick(View view) {
view.setSelected(!view.isSelected());
People people = peopleList.get(mPosition);
people.setSelected(!people.isSelected());
notifyDataSetChanged();
}
}
Activity
public class BulidActivity extends AppCompatActivity {
private List<People> peopleList = new ArrayList<>();
private List<People> peopleListCopy = new ArrayList<>();
private RecyclerView recyclerView;
private BuildCustomAdapter buildCustomAdapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bulid);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
BuildData();
peopleListCopy.addAll(peopleList);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
buildCustomAdapter = new BuildCustomAdapter(peopleList);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(buildCustomAdapter);
AddTxt();
BtnBuildNow();
}
private void BtnBuildNow() {
Button btnnuildnow = (Button) findViewById(R.id.btn_build_now);
btnnuildnow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(BulidActivity.this, AlertList.class);
startActivity(intent);
}
});
}
private void AddTxt() {
EditText editTxt = (EditText) findViewById(R.id.etSearch);
editTxt.setTextColor(Color.WHITE);
editTxt.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.setFocusable(true);
v.setFocusableInTouchMode(true);
return false;
}
});
editTxt.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() <= 0) {
peopleList.clear();
peopleList.addAll(peopleListCopy);
recyclerView.setAdapter(null);
buildCustomAdapter = new BuildCustomAdapter(peopleList);
recyclerView.setAdapter(buildCustomAdapter);
} else {
buildCustomAdapter.getFilter().filter(s.toString());
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
private List<People> BuildData() {
DataBaseHelper db = new DataBaseHelper(getApplicationContext());
try {
db.createDataBase();
} catch (IOException ioe) {
throw new Error("Unable to create database");
}
if (db.open()) {
peopleList = db.getPeople();
}
return peopleList;
}
Model class
public class People implements Serializable {
private String peopleImage;
private String peopleName;
private boolean selected;
public void setPeopleName(String peopleName) {
this.peopleName = peopleName;
}
public String getPeopleName() {
return peopleName;
}
public void setPeopleImage(String peopleImage) {
this.peopleImage = peopleImage;
}
public String getPeopleImage() {
return peopleImage;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
DatabaseHelper.class
public class DataBaseHelper extends SQLiteOpenHelper {
private static final String DB_PATH = "/data/data/databasename/databases/";
private static final String DB_NAME = "alertme.db";
private final String TABLE_PEOPLE = "people";
private final String TABLE_CATEGORY = "category";
private final String CATEGORY_NAME = "name";
private final String ID = "id";
private final String CATEGORY_ID = "category_id";
private final String PEOPLE_IMAGE = "image";
private final String PEOPLE_NAME = "name";
private SQLiteDatabase myDataBase;
private final Context myContext;
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, 1);
this.myContext = context;
}
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (dbExist) {
} else {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
private void copyDataBase() throws IOException {
InputStream myInput = myContext.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
public boolean open() {
try {
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
return true;
} catch (SQLException sqle) {
myDataBase = null;
return false;
}
}
public List<People> getPeople(String category_id) {
List<People> peoples = new ArrayList<>();
try {
SQLiteDatabase db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READWRITE);
Cursor cursor = db.rawQuery("select * from people where category_id = " + category_id, null);
while (cursor.moveToNext()) {
String peopleName = cursor.getString(cursor.getColumnIndex(PEOPLE_NAME));
String peopleImage = cursor.getString(cursor.getColumnIndex(PEOPLE_IMAGE));
People people = new People();
people.setPeopleName(peopleName);
people.setPeopleImage(peopleImage);
peoples.add(people);
}
} catch (Exception e) {
Log.d("DB", e.getMessage());
}
return peoples;
}
public List<Category> getCategory() {
List<Category> categoryList = new ArrayList<>();
try {
String query = " SELECT * FROM " + TABLE_CATEGORY;
SQLiteDatabase db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READWRITE);
Cursor cursor = db.rawQuery(query, null);
while (cursor.moveToNext()) {
int categoryID = cursor.getInt(cursor.getColumnIndex(ID));
String categoryName = cursor.getString(cursor.getColumnIndex(CATEGORY_NAME));
Category category = new Category();
category.setId(categoryID);
category.setCategoryName(categoryName);
categoryList.add(category);
}
} catch (Exception e) {
Log.d("DB", e.getMessage());
}
return categoryList;
}
#Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
First you should implement Serializable interface in your Build model class like this :-
public class Build implements Serializable{
//Content will be as it is
}
Change your clickListener like this :-
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
build.setSelected(!build.isSelected());
if (build.isSelected()) {
holder.button.setBackgroundResource(R.drawable.selected_true_icon_new);
Intent intent = new Intent(context, youractivity.class)
intenet.putExtra("build",build);
context.startActivity(intent);
} else
holder.button.setBackgroundResource(R.drawable.add_button_icon);
}
});
In the onCreate method of receiving activity write this :-
Build build = (Build) getIntent().getSerializableExtra("build");
Add Intent in below Method,
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
build.setSelected(!build.isSelected());
if (build.isSelected()) {
holder.button.setBackgroundResource(R.drawable.selected_true_icon_new);
Intent intent = new Intent(context, youractivity.class)
intenet.putExtra("key","value");
context.startActivity(intent);
} else
holder.button.setBackgroundResource(R.drawable.add_button_icon);
}
});
Huge mistak that you register to the click event on your ViewHolder! you will get diffrent position from the actual because when android use notifyItemMoved the viewBindHolder will not be called and than you got the wrong position.
and in the click listener implementation you should pass Intent with your data

How do I properly execute database calls on other threads?

I am really confused how I should be using threads in my Android applications for database interaction. There are too many resources and I don't know which to choose from. So I'm hoping to get more specific and focused advice on my particular situation so I have a starting point.
This is my database class structure, which works great so far:
public class DatabaseHelper extends SQLiteOpenHelper {
private static volatile SQLiteDatabase mDatabase;
private static DatabaseHelper mInstance = null;
private static Context mContext;
private static final String DB_NAME = "database.db";
private static final int DB_VERSION = 1;
private static final DB_CREATE_THINGY_TABLE = "CREATE TABLE blahblahblah...";
//other various fields here, omitted
public static synchronized DatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
try {
mInstance.open();
}
catch (SQLException e) {
e.printStackTrace();
}
}
return mInstance;
}
private DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
mContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DB_CREATE_THINGY_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
#Override
public void onConfigure(SQLiteDatabase db){
super.onConfigure(db);
db.setForeignKeyConstraintsEnabled(true);
}
public void open() throws SQLException {
mDatabase = getWritableDatabase();
}
public void close() {
mDatabase.close();
}
public long addNewThingy(String name) {
ContentValues values = new ContentValues();
values.put(DatabaseHelper.THINGY_COLUMN_NAME, name);
return mDatabase.insertWithOnConflict(DatabaseHelper.THINGY_TABLE, null, values, SQLiteDatabase.CONFLICT_IGNORE);
}
public Thingy getThingyById(long id) {
Cursor cursor = mDatabase.query(
DatabaseHelper.THINGY_TABLE, // table
new String[]{DatabaseHelper.THINGY_COLUMN_ID, DatabaseHelper.THINGY_COLUMN_NAME}, // column names
DatabaseHelper.THINGY_COLUMN_ID + " = ?", // where clause
new String[]{id + ""}, // where params
null, // groupby
null, // having
null); // orderby
cursor.moveToFirst();
Thingy thingy = null;
if (!cursor.isAfterLast()) {
String name = getStringFromColumnName(cursor, DatabaseHelper.THINGY_COLUMN_NAME);
thingy = new Thingy(id, name);
cursor.moveToNext();
}
cursor.close();
return thingy;
}
}
So any time I want access to the database I do mDatabaseHelper = DatabaseHelper.getInstance(context); and I am good to go. I don't make any explicit calls to open() or close() or anything like that. However right now I am making all my database calls on the UI thread, I believe (either in my onCreate or onCreateView methods or separate methods which don't invoke any new threads or anything).
How would I correctly make this threaded so that I am not performing database operations on the UI thread?
I figure I have to change all my database calls to basically do this:
Make any necessary edits to my database class first to ensure it will work properly in the event that multiple threads are trying to perform operations at the same time. I already tried by making my class a singleton (I think it's a singleton, anyway?) and using keywords like "volatile" and "synchronized" but maybe I am missing something somewhere.
Perform database operation in its own thread.
Somehow trigger additional code back in the appropriate function/activity/fragment that will execute once the database operation has completed.
Make this whole process versatile enough to where I can do it anywhere.
Am I making sense? Is this the right way to be going about all this? Is there a simple example you can make that can show me how to, for example, correctly do something like mThingy = mDatabaseHelper.getThingyById(id); or mDatabaseHelper.addNewThingy(someName); from a sample activity/fragment/etc using proper threading?
Simple solution using Threads
public class DatabaseHelper extends SQLiteOpenHelper {
//...
public void addNewThingyAsync(final String name, final Callback<Long> cb) {
new Thread(new Runnable(){
#Override
public void run(){
cb.callback(addNewThingy(name));
}
}).start();
}
private synchronized long addNewThingy(String name){
//implementation...
}
public void getThingyByIdAsync(final long id, final Callback<Thingy> cb) {
new Thread(new Runnable(){
#Override
public void run(){
cb.callback(getThingyById(id));
}
}).start();
}
private synchronized Thingy getThingyById(long id) {
//implementation...
}
public interface Callback<T> {
public void callback(T t);
}
}
Solution using AsyncTasks
Same as above with the following changes:
public class DatabaseHelper extends SQLiteOpenHelper {
//...
public void addNewThingyAsync(final String name, final Callback<Long> cb) {
new AsyncTask<Void, Void, Long>(){
#Override
protected Long doInBackground(Void... ignoredParams) {
return addNewThingy(name);
}
#Override
protected void onPostExecute(Long result) {
cb.callback(result);
}
}.execute();
}
//...
public void getThingyByIdAsync(final long id, final Callback<Thingy> cb) {
new AsyncTask<Void, Void, Thingy>(){
#Override
protected Thingy doInBackground(Void... ignoredParams) {
return getThingyById(id);
}
#Override
protected void onPostExecute(Thingy result) {
cb.callback(result);
}
}.execute();
}
//...
}
Calling (works with both approaches)
long mId = ...;
mDatabaseHelper = DatabaseHelper.getInstance(context);
mDatabaseHelper.getThingyByIdAsync(mId, new Callback<Thingy>{
#Override
public void callback(Thingy thingy){
//do whatever you want to do with thingy
}
});
How would I correctly make this threaded so that I am not performing
database operations on the UI thread?
Simply perform any database operations off the UI thread. A common technique involves an AsyncTask. For example:
public class GetThingyTask extends AsyncTask<Long, Void, Thingy> {
private Context context;
public AddTask(Context context){
this.context = context;
}
#Override
protected Thingy doInBackground(Long... ids) {
final long id = ids[0];
Cursor cursor = DatabaseHelper.getInstance(context).query(
DatabaseHelper.THINGY_TABLE,
new String[]{
DatabaseHelper.THINGY_COLUMN_ID,
DatabaseHelper.THINGY_COLUMN_NAME
},
DatabaseHelper.THINGY_COLUMN_ID + "=?",
new String[]{String.valueOf(id)},
null, null, null);
String name = null;
if (cursor.moveToFirst() && (cursor.getCount() > 0)) {
name = getStringFromColumnName(cursor, DatabaseHelper.THINGY_COLUMN_NAME);
}
cursor.close();
return new Thingy(id, name);
}
#Override
protected void onPostExecute(Thingy thingy) {
//Broadcast the Thingy somehow. EventBus is a good choice.
}
}
And to use it (inside, for example, an Activity):
new GetThingyTask(this).execute(id);

Correct way to open/close the database?

Right now I am using a static instance of the SQLOpenHelper class like so:
public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;
private final Context mContext;
//...
public static synchronized DatabaseHelper getInstance(Context context) {
/**
* use the application context as suggested by CommonsWare.
* this will ensure that you don't accidentally leak an Activity's
* context (see this article for more information:
* http://android-developers.blogspot.nl/2009/01/avoiding-memory-leaks.html)
*/
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
private DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
mContext = context;
}
//...
}
And then a DatabaseProcessor class like so:
public class DatabaseProcessor {
private SQLiteDatabase mDatabase;
private DatabaseHelper mSQLHelper;
private Context mContext;
public DatabaseProcessor(Context context) {
mContext = context;
mSQLHelper = DatabaseHelper.getInstance(mContext);
}
public void open() throws SQLException {
mDatabase = mSQLHelper.getWritableDatabase();
}
public void close() {
mDatabase.close();
}
//...
}
So if I want to access my database, I do something like this:
DatabaseProcessor mDatabaseProcessor = new DatabaseProcessor(this);
mDatabaseProcessor.open();
mSomeList = mDatabaseProcessor.doSomeQueryAndReturnResults();
mDatabaseProcessor.close();
Is this the correct way to do this? Or is it better to open the database in the base Activity onResume() method and close it during onPause()? How do I correctly throw errors for situations where the database is not open when I try to run a query?
EDIT Refactored version:
public class DatabaseHelper extends SQLiteOpenHelper {
private static SQLiteDatabase mDatabase;
private static DatabaseHelper mInstance = null;
private static Context mContext;
// ...
public static synchronized DatabaseHelper getInstance(Context context) {
/**
* use the application context as suggested by CommonsWare.
* this will ensure that you don't accidentally leak an Activity's
* context (see this article for more information:
* http://android-developers.blogspot.nl/2009/01/avoiding-memory-leaks.html)
*/
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
private DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
mContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DB_CREATE_SOME_TABLE); //some SQL expression
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(DB_ALTER);
}
public void open() throws SQLException {
mDatabase = getWritableDatabase();
}
public void close() {
mDatabase.close();
}
public boolean isOpen() {
return mDatabase.isOpen();
}
//below this would be various CRUD functions operating on mDatabase
// ...
// ...
}
The best way would be to put your query/transaction statements in try-catch and then release all your resources and close the connection in finally block.
try{
mSomeList = mDatabaseProcessor.doSomeQueryAndReturnResults();
} catch(Exception exc){
//Catch exceptions here
}
finally{
if(mDatabaseProcessor != null)
mDatabaseProcessor.close();
}

Categories