Nullpointer Exception after deleting entry from SQL database - java

I'm working on an app for a robot where the user can define punch combinations which the robot will later fetch from the device. To allow the user to store these trainings I have defined a class "Trainings" which holds the id, the name and the punch combination of the training. This training is later saved in a database, for which I have written a DatabaseHandler class. Adding and displaying the data works fine, but whenever I want to delete an entry with the method below:
public void deleteTraining(Training training) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_TRAININGS, KEY_ID + " = ?",
new String[] { String.valueOf(training.getID()) });
db.close();
}
and later try to populate my GridView again ( handled by a GridAdapter class), I get a Nullpointer Exception
java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.noeth.tobi.mcrobektrainingsplaner.Training._name' on a null object reference
at com.noeth.tobi.mcrobektrainingsplaner.GridAdapter.getView(GridAdapter.java:50)
the getView method of the GridAdapter:
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
// if it's not recycled, initialize some attributes
btn = new Button(context);
btn.setLayoutParams(new GridView.LayoutParams(370, 350));
btn.setPadding(2,100,2,100);
btn.setOnClickListener(new CustomOnClickListener(position, context));
btn.setOnLongClickListener(new CustomOnLongClickListener(position, context, btn));
}
else {
btn = (Button) convertView;
}
btn.setText(db.getTraining(position)._name); //Here the programm throws a Nullpointer Exception AFTER deleting an entry from the database
btn.setTextColor(Color.WHITE);
btn.setBackgroundResource(R.drawable.button_border);
btn.setTag("not_activated");
btn.setId(position);
return btn;
}
I figured that it must have something to do with the id of the deleted training, as the loop simply goes through all ids so I wrote a method recalcIDs which recalculates the id of every item coming after the deleted training:
recalcIDs
public void recalcIDs(){
int k = 1;
int subtract = 1;
int id;
Training training;
for(int i = deleted.get(0)+1; i < db.getTrainingCount(); i++){
if(deleted.size() > 1){
if(i < deleted.get(k)){
training = db.getTraining(i);
id = training.getID();
training.setID(id-subtract);
}
else{
k+=1;
subtract+=1;
}
}
else{
training = db.getTraining(i);
id = training.getID();
training.setID(id-subtract);
}
}
}
However this does not fix it.
When reinstalling the app and starting with a completely new database everythings works again.
Does anybody have an idea what I've done wrong?
P.S.: Here's the getTraining method where it can't find the name:
Training getTraining(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Training training;
Cursor cursor = db.query(TABLE_TRAININGS, new String[] { KEY_ID,
KEY_NAME, KEY_SK}, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null && cursor.moveToFirst()){
training = new Training(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getLong(2));
cursor.close();
}
else{
training = null;
Toast.makeText(con,"Couldn't find any training sessions!", Toast.LENGTH_LONG).show();
}
// return training
return training;
}

I'm assuming your the Training.setId method doesn't call the database.
You shouldn't change the id of your training because they get managed by the underlaying database. If you only change the ids in you application logic both datasets (application and database) will differ.
I would recommend to reload all the trainings from the database after a user decided to delete one and call the Gridview.notifyDatasetChanged afterwards.

Related

Error querying sqlite database in android studio

