Creating nested arrays from an SQLite database in Android - android

I'm creating a simple multiple choice trivia game in Android where the user has three choices. The correct answer choice is pulled directly from the DB, and the two other wrong choices are randomly selected using a method. I put the correct and 2 wrong answers in an array and shuffle the array. The game works fine when in the random selection method I'm only grabbing one column from the row. Now I'd like to grab 3 columns from each random row. So then my problem is how to write the code that is "get two random rows with three columns and put the resulting array into an array that can be shuffled". Here's my working code:
DBAdapter:
// ---Grabs 2 RANDOM ---
public String[] getRandomHA() {
Cursor cursor = this.db.query(
"hdtable Order BY RANDOM() LIMIT 2",
new String[] { KEY_HA }, null, null, null, null, null);
if (cursor != null) {
int i = 0;
String colStrings[] = new String[cursor.getCount()];
while (cursor.moveToNext())
{
colStrings[i] = cursor.getString(0);
i++;
//cursor.close();
}
return colStrings;
}
return null;
}
// --- END Grabs 2 RANDOM ---
Main Activity:
// --- Random 2 answers ----
public void getRandom() {
dba.open();
String[] wrong2 = dba.getRandomHA();
dba.close();
}
shuffle an Array:
// --- shuffle array ----
String[] numbArray = { rightAnswer[2], wrong2[0], wrong2[1] };
List<String> aList = new ArrayList<String>();
for (String s : numbArray)
aList.add(s);
Collections.shuffle(aList);
TextView[] tVs = { optionA_TV, optionB_TV, optionC_TV };
for (int i = 0; i < tVs.length; i++) {
tVs[i].setText(aList.get(i));
}
// --- END shuffle array ----
So is this how I'd write the DB Adapter method?
// ---Grabs 2 RANDOM ---
public String[] getRandomHA() {
Cursor cursor = this.db.query(
"hdtable Order BY RANDOM() LIMIT 2",
new String[] { KEY_Y, KEY_MD, KEY_HA }, null, null, null, null, null);
if (cursor != null) {
int i = 0;
String colStrings[] = new String[cursor.getCount()];
while (cursor.moveToNext())
{
colStrings[i] = cursor.getString(0);
colStrings[i] = cursor.getString(1);
colStrings[i] = cursor.getString(2);
i++;
//cursor.close();
}
return colStrings;
}
return null;
}
// --- END Grabs 2 RANDOM ---
and if the above method is correct, then how would I write the main activity methods to reflect the nested arrays?

The first thing that comes to my mind is to use an instance of the java.util.Random class to call one of the nextXXX() methods to generate a random number. Use that number to select a row from the database to use as your random wrong answer.

Related

Set all returned data to textview from sqlite

