SQLiteAssetHelper - 'No such table' error - java

I have prepopulated a database with DB Browser for SQLite and tried to retrieve data from it using SQLiteAssetHelper (installed and used it using the guide at https://github.com/jgilfelt/android-sqlite-asset-helper ) and got a "No such table" error. I am sure that there is a table named that way in the database. I've tried to debug it and saw that I leave the DATABASE_VERSION as equal to one than it detects that there is already a database and doesn't copy it, though if I change the database version and setForceUpdate to (true) then it copies it, but I get the same error anyway. What should I do for SQLiteAssetHelper to copy my database properly and get rid of that annoying error?
Code:
DataBaseHelper class:
public class DataBaseHelper extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "DonRoll";
private static final int DATABASE_VERSION = 2;
private static DataBaseHelper instance;
public static DataBaseHelper getInstance(Context context){
if (null == instance){
instance = new DataBaseHelper(context);
}
return instance;
}
private DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public Cursor getAllCategoryNames() {
setForcedUpgrade(2);
SQLiteDatabase db = getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables("MenuCategories");
Cursor c = qb.query(db, null, null, null, null, null, null);
c.moveToFirst();
return c;
}
}
Activity class:
public class CategoryListActivity extends ListActivity {
DataBaseHelper db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_category_list);
db = DataBaseHelper.getInstance(this);
getData();
}
#SuppressWarnings("deprecation")
private void getData() {
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1,
db.getAllCategoryNames(),
new String[] { "value" },
new int[] { android.R.id.text1 });
ListView listView = (ListView) findViewById(android.R.id.list);
listView.setAdapter(adapter);
}
}

Problem solved: I've used adb pull to get the database file from the assets folder and it somehow got corrupted - it had only the "android_metadata" table. I don't know why this happened (maybe because I renamed it after I have put it into Android studio?), but once I have deleted this file and replaced it with a proper one everything worked just fine.

Related

force close while adding to array

I want to get one column from my SQLite database and add that information in an array.
I use from array and cursor and two java classes.
My sqlite database doesn't have a problem as in another page I was able to get information.
My Android application force closes while I'm expecting to see the information displayed.
My method (displayrooidad):
public String displayrooidad(int row) {
Cursor cu = db.query(DB_TBL_ROOIDAD, null, null, null, null, null, null, null);
cu.moveToPosition(row);
String content = cu.getString(1);
return content;
}
my java class
SQLiteHelper: is a javaclass for connect to database.
open and close methods Working properly.
public class Rooidad extends AppCompatActivity {
Spinner sp;
TextView txt;
SQLiteHelper sq;
String[] myarray;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.rooidad);
// sp=(Spinner)findViewById(R.id.sp);
txt = (TextView)findViewById(R.id.test);
sq=new SQLiteHelper(getBaseContext());
sq.open();
int row =sq.countofrow();
myarray=new String[row];
for(int teller=0;teller<=row;teller++){
String tittle = sq.displayrooidad(teller);
myarray[teller]=tittle.toString();
}
sq.close();
txt.setText(myarray[4].toString());
}
}
I think you need to put teller < row because your tab has only row elements not row+1.

Populating a ListView with SQLite - ListView appends rows but doesn't show text