I have a problem in my application, to see if there is someone who can help me.
It turns out that in my application I have made a database with SQLite that has two tables, one for players and one for results.
#Override
public void onCreate(SQLiteDatabase BaseDeDades) {
BaseDeDades.execSQL("create table jugadors(codi int primary key, nom text, cognoms text, data date, club text, categoria text)");
BaseDeDades.execSQL("create table resultats(codipuntuacio int primary key, codijugador int,codiexercici text, puntuacio text, temps long, data date)");
}
To consult the first of the tables (players) that shows a list of all the players entered in the database, I did it as follows.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_llistajug);
Llistajugadors();
}
public void Llistajugadors(){
AdminSQLiteOpenHelper admin = new AdminSQLiteOpenHelper(this,"administracio",null,1);
SQLiteDatabase BaseDeDades = admin.getWritableDatabase();
if(BaseDeDades!=null){
Cursor c= BaseDeDades.rawQuery("select * from jugadors",null);
int quantitat = c.getCount();
int i=0;
String[] array = new String[quantitat];
if (c.moveToFirst()){
do{
String linia = c.getInt(0)+"-"+c.getString(1);
array[i] = linia;
i++;
}while(c.moveToNext());
}
ArrayAdapter<String>adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,array);
final ListView llista = (ListView)findViewById(R.id.llista);
llista.setAdapter(adapter);
llista.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = getIntent();
intent.putExtra("dato2", llista.getItemAtPosition(position).toString());
setResult(RESULT_OK,intent);
finish();
}
});
}
}
}
The problem has arisen when trying to consult the data of the other table (results) since I have tried to do it the same way
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_llistajug);
jugador = getIntent().getStringExtra("name");
exercici = getIntent().getStringExtra("exercise");
nom = jugador.split("-")[1];
codi = Integer.parseInt(jugador.split("-")[0]);
Resultats();
}
public void Resultats() {
AdminSQLiteOpenHelper admin = new AdminSQLiteOpenHelper(this, "administracio", null, 1);
SQLiteDatabase BaseDeDades = admin.getWritableDatabase();
if (BaseDeDades != null) {
Cursor c2 = BaseDeDades.rawQuery("select * from resultats",null);
int quantitat2 = c2.getCount();
int i2 = 0;
String[] array2 = new String[quantitat2];
if (c2.moveToFirst()) {
do {
String linia2 = c2.getInt(0) + "-" + c2.getString(1);
array2[i2] = linia2;
i2++;
} while (c2.moveToNext());
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, array2);
final ListView llista2 = (ListView) findViewById(R.id.llista2);
llista2.setAdapter(adapter);
}
}
}
But when executing this activity, in this case the application stops.
Does anyone know why if I have done it the same way? Thank you
This is the error that appears in Logcat when executing the activity:
Logcat error
Thanks, the bug was fixed. But now I have another problem with the query. How can I make the query for a string?
codijugador i codi are integers and it works correctly but adding another parameter codiexercici = exerici which are strings gives me an error, are they not done the same way?
Thanks, the bug was fixed. But now I have another problem with the query. How can I make the query for a string?
Thanks, the bug was fixed. But now I have another problem with the query. How can I make the query for a string?
co-player i codi are integers and it works correctly but adding another parameter codiexercici = exerici which are strings gives me an error, are they not done the same way?
Cursor c = BaseDeDades.rawQuery("select * from resultats where codijugador = "+codi+" and codiexercici="+exercici, null);
String must be enclosed inside single quotes, but this is something that you should not do by concatenating the parameters and the single quotes.
Use ? placeholders for the parameters and the 2nd argument of rawQuery() to pass them:
Cursor c = BaseDeDades.rawQuery(
"select * from resultats where codijugador = ? and codiexercici = ?",
new String[] {String.valueOf(codi), exercici}
);

Android content provider returning wrong contact id

I'm working on an Android application that manages contacts (Add, Update, Delete)
This is the code that lists the contacts in listview
list_ct.clear();
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null)
{
while (cursor.moveToNext())
{
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Cursor cursor2 = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, CommonDataKinds.Phone.CONTACT_ID +" = "+ id,null, null);
ArrayList<String> phones = new ArrayList<String>();
while (cursor2.moveToNext())
{
String phoneNumber = cursor2.getString(cursor2.getColumnIndex(CommonDataKinds.Phone.NUMBER));
phones.add(phoneNumber);
}
Contact ct = new Contact(id,name,phones);
adapter.notifyDataSetChanged();
}
}
This is the listview event listener
lv.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Contact current = (Contact)list_ct.get(position);
Intent in=new Intent(Intent.ACTION_EDIT,Uri.parse("content://contacts/people/"+current.getId()));
startActivityForResult(in,2);
}
});
When I click on a contact in the listview, for some of them the intent opens and closes immediatly, as if the id doesn't exist in the contact's database, and for others it opens the contact edit for another contact.
The contact display name and its phone numbers are correctly shown, but the id is wrong. What I don't understand is why the id in the first cursor works for showing the contact's phone numbers, but not to update.
You're using a very old and deprecated Android API called "People" for your Contact URI, never use People's API, always ContactsContract.
You should build your contact uri like this:
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
Other then that, your query is super-slow, you can replace those hundreds of queries with a single fast query to make your app faster and life easier, see an example code in this answer:
https://stackoverflow.com/a/47788324/819355

Why my sqlite insert method is not working