I want to set the random data from my table to a single textview.I am able to fetch random data from sqlite but I can not set it to my textview.Probably I should not use setText to put it there.
"Generate" function should bring each time random data from that table.
- main class -
I am having my problem down here (Part of the above class)
private void generatecompliment() {
Cursor cursor = mydb.generatecompliments();
cursor.moveToFirst();
String[] compliments1 = new String[cursor.getCount()];
//cursor.moveToNext();
shwtxt.setText(cursor.getString(1));
}}
- databasehelper class-
public Cursor generatecompliments () {
SQLiteDatabase sqLiteDatabase2 = getReadableDatabase();
String sql ="SELECT * FROM " + TABLE_NAME2 + "ORDER BY RANDOM() LIMIT 1";
return sqLiteDatabase2.rawQuery(sql, null);
}
}
Note:I have a third class which uses another table but I did not put it here since its working fine.
Thanks for help.
You have two options
I believe that you would want something like :-
private void generatecompliment() {
boolean done_first_column = false;
StringBuilder sb = new StringBuilder();
Cursor cursor = mydb.generatecompliments();
if (cursor.moveToFirst()) {
for (String column_name; cursor.getColumnNames) {
if (done_first_column) {
sb.append(" "); //<<<<<<<<<< separator between column data
}
sb.append(cursor.getString(csr.getColumnIndex(column_name));
done_first_column = true;
}
}
cursor.close();
shwtxt.setText(sb.toString());
}
or alternatively
private void generatecompliment() {
StringBuilder sb = new StringBuilder();
Cursor cursor = mydb.generatecompliments();
if (cursor.moveToFirst()) {
for (int i =0; i < cursor.getColumnCount(); i++) {
if (i > 0) {
sb.append(" "); //<<<<<<<<<< separator between column data
}
sb.append(cursor.getString(i);
}
}
cursor.close();
shwtxt.setText(sb.toString());
}
The difference being that the first gets a String array of the column names using the Cursor getColumnNames method, whilst the second retrieves the number of columns retrieved from the Cursor getColumnCount method.
This assumes that by saying all returned data that you want data from all columns concatenated.
This also assumes that you want a space separating the data from each column.
There is also the assumption that shwtxt has been appropriately instantiated.
The above code is in-principle code, it has not been tested or run so it may caontain some small errors.

Alternate way to access multiple columns independently from a database?

My application stores three items: "name", "email", "mobile" in its database under the same table. I want to access each of them independently so that I could display their value under their respective TEXTVIEWs. I access them independently because if I access them all through one single function I won't be able to display the values
Currently, I have to write a function for each column so as to get information from it.
Example to get "email"
public String getUserEmail(String mobile) {
String[] columns = new String[] {USER_EMAIL};
Cursor c = MainDataBase.query(REG_INFO_TABLE, columns, USER_MOBILE_NUMBER + "=" + mobile, null, null, null, null);
String result = "";
int email = c.getColumnIndex(USER_EMAIL);
while(c.moveToNext()) {
result = result + c.getString(email);
}
return result;
}
So, if I need the the "name", I'll have to write another function similar to above to get it.
Now, if I need to access 50 such columns, I'll have to make 50 such functions which does not sound good. Is there any other way I can do this? Can arrays be used here?
You should consider creating a User class that holds the data for each User. Then you change getAllRegInfo() to return a User object. This has the advantage that the rest of your app only accesses Users and has no idea where the data comes from. It is also much more expressive to write
User user = getAllRegInfo();
String name = user.getName();
rather than
String[] user = getAllRegInfo();
String name = user[0];
In addition, a User class can have fields of any type rather than being forced to convert all data to String.
Okay, so I found an alternative. It is using arrays only.
Here is the code:
public String[] getAllRegInfo() {
String[] columns = new String[] {USER_NAME, USER_EMAIL, USER_MOBILE_NUMBER};
Cursor c = MainDataBase.query(REG_INFO_TABLE, columns, null, null, null, null, null);
String[] result = new String[3];
for(int j=0; j<3; j++) {
result[j] = "";
}
int[] column = new int[3];
column[0] = c.getColumnIndex(USER_NAME);
column[1] = c.getColumnIndex(USER_EMAIL);
column[2] = c.getColumnIndex(USER_MOBILE_NUMBER);
while(c.moveToNext()) {
for(int i = 0; i<3; ++i) {
result[i] = c.getString(column[i]);
}
}
return result;
}
Of course, one will have to manually asign the array indexes to the columns. Like this:
column[0] = c.getColumnIndex(USER_NAME);
column[1] = c.getColumnIndex(USER_EMAIL);
column[2] = c.getColumnIndex(USER_MOBILE_NUMBER);
The solution seems to be working fine but I'm not sure how scalable it is.

How to retrieve single sqlite column and store rows into array

Im new to android, and i use Sqlite to store an array of type double into a column called "KEY_VALUE"
public long createEntry(Double rates) {
ContentValues cv = new ContentValues();
cv.put(KEY_VALUE, rates);
return ourDatabase.insert(TABLE, null, cv);
}
I put the data into the columns here via another class
for(i=0;i<37;i++){
entry.createEntry((theRSSHandler.rates()[i]));
}
Now i would like to retrieve the column i saved and get each row as an array element, ive seen and tried other similar solutions but they have not worked.
Here is the method i use to try and get the column data But it has failed.
public Double[] getData() {
String[] col = {KEY_VALUE};
Cursor c = ourDatabase.query(TABLE, col, KEY_VALUE , null, null, null, null);
Double[] result = null;
if(c != null){
c.moveToFirst();
}
int iVal = c.getColumnIndex(KEY_VALUE);
for(c.moveToFirst(); !c.isAfterLast(); c.moveToNext()){
result[c.getPosition()] = c.getDouble(iVal);
}
return result;
}
you are trying to put values in an array that has not been initialized.
Double[] result = null;
needs to be followed up with something like...
result = new Double[100];
i think you probably want to initialize it with the number of records pointed to by the cursor
result = new Double[c.count()];

Skip deleted/empty rows sqlite

I am populating AChartEngine from sqlite database and I need all of the data to be displayed. The problem I'm having is when I delete a record the graph series stops populating at the deleted record. I need to find a way to skip over deleted/empty records and continue populating my graph. I need it to do it the same way listview skips over deleted records and keeps on displaying all rows. I am very new to a lot of this and am having a very difficult time with this. I have tried to write if statements in order to skip deleted/empty rows but nothing seems to work. Thank you for helping!
in my graphing activity:
for (int i = 1; !c.isAfterLast(); i++) {
String value1 = db.getValue1(i);
String value2 = db.getValue2(i);
c.moveToNext();
double x7 = Double.parseDouble(value1);
double y7 = Double.parseDouble(value2);
myseries.add(x7, y7);
}
I am getting error: CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
If I surround with try and catch it will populate rows up until the deleted record.
"EDIT"
in my sqlite database:
public String getValue1(long l) {
String[] columns = new String[]{ EMP_DEPT };
Cursor c = db.query(EMP_TABLE, columns, EMP_ID + "=" + l, null, null, null, null);
if (c != null){
c.moveToFirst();
String value1 = c.getString(0);
return value1;
}
return null;
}
public String getValue2(long l) {
String[] columns = new String[]{ EMP_DATE1 };
Cursor c = db.query(EMP_TABLE, columns, EMP_ID + "=" + l, null, null, null, null);
if (c != null){
c.moveToFirst();
String value2 = c.getString(0);
return value2;
}
return null;
}
Your issue is that your safety net for commands on rows that don't exist is to use if (c != null){ and then perform your commands inside that block, but a Cursor request from a query will never come up null, it will instead result in a cursor object with no rows.
A more appropriate solution to use this as your safety net instead if (c.moveToFirst()){ Because the method itself returns a boolean for if the method actually carried itself out in the first place - true if it moved and false if not (which occurs when there's no rows to move into). another check, if you wish, would be to see how many rows the cursor has with c.getCount().
Additionally, you should combine your methods so that you don't make redundant queries to the database:
public String[] getValues(long l) {
String[] results = new String[2];
String[] columns = new String[]{ EMP_DEPT, EMP_DATE1 };
Cursor c = db.query(EMP_TABLE, columns, EMP_ID + "=" + l, null, null, null, null);
if (c.moveToFirst()) {
results[0] = c.getString(0);
results[1] = c.getString(1);
} else {
Log.d("GET_VALUES", "No results formed from this query!");
}
return results;
}
You should use a single query to get all values at once:
SELECT Date1 FROM MyTable WHERE id BETWEEN 1 AND 12345
or:
db.query(EMP_TABLE, columns, EMP_ID + " BETWEEN 1 AND " + ..., ...);
Then missing values will just not show up when you iterate over the cursor.

get random no between range without duplicate

All
I want logical help. I have 100 row in database and get all rows random ally without duplication I have used below code.
public ArrayList<Rows> getRows(){
ArrayList<Rows> myRaw=new ArrayList<Rows>();
Cursor rawCursor=this.db.query(DB_TABLE, null, null, null, null, null, null);
if(rawCursor.getCount()>0){
Random rng = new Random();
rawCursor.moveToFirst();
do {
// Ideally just create one instance globally
ArrayList<Rows> generated = new ArrayList<Raws>();
for (int i = 0; i < 371; i++)
{
while(true)
{
Integer next = rng.nextInt(371) + 1;
rawCursor.moveToPosition(next);
Rows raw=new Raws(rawCursor.getInt(rawCursor.getColumnIndex("_id")),rawCursor.getString(rawCursor.getColumnIndex("raw")),rawCursor.getInt(rawCursor.getColumnIndex("fav")));
if (!generated.contains(raw))
{
// Done for this iteration
generated.add(raw);
break;
}
}
}
myRaw=generated;
} while (rawCursor.moveToNext());
rawCursor.close();
}
return myRaw;
}
Thanks All
You can tell the database to order the records by some random number:
cursor = db.query(DB_TABLE, null, null, null, null, null, "random()");
What about Collections shuffle?
http://developer.android.com/reference/java/util/Collections.html#shuffle(java.util.List)
public ArrayList<Rows> getRows() {
ArrayList<Rows> myRaw = new ArrayList<Rows>();
Cursor rawCursor = this.db.query(DB_TABLE, null, null, null, null, null, null);
if (rawCursor.getCount() > 0) {
// get all the rows
rawCursor.moveToFirst();
do {
Rows raw = new Raws(rawCursor.getInt(rawCursor.getColumnIndex("_id")), rawCursor.getString(rawCursor.getColumnIndex("raw")), rawCursor.getInt(rawCursor.getColumnIndex("fav")));
myRaw.add(raw);
} while (rawCursor.moveToNext());
rawCursor.close();
}
// shuffle the rows in some kind of random order
Collections.shuffle(myRaw);
return myRaw;
}
The answer provided by #CL. could be a better option, but the main difference is that the shuffle method has an option to provide your own Random object, this means that you can seed the random.
//Random with seed;
Random r = new Random(68498493);
Collections.shuffle(myRaw, r);

Categories

Resources