I'm trying to populate a ListView with SQLite items. After reading about this here and in other tutorials/examples I tried the following code, but I can't spot where exactly is the issue with it, since it's not working as intended, ListView isn't showing any items. My database has only one type of data, a string called sentence. Any help that could at least point me a direction in solving the issue is appreciated.
First I made a FavoritesDataBaseCore.java:
package com.easyprojects.artgames;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by Vinicius on 19/05/2017.
*/
public class FavoritesDataBaseCore extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "Favorites.db";
public FavoritesDataBaseCore(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table favorite(_id integer primary key autoincrement, sentence text not null)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists favorite");
onCreate(db);
}
}
The sentence is supposed to be added through a button click in CharacterActivity.java, relevant code:
ImageButton setFavoriteBtn;
private SQLiteDatabase database;
FavoritesDataBaseCore helper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_character);
setFavoriteBtn = (ImageButton) findViewById(R.id.setFavoriteBtnId);
setFavoriteBtn.setOnClickListener(this);
// Database stuff
helper = new FavoritesDataBaseCore(this);
database = helper.getWritableDatabase();
}
// Code below is inside public void onClick(View view)
case R.id.setFavoriteBtnId:
ContentValues values = new ContentValues();
values.put("sentence", characterTV.getText().toString());
database.insert("favorite", null, values);
// A Toast here showing values.toString() works well
break;
And finally the Activity that contains the ListView and creates the Cursor, I suspect the problem is here, since the Cursor is a major responsable for setting a correct adapter to the ListView, FavoritesActivity.java, relevant code:
private SQLiteDatabase database;
FavoritesDataBaseCore helper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_favorites);
helper = new FavoritesDataBaseCore(this);
database = helper.getReadableDatabase();
String[] field = {"sentence"};
int[] to = new int[]{R.id.SentenceAd};
Cursor cursor = getData();
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, field, to, 0);
final ListView FavoritesListView = (ListView) findViewById(R.id.listviewID); // ListView
FavoritesListView.setAdapter(adapter);
}
public Cursor getData(){
Cursor cursor;
String[] field = {"sentence"};
cursor = database.query("favorite",null,null,null,null,null,null);
return cursor;
}
My database_adapter.xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/SentenceAd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
Edit: After adapting the code with #MikeT's suggestions I've come to the conclusion my ListView is appending rows each time I add a value into the database, but sentence is never shown in those rows.
There are a number of issues. The first few are related to the creation of the Cursor in preparation for it's use by the SimpleCursorAdapter. Then there is an issue with how the SimpleCursorAdpater has been instantiated/ssetup.
The Cursor.
Cursor adpaters require that a column named _id exists. To overcome this issue the cursor should include both columns. The easiest way to accomplish this is to use null as the 2nd parameter to the query method.
Change
cursor = database.query("favorite",field,null,null,null,null,null);
to
cursor = database.query("favorite",null,null,null,null,null,null);
A Cursor returned from the query method will not be null (cusror.getCount() is how you would check for no rows), so there is no need or use checking if it is null. Additionally the Cursor Adpater (simple or custom) will do the necessary cursor navigation. There is no need to move the cursor. The original has been edited accordingly so no change is required.
Last in regard to the Cursor, closing the Database would close the Cursor (again already edited).
The SimpleCursorAdapter
The issue is that you are using a supplied layout as in android.R.layout.simple_list_item_1 (the 2nd parameter) this expects you to signify which Cursor column (you have signified sentence) will be displayed in it's specific TextView but you have provided a TextView in your own layout.
Changing
int[] to = new int[]{R.id.SentenceAd};
to
int[] to = new int[]{android.R.id.text1};
Is one way to resolve the problem, but it's a waste your time and effort in creating you own layout.
To utilise your own layout then don't make the above change (as you will want the id of the TextView in your layout) but instead change
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, field, to, 0);
to use your layout
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.database_adapter, cursor, field, to, 0);
In short the 2nd (The layout to be used) and the 4th (The Column from the Cursor, by name) and 5th (The ID of the TextView within the layout where the data from the column will be placed) parameters are interdependent/reliant upon each other.

Display data from database into text view (Android)

