i'm searching for hours now, to get a solution for this problem:
at the very beginning of my android app, a layout with buttons is shown to the user. if he clicks on the button "Tasks" a listView should pop up (another activity and layout) to show him all available Tasks, and with a click on one he can do even more things, but they're not necessary for my problem. the point is, the app won't get any Data out of the Database, but when I Step Into or Step Over the lines which call a method for all the DBStuff it works.
Here are the necesssary lines:
if (connection1.OpenDatabase(1, getDataBaseName()))
{
CTask = connection1.DBQueryTable(getDataBaseName(), "Tasks", TempFieldT);
CEquipment = connection1.DBQueryTable(getDataBaseName(), "Equipment", TempFieldE);
connection1.CloseDatabase();
}
so he will run over those lines, execute the lines beneath, but wont give any Data back, when i'm not supervising it with breakpoints, and the steps. when i do it, all things work the way they should.
The Database Stuff the app runs through at this place.
public Android.Database.ICursor DBQueryTable(string DataBaseName, string TableName, string[] Fields)
{
FindDBPath(DataBaseName);
Android.Database.ICursor c;
string TempF = "";
string str = "";
foreach (string n in Fields)
{ TempF += n + ","; }
SQLQuery = "SELECT " + (str = TempF.TrimEnd(',')) +" FROM " + TableName;
c = sqldTemp.RawQuery(SQLQuery, null);
return c;
}
so why do the app/compiler/debugger behave like this? are there any mistakes i did, but i can't figure out right now?
Ps: yeah i know there is a query function, but thats not necessary here as long as it would provide a solution to my problem.
Your DBQueryTable method returns a cursor. That will become invalidated as soon as you close the connection in the following line:
connection1.CloseDatabase();
You should keep the connection open for as long as you need the cursor. For example, you could fetch all the data from the cursor and then close the connection.
Related
My application allows a user to call the most recent number that was called out. By hitting the "Call" button with an empty text box it will grab the latest Outgoing number in my ORM database. The issue however happens on only some phones.
When I pull my data I do so with the following code:
Dao<RecentCallsInfo, Integer> dao = null;
if (getActivity() instanceof MainActivity) {
MainActivity main = (MainActivity) getActivity();
dao = main.getDatabaseHelper().getRecentDataDao();
}
QueryBuilder<RecentCallsInfo, Integer> qb = dao.queryBuilder();
qb.orderBy(RecentCallsInfo.RECENT_COLUMN_ID, false);
qb.where().eq(RecentCallsInfo.RECENT_COLUMN_CALL_TYPE, "Outgoing");
// when you are done, prepare your query and build an iterator
CloseableIterator<RecentCallsInfo> iterator = dao.iterator(qb.prepare());
// get the raw results which can be cast under Android
AndroidDatabaseResults results = (AndroidDatabaseResults)iterator.getRawResults();
Cursor c = results.getRawCursor();
if(c.moveToFirst()){
if(!c.getString(RecentQuery.COLUMN_NUM).isEmpty()){
System.out.println("Recent Record: \n Name:" + c.getString(RecentQuery.COLUMN_NAME) +
"\nNum:" + c.getString(RecentQuery.COLUMN_NUM) + "\nNumType:" + c.getString(RecentQuery.COLUMN_NUM_TYPE)+
"\nCallType:" + c.getString(RecentQuery.COLUMN_CALL_TYPE));
etcalle.setText(c.getString(RecentQuery.COLUMN_NUM));
}
}
//RecentQuery.COLUMN_NAME = 5
//RecentQuery.COLUMN_NUM = 6
//RecentQuery.COLUMN_NUM_TYPE = 0
//RecentQuery.COLUMN_CALL_TYPE = 2
When I debug my c Cursor, it gives me these columns with these values
[recentNumberType, recentCallCost, recentCallType, recentCallerID, recentDate, recentName, recentNumber, _id]
Name:anthony
Num:(111) 111-1111
NumType:Mobile
CallType:Outgoing
When I get my c Cursor on another phone I get
[recentCallCost, recentCallType, recentCallerID, recentDate, recentName, recentNumber, recentNumberType, _id]
Name:(111) 111-1111
Num:Mobile
NumType:FREE
CallType:1867
So when I try and pull my data by index I get different values. Why does this happen? Both phones are Nexus 5 and on 4.4.2.
Any insight on this would be great. Thanks!
Columns can "change". For example, consider this case.
Version 1 of an app creates the T table, with columns A, C
In version 2, you want to change the structure of the database. So you add the B column to your "create table" scripts. In new devices, this table will have columns A, B, C.
However, in the onUpgrade() part, you just add column B (via ALTER TABLE), and the structure will end up as A, C, B.
In general it's a bad idea to use fixed ("integer") column indexes, unless you also specify which columns you want (i.e. not using SELECT *). Using getColumnIndex() (outside the loop) is safer.
Part of my functionality requires updating a value in every row (only happens rarely, when a user selects a certain setting).
Trouble is, the query takes a good few minutes to perform (at best), and there's only 269 test records. Is there any way this could be optimized?
String allRecords = "SELECT id, weight FROM Workout_Entry";
Cursor cursor = db.rawQuery(allRecords, null);
int rows = cursor.getCount();
int id;
double weight;
try
{
if (cursor.moveToFirst())
{
do
{
for (int i = 0; i < rows; i++)
{
id = cursor.getInt(0);
weight = cursor.getInt(1) / 2.2;
String strFilter = "id = " + id;
ContentValues args = new ContentValues();
args.put("weight", weight);
db.update("Workout_Entry", args, strFilter, null);
}
} while (cursor.moveToNext());
}
} finally
{
cursor.close();
}
(db).close();
Thanks!
Just push the work to the database engine instead of pulling the data out one row at a time and firing up a new update query each time. Replace your code with something like:
db.execSQL("UPDATE Workout_Entry SET weight=weight/2.2");
Also, since this seems to be some kind of metric/imperial unit conversion, consider keeping the data in just one format in the database and convert/format to the appropriate unit for display purposes.
You should learn to use transactions - you can see example of how you use that in this presentation of mine.
Also showing the impact of not using the transaction.
Ok, I've realised my error. I had a do while loop for every record, and inside of that was a for loop which looped through x many times, where x was the amount of existing records.
So it was going through O(n)² times instead of O(n).
Thanks to those who replied! I found both of your comments useful.
So I'm still building a Database to support a project of mine. There are two different things to be saved: first, attribute values of some player objects and second, simple values stored in a java class.
ATM my problem lies in the process of loading values of a player object and writing it in the respective class.
Now let's see some code:
Following you see the method I want to use for saving the values in the database.
That works fine atm, but I just realized I'm still passing the contentValues object an extra value for the 'ID' , which I did set - and planned to keep that way - as autoincrement.
Any Idea how to work this in accordingly?
public void savePlayer(Player player[]) {
for (int i = 0; i <= 3; i++) {
playerValues.put("ID", i);
playerValues.put("Name", player[i].getName());
playerValues.put("HP", player[i].getHp());
playerValues.put("Satisfaction", player[i].getsatisfaction());
playerValues.put("Hygiene", player[i].isHygieneInt());
playerValues.put("IsAlive", player[i].isAliveInt());
}
db.insert("playertable", null, playerValues);
}
Okay, hold on to your hats because this might look a bit like spaghetti - the load-method:
public void loadPlayer() {
String[] namecolumn = { "Name" };
String[] intcolumn = { "ID, HP, Satisfaction, Hygiene, IsAlive" };
String[] namesToString = new String[4];
for (int j = 0; j <= 3; j++) {
Cursor playerCursorName = db.query("playertable", namecolumn, "ID="
+ j, null, null, null, null);
namesToString = cursorToString(playerCursorName);
Resource.playerArray[j].setName(namesToString[j]);
}
for (int i = 0; i < 3; i++) {
int[] restToInt;
Cursor playerCursorInt = db.query("playertable", intcolumn, "ID="
+ i, null, null, null, null);
restToInt = cursorToInt(playerCursorInt, 4);
Resource.playerArray[i].setHp(restToInt[i]);
Resource.playerArray[i].setsatisfaction(restToInt[i]);
Resource.playerArray[i].setHygieneInt(restToInt[i]);
Resource.playerArray[i].setAliveInt(restToInt[i]);
}
}
Yeah, I know this looks pretty ugly but let me explain it:
Because there are 4 player objects I planned on iterating through the database entries by using the ID as identifier to get exactly one row at a time and writing the name and the other values of this object in the java class where I want to manage them within my project.
Note: same problem with autoincrement here than in the save method
In addition, I get a CursorIndexOutOfBoundsException when calling loadPlayer because
Index -1 is being requested - isn't that the result of an operation on the database resulting in an error?
Yeah that's pretty much it, I'll provide you with additional code if requested, hope someone can help me
You are using Cursors in a slightly odd way here.
The point of a Cursor is to ask SQLite to do the hard work of fetching data for you, and your job is simply to use the cursor to iterate through the returned values.
Firstly, I would change the query here to ask for all values in the table (and perhaps put some condition to constrain what you get back), to make sure your cursor then contains all your values.
Then, I would loop through the cursor's values by using a while loop, (with cursor.moveToPosition(-1) before the loop) moving along the cursor by using cursor.moveToNext().
See the API for more information:
http://developer.android.com/reference/android/database/Cursor.html
With regard to the autoincrement problem, as far as I can remember you can leave out the ID and use db.insert() without that field and the database will provide an ID for you.
You shouldn't have the same issue in your load method because it doesn't make sense to autoincrement when loading, you just get back what's in the database.
I have an SQLite query in my android app that seems to crash when it takes too long to execute. It crashes with NullPointerException and tells me the line number...
When I put breakpoints around that line and see that it always gets filled with a variable, the app does not crash and does what it is supposed to.
So aside from having a phantom null pointer, it appears the problem is that the breakpoints actually slow things down giving the query time to complete. Without breakpoints it always crashes without fail.
Others here seem to have a similar problem, and I've read some things about SQLite taking an erratic amount of time to complete tasks, but this table should only ever have a few entries in it (the one I'm testing should only have three entries, 4 columns)
Suggestions on how to make it not crash? Perhaps put a thread wait inside the method that makes the query?
public void fetchItemsToRemove() throws SQLException{
Cursor mCursor =
mapDb.query(myMain_TABLE, new String[] {myOtherId, myCustomID, myDATE}, null, null, null, null, null);
if(mCursor.moveToFirst())
{
do
{
/*taking "dates" that were stored as plain text strings, and converting them to
*Date objects in a particular format for comparison*/
String DateCompareOld = mCursor.getString(mCursor.getColumnIndex(myDATE));
String DateCompareCurrent = "";
Date newDate = new Date();
DateCompareCurrent = newDate.toString();
try {
DateCompareOld = (String)DateCompareOld.subSequence(0, 10);
DateCompareCurrent = (String)DateCompareCurrent.subSequence(0, 10);
SimpleDateFormat dateType = new SimpleDateFormat("EEE MMM dd");
Date convertDate = dateType.parse(DateCompareOld);
newDate = dateType.parse(DateCompareCurrent);
if(convertDate.compareTo(newDate) < 0)
{
//remove unlim id
mapDb.delete(myMain_TABLE, myDATE + "=" + mCursor.getString(mCursor.getColumnIndex(myDATE)), null);
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}while(mCursor.moveToNext());
mCursor.close();
}
else
{
mCursor.close();
}
}
Now "line 342" where it crashes with NullPointerException is DateCompareOld = (String)DateCompareOld.subSequence(0, 10); where it gets a subsequence of the string. If it gets here and is null, this means the string was never filled at String DateCompareOld = mCursor.getString(mCursor.getColumnIndex(myDATE));
as if the query just got skipped because it took too long. Do note this is in a while loop, and I have done tests to make sure that the mCursor never goes out of bounds.
You're deleting things from a DB table whilst iterating over the results of a query from that table. Sounds a bit dangerous.
Try building a list, inside the loop, of things to be deleted, and then delete them in a single go after the loop finishes.
Also, wrap the entire thing in a DB transaction. When you're modifying the DB in a loop, that can make a huge difference to performance.
EDIT: a quick explanation of transactions:
A transaction allows you to combine a bunch of DB queries/modifications into a single atomic operation which either succeeds or fails. It's primarily a safety mechanism so your DB isn't stuck in an inconsistent state if something goes wrong half way through, but it also means that any modifications are committed to the DB's file storage in a single shot rather than one at a time, which is much faster.
You start the transaction at the start of your function:
public void fetchItemsToRemove() throws SQLException{
db.beginTransaction();
Cursor mCursor = ....
You set it as successful if the whole function completes without errors. This probably means you want to remove the inner try/catch and have an outer try/catch enclosing the loop. Then at the end of the try{ }, you can assume nothing's gone wrong, so you call:
db.setTransactionSuccessful();
Then, in a finally clause, to make sure you always close the transaction whether it's successful or otherwise:
db.endTransaction();
I am having some trouble implementing a sqlite database in my simple android application:
a user is displayed a list of animals in a Listview.Upon selecting an animal the user is brought to an activity "Animal",which will display a picture of the animal and give them options to
view Animal Bio
Back
All very simple so far, right?
I have working the database, which will populate the listView of animals.Database currently looks like
Table Animal-
_ID,
Name
Table Biography-
_ID,
Bio
This is where I would welcome any helpful advice on my problem, or on how to improve my implementation.
Currently populating the DB as follows
long populateDB(){
String[] animalName = {"Lion" "Zebra", "Tiger", "Gorilla",...};
String[] animalBios = {"Found in the "...}
ContentValues animalNameVals = new ContentValues();
ContentValues animalBioVals = new ContentValues();
long[] rowIds = new long[animalName.length];
// Populate the animal table
for(int i = 0; i < animalName.length; i++){
animalNameVals.put(KEY_ANIMALNAME, animalName[i]);
rowIds[i] = db.insert(ANIMAL_TABLE, null, animalNameVals);
}
// Populate the Bio table
for(int j = 0; j < bios.length; j++){
animalBioVals.put(KEY_BIO, bios[j]);
rowIds[j] = db.insert(BIOS_TABLE, null, animalBioVals);
}
return rowIds[0];
}
And had planned on being able to tell database which animal on list was selected by passing extras with the intent, eg if position on listItemClick == 1, pass in tiger and retrieve tiger bio from db.
Problems:
Then on the Animal activity page is getExtra() == tiger, telling the activity that tiger was selected from the list and to load this bio from the DB..well, I cannot see an efficient method of implementation for this idea and am struggling to do so.
My second headache comes from adding the bio to the application from the Db.Originally I had a test bio hardcoded in a string, shown in a TextView.Is there a way to retrieve a string from a cursor and add it to the TextView id?I understand I will need some adapter, what I do not understand is why cant it be as simple as setResource(R.id.bio) = bio.
Thanks you for reading and any help is much appriciated.
First problem: First of all, I'm not sure why you don't have the column Bio in the Animal-table? As no Bio would fit to any other animal than itself, you can safely do this. By doing this you can query the database upon selection and pass the entire object (including name of animal and bio) to the next Activity and use this to get your information. If this was somewhat unclear, let me know and I'll try to explain it better.
Second problem: You can get values from tables (there of also Strings) using a Cursor. To get the String you can do something like this where cursor is the Cursor with your result from the database:
String bio;
// Move Cursor to its first element
if(cursor.moveToFirst()) {
// Make sure the cursor is not null
if(cursor != null) {
bio = cursor.getString(cursor.getColumnIndex("Bio")));
}
}
Sidenote: If I read the code correctly, it seems that you use long for ID's? The usual thing to go about ID's is integers as far as I know.