Save data with SQLite
Hi guys, I'm new to Android and i'm working in a Notes App, until now I have done with the main interphace and recieve the inputs from the Edittext, but when it comes to saving data to my SQLite DB, my code is failling, can you please tell me what I been doing wrong ?.
FormActivity method
public void saveToDB(View view) {
try {
String subjet = asunto.getText().toString();
String body = cuerpo.getText().toString();
int day = myCalendar.get(Calendar.DAY_OF_MONTH);
int month = myCalendar.get(Calendar.MONTH);
int year = myCalendar.get(Calendar.YEAR);
Note note = new Note(subject,body,day,month,year); // Create an instance of Note class
DBHelper db = new DBHelper(this,"TaskList.db",null,1); // New Instance of DBHelper class
db.InsertIntoTable(note); // pass the newly created Note instance to DBHelper insert method
db.close(); // we close Database
Toast.makeText(this,"Note saved !!",Toast.LENGTH_SHORT).show(); // Notify the user of the operation success
Intent intent = new Intent(FormActivity.this,MainActivity.class); // Lets return to MainActivity again
startActivity(intent);
}
catch (Exception e){
Toast.makeText(this,"Unable to save note",Toast.LENGTH_SHORT).show();
}
}
DBHelper insert method
public Long InsertIntoTable(Note note){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
/* We organize the values in the respective rows */
values.put(col_subject,note.getSubject());
values.put(col_note,note.getBody());
values.put(col_day,note.getDay());
values.put(col_month,note.getMonth());
values.put(col_year, note.getYear());
// Time to insert data to Database
long rowID = db.insert(table_name,null,values);
return rowID;
}
I put a Toast, to prevent my app from crashing in case and to see if the operation succed, but it fails everytime.
RecyclerAdapter class
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.itemview,null);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
Note note = noteList.get(i);
viewHolder.asunto.setText(note.getAsunto());
viewHolder.nota.setText(note.getCuerpo());
viewHolder.fecha.setText(note.getDia() + "/" + note.getMes() + "/" + note.getAno());
viewHolder.etiqueta.setText(note.getTag());
}
This is in my stacktrace:
E/RecyclerView: No adapter attached; skipping layout

Android SQLite Database not fully commiting? Changes until Activity ends?