This is my code for database class (DatabaseHelper.java)
public Cursor getAllData(){
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.rawQuery("select * from "+TABLE_NAME,null);
return res;
}
This is another class which is (MainSuggestion.java)
public class MenuSuggestion extends AppCompatActivity {
DatabaseHelper myDb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu_suggestion);
<br/>
Cursor res = myDb.getAllData();
if (res.moveToFirst()) {
TextView bmi = (TextView) findViewById(R.id.textView9);
TextView kcal = (TextView) findViewById(R.id.textView10);
bmi.setText(res.getString(3));
kcal.setText(res.getString(4));
}
}
}
Can someone tell me, what's wrong with my code?
The exact reason this isn't working is because "myDb" is null on this line.
Cursor res = myDb.getAllData();
However, I recommend you Running a Query with a CursorLoader. It might seem overkill, loading stuff from the database on the main thread like you are can lead to ANR errors.
Query data from database, you have to use:
this.getReadableDatabase();
You use getWritableDatabase() when you want to write, update, delete data into/from database.

Android SQLite Attempt to unlock read lock, not locked by current thread

My application was running fine, until I stumbled across this SQLite error:
java.lang.IllegalMoniterStateException: attempt to unlock read lock, not locked by current thread
I've tried all the other answers on StackOverflow, but they didn't seem to help. They all said I have multiple threads creating instances of my SQLiteDBAdpdter, but I only have on Activity, but its a SherlockFragmentActivity. Each of the classes create a new instance of the SQliteDBAdapter, so I'm not sure if this is why I'm getting this error.
I've been stuck on this for hours, and would GREATLY appreciate any help.
Fragment 1:
public final class NotesFragment extends SherlockListFragment {
NotesDbAdapter db;
private static final int ACTIVITY_EDIT = 1;
private static final int DELETE_ID = Menu.FIRST + 1;
public static NotesFragment newInstance(String content) {
NotesFragment fragment = new NotesFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
db = new NotesDbAdapter(getActivity());
db.open();
if (db.fetchAllNotes().getCount() == 0) {
doWelcomeMessage();
}
db.close();
}
private void doWelcomeMessage() {
// Show welcome dialog
startActivity(new Intent(getActivity(), NotesWelcome.class));
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
return null;
}
db = new NotesDbAdapter(getActivity());
db.open();
if (db.fetchAllNotes().getCount() == 0) {
doWelcomeMessage();
}
db.close();
return ll;
}
}
The error is pointing to db.open(); in the onCreate() method. The open() method is in my SQLiteDBAdapter (NotesDBAdapter) which is as follows:
public NotesDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
And theonCreate() in my NotesDBAdapter is:
#Override
public void onCreate(SQLiteDatabase db) {
SQLiteDatabase checkDB = null;
String myPath = "data/data/com.xxx.xxx/databases/data.db";
checkDB = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READONLY);
if (checkDB != null) {
// exists; do nothing
} else {
// create DB
db.execSQL(DATABASE_CREATE);
}
}
Thanks again!
EDIT
The other fragment
creating a new instance
of the database is called fragment 2, but I did not show its code as its really the same as fragment 1.
I am not sure if this is the problem, but seems you are opening the same database twice for write. Please just open one and share it within your application.
Please also read here: Android threading and database locking
You write:
Each of the classes create a new instance of the SQliteDBAdapter, so
I'm not sure if this is why I'm getting this error.
I'm not sure which classes you mean there, since I only see two partial classes in your example -- NotesFragment and NotesDbAdapter. But if your activity depends on other classes that each open and close the database, then you must ensure that there aren't any recursive attempts to open the DB. (I.e., class A opens the database, then calls class B, which attempts to open the database using its own instance of the DBHelper. At that point, B is trying to open the database while A has it open.)
As dongshengcn noted earlier, that could be the bug. It might be more appropriate to open the database in NotesFragment.onCreate, and close it in NotesFragment.onDestroy, and pass the db object from NotesFragment into these other classes.
The next question is, does your NotesDbAdapter class have an appropriate close method? It should look something like this, and (as mentioned above) be called from NotesFragment.onDestroy.
#Override
public synchronized void close() {
if (mDbHelper != null) {
mDbHelper.close();
mDbHelper = null;
}
super.close();
}

How do I implement autocomplete with cursoradapter