Sorry for the long description, it's hard to describe my problem without giving you some background.
Okay so I have an app that uses one SQLite database and has two tables in it Table 1 and Table 2. I have a main activity with fragment with a button that starts my Log activity with fragment. The Log activity has a tabbed viewpager and in each view of the viewpager is a listview (Tab 1 listview and Tab 2 listview) with data from the corresponding tables (Table 1 and Table 2) in the database.
So when I'm in my Log Activity with Fragment I can click on the Tab 1 and it will populate the Tab 1 listview with the data from the Table 1 in my database. When I click on Tab 2 it'll populate the Tab 2 listview with the data from my Table 2 in my database. Each tab has it's own fragment. Tab 1 fragment and Tab 2 fragment.
So to explain my issue I'll just focus on my Tab 1, because both tabs are doing the same time.
WHAT WORKS:
Let me explain first though that if I add Data X into my Tab 1, Table 1, it will populate Listview 1 with Data X and add the Data X into my Table 1 just fine. I can Log.d my Table 1 and see it got entered just fine. If I press back on the phone to go back to my Main Activity with Fragment and then decide to go back into my Log Activity with Fragment it will populate the Listview 1 just fine with Data X and Data X is still in my Table 1, because again I can Log.d my Table 1 and see the data has been entered just fine. If I delete Data X now after having gone to the Main Activity and back into the Log Activity the Data X will delete from my Table 1 just fine and it will be removed from my Listview 1. I can log.d my Table 1 after deleting and see it has been deleted from my Table 1.
WHAT DOESN'T WORK:
So my actual issue is when I add lets say Data X and Data Y into my Tab 1, Table 1 of my database. The Listview 1 will populate with Data X and Data Y and insert Data X and Data Y into the database just fine because I can Log.d the table and see Data X and Data Y have been entered into my table.... But now lets say I decide to instantly delete the Data Y (While have never left the Log Activity this time) it will not delete from the Table 1 but it will delete Data Y from my Listview 1. So now when I Log.d my Table 1 I see that I still have Data X and Data Y in my Table 1, but my Listview 1 shows only Data X. If I now press the back button and go back to my Main Activity, and then again go back into my Log Activity it will populate my Tab 1 Listview 1 with Data X and Data Y because Data Y was not actually removed from my Table 1.
It seems as if I can't Delete or Edit freshly entered Data into my Tables without first leaving my Log Activity and going back into it to "Commit/Finalize" the data entered into the Table 1. My Insert, Update, and Delete functions work just fine after I have left the Logs Activity after adding fresh data and then going back into my Logs Activity. But My Delete and Update functions do not work properly if I add fresh data and then instantly try to alter that data. My Listview is updating and populating correctly though.
WHAT I'VE RESEARCHED AND TRIED:
I've made sure I have one instance of my SQLiteOpenHelper and my SQLiteDatabase variables. I have also tried to open the database before every insert, edit, or delete and then close it after I inserted, editted, or deleted. It didn't seem to have any effect. Currently i have the datasource get closed onPause() and opens again on onResume(). And finally I have tried setting up a setTransactionSuccessful() and then endTransaction() after beginTransaction() for each Insert, Update, or Delete.
CURRENT IDEAS:
I'm thinking it might have to do with my id's of my entries in my Tables... I believe it should auto increment the id when a new entry is added to the table. They might not be what I'm expecting them to be when the data is added and then instantly try to alter the data. The id's shouldn't change though when I back out of the Log activity and go back in though so I'm not too sure.
CODE:
Here is code for one of my Tab fragments I stripped out a lot of stuff due to size of the file.
public class LogOilTabFragment extends Fragment implements View.OnClickListener{
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mContext = getActivity();
DataSource.getInstance(mContext).open();
mListView = (ListView) view.findViewById(R.id.oil_list);
arrayOfLogs = new ArrayList<Log>();
arrayOfLogs = DataSource.getInstance(mContext).getAllLogs(LogsContract.OilTable.TAG);
mAdapter = new LogAdapter(getActivity(), arrayOfLogs);
mListView.setAdapter(mAdapter);
}
}
#Override
public void onResume() {
DataSource.getInstance(mContext).open();
super.onResume();
}
#Override
public void onPause() {
DataSource.getInstance(mContext).close();
super.onPause();
}
private void addLog() {
LayoutInflater factory = LayoutInflater.from(getActivity());
final View view = factory.inflate(R.layout.add_edit_log, null);
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setView(view);
alert.setPositiveButton("ADD LOG", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int whichButton) {
String date = dateInput.getText().toString();
String amount = amountInput.getText().toString();
String miles = milesInput.getText().toString();
if (error_count == 0) {
Log log = new Log();
log.setmDate(date);
log.setmAmount(amount);
log.setmMiles(miles);
DataSource.getInstance(mContext).insert(date, amount, miles, OilTable.TAG);
mAdapter.add(log);
mAdapter.notifyDataSetChanged();
mListView.smoothScrollToPosition(mPosition);
}
}
});
alert.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
alert.show();
}
private void editLog() {
LayoutInflater factory = LayoutInflater.from(getActivity());
final View view = factory.inflate(R.layout.add_edit_log, null);
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setView(view);
Log log = null;
//Pre fill in the edit text views with the data already in the database
if (mAdapter.getCount() > 0 && mPosition >= 0) {
log = (Log) mAdapter.getItem(mPosition);
dateInput.setText(log.getmDate());
amountInput.setText(log.getmAmount());
milesInput.setText(log.getmMiles());
}
alert.setPositiveButton("EDIT LOG", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String date = dateInput.getText().toString();
String amount = amountInput.getText().toString();
String miles = milesInput.getText().toString();
if (error_count == 0) {
Log log = (Log) mAdapter.getItem(mPosition);
DataSource.getInstance(mContext).edit(log.getmId(), date, amount, miles, OilTable.TAG);
mAdapter.clear();
arrayOfLogs = new ArrayList<Log>();
arrayOfLogs = DataSource.getInstance(mContext).getAllLogs(OilTable.TAG);
mAdapter.addAll(arrayOfLogs);
mAdapter.notifyDataSetChanged();
}
}
});
alert.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
//Do Nothing
}
});
alert.show();
}
private void deleteLog() {
LayoutInflater factory = LayoutInflater.from(getActivity());
final View view = factory.inflate(R.layout.delete_log, null);
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setView(view);
alert.setPositiveButton("DELETE LOG", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Log log = null;
if (mAdapter.getCount() > 0) {
log = (Log) mAdapter.getItem(mPosition);
DataSource.getInstance(mContext).delete(log, OilTable.TAG);
mAdapter.remove(log);
mAdapter.notifyDataSetChanged();
}
}
});
alert.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
//Do Nothing
}
});
alert.show();
}
Here is my class that has my Insert, Update, and Delete code from my DataSource
public class DataSource {
public static DataSource dataSource;
private SQLiteDatabase mSQLiteDatabase;
private LogsDBHelper mLogsDBHelper; //LogsDBHelper Extends SQLiteOpenHelper
}
//String of column names for the oil sqlite database.
private String[] mAllOilColumns = {
OilTable.COLUMN_ID,
OilTable.COLUMN_DATE,
OilTable.COLUMN_AMOUNT,
OilTable.COLUMN_MILES};
//String of column names for the coolant sqlite database.
private String[] mAllCoolantColumns = {
OilTable.COLUMN_ID,
OilTable.COLUMN_DATE,
OilTable.COLUMN_AMOUNT,
OilTable.COLUMN_MILES};
public static synchronized DataSource getInstance(Context context) {
if (dataSource == null) {
dataSource = new DataSource(context.getApplicationContext());
}
return dataSource;
}
private DataSource(Context context) {
mLogsDBHelper = new LogsDBHelper(context); //LogsDBHelper Extends SQLiteOpenHelper
}
public void open() throws SQLiteException {
mSQLiteDatabase = mLogsDBHelper.getWritableDatabase();
}
public void close() {
mLogsDBHelper.close();
// mSQLiteDatabase.close();
}
//Method takes a string and depending on the string creates a query from the correct
//database table and returns the amount of items in the table
public int getLength(String tag){
Cursor cursor;
switch (tag) {
case OilTable.TAG:
cursor = mSQLiteDatabase.query(OilTable.TABLE_NAME,
mAllOilColumns, null, null, null, null, null);
return cursor.getCount();
case CoolantTable.TAG:
cursor = mSQLiteDatabase.query(CoolantTable.TABLE_NAME,
mAllCoolantColumns, null, null, null, null, null);
return cursor.getCount();
}
return 0;
}
//Inserts a log into the correct sqlite table with the passed values
public void insert(String date, String amount, String miles, String tag) {
ContentValues values = new ContentValues();
switch (tag) {
case OilTable.TAG:
values.put(OilTable.COLUMN_DATE, date);
values.put(OilTable.COLUMN_AMOUNT, amount);
values.put(OilTable.COLUMN_MILES, miles);
mSQLiteDatabase.insert(OilTable.TABLE_NAME, null, values);
break;
case CoolantTable.TAG:
values.put(CoolantTable.COLUMN_DATE, date);
values.put(CoolantTable.COLUMN_AMOUNT, amount);
values.put(CoolantTable.COLUMN_MILES, miles);
mSQLiteDatabase.insert(CoolantTable.TABLE_NAME, null, values);
break;
}
}
//Edits/Updates a log into the correct sqlite table with the passed values
public void edit(Long id, String date, String amount, String miles, String tag){
ContentValues values = new ContentValues();
switch (tag) {
case OilTable.TAG:
values.put(OilTable.COLUMN_DATE, date);
values.put(OilTable.COLUMN_AMOUNT, amount);
values.put(OilTable.COLUMN_MILES, miles);
mSQLiteDatabase.update(OilTable.TABLE_NAME, values, "_id=" + id, null);
break;
case CoolantTable.TAG:
values.put(CoolantTable.COLUMN_DATE, date);
values.put(CoolantTable.COLUMN_AMOUNT, amount);
values.put(CoolantTable.COLUMN_MILES, miles);
mSQLiteDatabase.update(CoolantTable.TABLE_NAME, values, "_id=" + id, null);
break;
}
}
//Deletes a log into the correct sqlite table based on the log id.
public void delete(Log log, String tag) {
long id = log.getmId();
switch(tag) {
case OilTable.TAG:
mSQLiteDatabase.delete(OilTable.TABLE_NAME,
OilTable.COLUMN_ID + " = " + id, null);
break;
case CoolantTable.TAG:
mSQLiteDatabase.delete(CoolantTable.TABLE_NAME,
CoolantTable.COLUMN_ID + " = " + id, null);
break;
}
}
//Returns an Arraylist of all of the logs from the table specified from the passed in value.
public ArrayList getAllLogs(String tag){
ArrayList logs = new ArrayList();
Cursor cursor;
Log log;
switch(tag) {
case OilTable.TAG:
cursor = mSQLiteDatabase.query(OilTable.TABLE_NAME,
mAllOilColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
log = cursorToLog(cursor);
logs.add(log);
cursor.moveToNext();
}
cursor.close();
break;
case CoolantTable.TAG:
cursor = mSQLiteDatabase.query(CoolantTable.TABLE_NAME,
mAllCoolantColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
log = cursorToLog(cursor);
logs.add(log);
cursor.moveToNext();
}
cursor.close();
break;
}
return logs;
}
//Used in local method getAllLogs()
private Log cursorToLog(Cursor cursor) {
Log log = new Log();
log.setmId(cursor.getLong(0));
log.setmDate(cursor.getString(1));
log.setmAmount(cursor.getString(2));
log.setmMiles(cursor.getString(3));
return log;
}
//Used to get all of the dates from the specified database in the call.
public String[] getAllDates(String tag){
Cursor cursor;
int index;
String[] dates = new String[0];
int i = 0;
switch(tag) {
case OilTable.TAG:
cursor = mSQLiteDatabase.query(OilTable.TABLE_NAME, mAllOilColumns, null, null, null, null, null);
index = cursor.getColumnIndex(OilTable.COLUMN_DATE);
dates = new String[cursor.getCount()];
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
dates[i] = cursor.getString(index);
i++;
cursor.moveToNext();
}
cursor.close();
break;
case CoolantTable.TAG:
cursor = mSQLiteDatabase.query(CoolantTable.TABLE_NAME, mAllCoolantColumns, null, null, null, null, null);
index = cursor.getColumnIndex(CoolantTable.COLUMN_DATE);
dates = new String[cursor.getCount()];
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
dates[i] = cursor.getString(index);
i++;
cursor.moveToNext();
}
cursor.close();
break;
}
return dates;
}
//Used to get all of the amounts from the specified database in the call.
public String[] getAllAmounts(String tag){
Cursor cursor;
int index;
String[] amounts = new String[0];
int i = 0;
switch(tag) {
case OilTable.TAG:
cursor = mSQLiteDatabase.query(OilTable.TABLE_NAME, mAllOilColumns, null, null, null, null, null);
index = cursor.getColumnIndex(OilTable.COLUMN_AMOUNT);
amounts = new String[cursor.getCount()];
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
amounts[i] = cursor.getString(index);
i++;
cursor.moveToNext();
}
cursor.close();
break;
case CoolantTable.TAG:
cursor = mSQLiteDatabase.query(CoolantTable.TABLE_NAME, mAllCoolantColumns, null, null, null, null, null);
index = cursor.getColumnIndex(CoolantTable.COLUMN_AMOUNT);
amounts = new String[cursor.getCount()];
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
amounts[i] = cursor.getString(index);
i++;
cursor.moveToNext();
}
cursor.close();
break;
}
return amounts;
}
//Used to get all of the miles from the specified database in the call.
public String[] getAllMiles(String tag){
Cursor cursor;
int index;
String[] miles = new String[0];
int i = 0;
switch(tag) {
case OilTable.TAG:
cursor = mSQLiteDatabase.query(OilTable.TABLE_NAME, mAllOilColumns, null, null, null, null, null);
index = cursor.getColumnIndex(OilTable.COLUMN_MILES);
miles = new String[cursor.getCount()];
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
miles[i] = cursor.getString(index);
i++;
cursor.moveToNext();
}
cursor.close();
break;
case CoolantTable.TAG:
cursor = mSQLiteDatabase.query(CoolantTable.TABLE_NAME, mAllCoolantColumns, null, null, null, null, null);
index = cursor.getColumnIndex(CoolantTable.COLUMN_MILES);
miles = new String[cursor.getCount()];
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
miles[i] = cursor.getString(index);
i++;
cursor.moveToNext();
}
cursor.close();
break;
}
return miles;
}
}
LogDBHelper Code
public class LogsDBHelper extends SQLiteOpenHelper {
//Application database name and version
private static final String DATABASE_NAME = "logs.db";
private static final int DATABASE_VERSION = 1;
public LogsDBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
// Database creation sql statement for oil table
final String SQL_CREATE_OIL_TABLE = "CREATE TABLE "
+ OilTable.TABLE_NAME + "( "
+ OilTable.COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ OilTable.COLUMN_DATE + " TEXT NOT NULL,"
+ OilTable.COLUMN_AMOUNT + " REAL NOT NULL,"
+ OilTable.COLUMN_MILES + " INTEGER NOT NULL);";
// Database creation sql statement for coolant table
final String SQL_CREATE_COOLANT_TABLE = "CREATE TABLE "
+ CoolantTable.TABLE_NAME + "( "
+ CoolantTable.COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ CoolantTable.COLUMN_DATE + " TEXT NOT NULL,"
+ CoolantTable.COLUMN_AMOUNT + " REAL NOT NULL,"
+ CoolantTable.COLUMN_MILES + " INTEGER NOT NULL);";
//Create the tables in the database
db.execSQL(SQL_CREATE_OIL_TABLE);
db.execSQL(SQL_CREATE_COOLANT_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+ OilTable.TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS "+ CoolantTable.TABLE_NAME);
onCreate(db);
}
}
UPDATE #1:
What I've found out after messing around and debugging for a few hours is that when I add a new data item to my table and then try to delete that freshly added item it thinks it's ID is 0... But it should not.
Example:
I have 1 data item in my table. It's data row looks like
ID: 1, Data: "Example Data 1"
Now if I add another data item to that table I'll have,
ID: 1, Data: "Example Data 1"
ID: 2, Data: "Example Data 2"
If I want to delete data item two right now after JUST inserting it. My delete query thinks I'm looking for ID: 0 so it doesn't find it and doesn't delete it. Makes sense.... But if I had my original
ID: 1, Data: "Example Data 1"
And then added a second data item so it now looks like this
ID: 1, Data: "Example Data 1"
ID: 2, Data: "Example Data 2"
And then press the back button to go back to my Main Activity... Then go back into my Log Activity to try and delete data item 2 the delete query will find the ID = 2 and delete the right data item
It's like my ID auto incremented id number isn't being committed unless I back out and go back in and then it finds it.
UPDATE #2:
Solved it,
Problem was in my Add method of my Tab Fragment... I was never updating the Log object with it's new ID after inserting the data into the table...
Log log = new Log();
Needed to set ID before adding it to mAdapter
log.setmDate(date);
log.setmAmount(amount);
log.setmMiles(miles);
mDataSource.insert(date, amount, miles, OilTable.TAG);
log.setmId(mDataSource.getLastLogID(OilTable.TAG));
mAdapter.add(log);
Solved it,
Problem was in my Add method of my Tab Fragment... I was never updating the Log object with it's new ID after inserting the data into the table...
Log log = new Log();
Needed to set ID before adding it to mAdapter
log.setmDate(date);
log.setmAmount(amount);
log.setmMiles(miles);
mDataSource.insert(date, amount, miles, OilTable.TAG);
log.setmId(mDataSource.getLastLogID(OilTable.TAG));
mAdapter.add(log);
Without it any recently added data would not be accessible by an ID in a query because I was referencing my ListView of Logs to get the Log information to edit and delete. It would work fine once i went out and loaded back into the Log Activity because my ListAdapter would populate with the full data including the IDs.

Slow Performance while listing SMS with the senders in android

I am using the bellow code to list a unique list of people that sent me SMS. It works fine but still its a bit slow it takes 4 to 5 seconds to load and I have 650 SMS on my device any suggestion ?
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listSMS();
}
private void listSMS()
{
TextView tview = (TextView) findViewById(R.id.list);
Uri uriSMSURI = Uri.parse("content://sms/inbox");
ContentResolver cr= this.getContentResolver();
Cursor cur = cr.query(uriSMSURI, null, null, null, null);
LinkedHashSet contactList= new LinkedHashSet();
String sms = "";
while (cur.moveToNext()) {
if(!contactList.contains(cur.getString(2)))
{
contactList.add(cur.getString(2));
sms += "From :" + getContactName(cur.getString(2),cr)+"\n";
}
}
cur.close();
tview.append(sms);
}
public static String getContactName(String num, ContentResolver cr) {
Uri u = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,Uri.encode(num));
String[] projection = new String[] { ContactsContract.Contacts.DISPLAY_NAME};
Cursor c = cr.query(u, projection, null, null, null);
try {
if (!c.moveToFirst())
return num;
int index = c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
return c.getString(index);
} finally {
if (c != null)
c.close();
}
}
Instead of preparing the list of contacts with their names up front and then passing it to the adapter, try preparing the list with ids only and then fetch the corresponding names inside the adapter. This will solve the delay to start but will make scrolling of the ListView a bit slower which can be solved by using a View Holder or some caching mechanism to prevent fetching the same name more than once. Also note that the adapter will query for names of contacts that are currently visible to the user only.

Categories