I have an SQLite database containing 2 tables 4000+ rows each used for autocomplete. I saw very simple examples that use an array of strings to provide autocomplete or they use the list of contacts to do the same. Obviously none of these work in my case. How do I use my own SQLite database with my own autocomplete data, for the autocomplete. Do I have to create content providers? How? Please give me some examples because I couldn't find any. I have managed to override SQLiteOpenHelper to copy the database from the assets folder to the /data/data/MY_PACKAGE/databases/ folder on the android. I have created a custom CursorAdapter that uses my custom SQLiteOpenHelper and returns a cursor from runQueryOnBackgroundThread. I get strange errors about some _id column missing. I have added the _id column to my tables. I also don't understand what is the Filterable interface doing and when does my data get filtered. What methods/classes do I need to override? Thanks.
It works.
You need the SQLiteOpenHelper from here. You basically have to copy your database into a specific folder from your assets folder. Then you need a custom CursorAdapter that uses your custom SQLiteOpenHelper.
Here is the onCreate method for my activity.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
KeywordsCursorAdapter kwadapter = new KeywordsCursorAdapter(this, null);
txtKeyword = (AutoCompleteTextView)this.findViewById(R.id.txtKeyword);
txtKeyword.setAdapter(kwadapter);
txtCity = (AutoCompleteTextView)this.findViewById(R.id.txtCity);
btnSearch = (Button)this.findViewById(R.id.btnSearch);
btnSearch.setOnClickListener(this);
}
Here is the cursoradapter. You can pass null for cursor when constructing.
public class KeywordsCursorAdapter extends CursorAdapter {
private Context context;
public KeywordsCursorAdapter(Context context, Cursor c) {
super(context, c);
this.context = context;
}
//I store the autocomplete text view in a layout xml.
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.keyword_autocomplete, null);
return v;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
String keyword = cursor.getString(cursor.getColumnIndex("keyword"));
TextView tv = (TextView)view.findViewById(R.id.txtAutocomplete);
tv.setText(keyword);
}
//you need to override this to return the string value when
//selecting an item from the autocomplete suggestions
//just do cursor.getstring(whatevercolumn);
#Override
public CharSequence convertToString(Cursor cursor) {
//return super.convertToString(cursor);
String value = "";
switch (type) {
case Keywords:
value = cursor.getString(DatabaseHelper.KEYWORD_COLUMN);
break;
case Cities:
value = cursor.getString(DatabaseHelper.CITY_COLUMN);
break;
}
return value;
}
#Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
//return super.runQueryOnBackgroundThread(constraint);
String filter = "";
if (constraint == null) filter = "";
else
filter = constraint.toString();
//I have 2 DB-s and the one I use depends on user preference
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
//String selectedCountryCode = prefs.getString("selectedCountry", "GB");
String selectedCountryCode = prefs.getString(context.getString(R.string.settings_selected_country), "GB");
selectedCountryCode += "";
//Here i have a static SQLiteOpenHelper instance that returns a cursor.
Cursor cursor = MyApplication.getDbHelpers().get(selectedCountryCode.toLowerCase()).getKeywordsCursor(filter);
return cursor;
}
}
Here is the part that returns the cursor: it's just a select with a like condition.
public class DatabaseHelper extends SQLiteOpenHelper {
...
public synchronized Cursor getKeywordsCursor (String prefix) {
if (database == null) database = this.getReadableDatabase();
String[] columns = {"_id", "keyword"};
String[] args = {prefix};
Cursor cursor;
cursor = database.query("keywords", columns, "keyword like '' || ? || '%'", args, null, null, "keyword", "40");
int idcol = cursor.getColumnIndexOrThrow("_id");
int kwcol = cursor.getColumnIndexOrThrow("keyword");
while(cursor.moveToNext()) {
int id = cursor.getInt(idcol);
String kw = cursor.getString(kwcol);
Log.i("keyword", kw);
}
cursor.moveToPosition(-1);
return cursor;
}
...
}
You can also create a custom content provider but in this case it would be just another useless class you need to override.

Categories