I've got a long running task that I run onResume on my activity. The task involves querying a database then decrypting some data, then manually sorting it then updating the sort order in the database using a transaction.
This works fine when I run it from the Activities main UI thread, but when I execute the same task from within an AsyncTask I always get these errors:
I/SqliteDatabaseCpp(5166): sqlite returned: error code = 1, msg = no such table: Household, db=/mnt/sdcard/myDatabase.db
no such table: while compiling: no such table: Household: , while compiling: SELECT DISTINCT street FROM Household WHERE street IS NOT NULL AND LENGTH(LTRIM(RTRIM(street)))>0
I know that the database exists and that SQL statement is fine because it runs fine outside the AsyncTask. Is there something about access my database from within an AsyncTask that causes problems?
I'm getting errors on the "SELECT DISTINCT" raw query below.
private boolean update_street_sort_order() {
boolean returnValue = false;
DBUtilities objDbUtil = null;
Cursor cCases = null;
final String SORT_ATTRIBUTE = "street_sort_order";
final int STREET_INDEX = 0;
final int ENCRYPTED_STREET = 0;
final int DECRYPTED_STREET = 1;
try {
objDbUtil = DBUtilities.getInstance(this);
if (objDbUtil != null) { // Get list of cases
ArrayList<String[]> alStreet = new ArrayList<String[]>();
SQLiteDatabase sqlitedatabase = objDbUtil.getDatabase();
if (sqlitedatabase != null && sqlitedatabase.isOpen()) {
cCases = sqlitedatabase.rawQuery("SELECT DISTINCT street "
+ "FROM Household " + "WHERE street IS NOT NULL "
+ "AND LENGTH(LTRIM(RTRIM(street)))>0", null);
String _password = this.context.getPassword();
if (cCases != null && cCases.moveToFirst()) {
do { // Create list of en/decrypted streets
alStreet.add(new String[] {
cCases.getString(STREET_INDEX),
Crypto.decrypt(_password,
cCases.getString(STREET_INDEX)) });
} while (cCases.moveToNext());
}
if (cCases != null) {
cCases.close();
cCases = null;
}
int alStreet_length = alStreet.size();
if (alStreet_length > 0) {
Collections.sort(alStreet, new Comparator<String[]>() {
#Override
public int compare(String[] lhs, String[] rhs) {
return lhs[DECRYPTED_STREET]
.compareToIgnoreCase(rhs[DECRYPTED_STREET]);
}
}); // sort decrypted street using custom comparator
StringBuilder sql_transaction = new StringBuilder(
"BEGIN TRANSACTION;" + "UPDATE Household SET "
+ SORT_ATTRIBUTE + "=NULL;");
for (int i = 0; i < alStreet_length; i++) {
sql_transaction.append(String.format(
"UPDATE Household " + "SET "
+ SORT_ATTRIBUTE + "=%1$d "
+ "WHERE street=\"%2$s\";", i,
alStreet.get(i)[ENCRYPTED_STREET]));
}
sql_transaction.append("COMMIT;");
// execute transaction
sqlitedatabase.execSQL(sql_transaction.toString());
}
returnValue = true;
}
}
} catch (Exception e) {
Log.e(Utilities.getFullMethodName(e), e.getMessage());
} finally {
if (objDbUtil != null) { // release resources
objDbUtil.close();
objDbUtil = null;
}
}
return returnValue;
Related
I'm getting many time repeating data from Sqlite / Android database. I want to get recode without repeating in Android cursor.
Here's my query:
public Cursor getQuizQuiestion(String cat, String level, String questionNo) {
String QUERY_SELECT_QUIESTION = "SELECT * FROM " +TABLE_QUIESTION +" WHERE "+COL_CAT+ " = '" +cat+"' AND "
+COL_LEVEL+ " = " +level+" ORDER BY RANDOM() LIMIT 1";
Cursor cursor = db.rawQuery(QUERY_SELECT_QUIESTION, null);
return cursor;
}
I Have Simple Example if I Used In My Project I think MayBe IT's Help You;
public ArrayList<ModelRandomList> getRandomData(String city){
ArrayList<ModelRandomList> modelRandomListArrayListLists = new ArrayList<ModelRandomList>();
String queryRandomData ="SELECT DISTINCT * FROM "+TABLE_NAME+" WHERE "+COL_CITY + "=?"+ "Order BY RANDOM()";
Cursor cursor = db.rawQuery(queryRandomData,new String[] { String.valueOf(city) });
if(cursor.getCount() != 0){
while (cursor.moveToNext()){
/*mName =cursor.getString(0);
mCity = cursor.getString(1);
Log.d(TAG,mName +" City "+mCity );*/
ModelRandomList modelRandomList = new ModelRandomList();
modelRandomList.setUserName(cursor.getString(0));
modelRandomList.setUserCity(cursor.getString(1));
modelRandomListArrayListLists.add(modelRandomList);
}
Random random = new Random();
Collections.shuffle(modelRandomListArrayListLists,random);
}
Log.d(TAG, "Get Random Totla No of Recode Found "+cursor.getCount());
return modelRandomListArrayListLists;
}
and in Your Activity
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private SqlLiteDataBaseHelper sqlLiteDataBaseHelper;
private Button btGetRandomData;
private ArrayList<ModelRandomList> modelRandomLists;
private Button btSingleRandomData;
private int position = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
modelRandomLists = new ArrayList<ModelRandomList>();
sqlLiteDataBaseHelper = new SqlLiteDataBaseHelper(MainActivity.this);
try{
if(sqlLiteDataBaseHelper.checkDataBase()){
Log.e(TAG, "Data Base Already Exists");
}else {
sqlLiteDataBaseHelper.CopyDataBaseFromAsset();
}
sqlLiteDataBaseHelper.openDataBase();
try {
Log.e(TAG, "No Of Racode In DataBase " + sqlLiteDataBaseHelper.getDataCount());
}catch (Exception e){
e.printStackTrace();
}
}catch (Exception e){
e.printStackTrace();
}
init();
}
private void init() {
btGetRandomData = (Button)findViewById(R.id.btRandomData);
btSingleRandomData = (Button)findViewById(R.id.btSingleRandomData);
}
#Override
protected void onResume() {
super.onResume();
btGetRandomData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
modelRandomLists = sqlLiteDataBaseHelper.getRandomData("A");
for (ModelRandomList crt : modelRandomLists) {
Log.e(TAG, " " + crt.getUserName());
Log.e(TAG, " " + crt.getUserCity());
}
}
});
btSingleRandomData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try{
Log.d(TAG,modelRandomLists.get(position).getUserName());
position ++;
}catch (Exception e){
e.printStackTrace();
position =0;
}
}
});
}
}
You would have to keep a track of what questions have been seen before. What about this:
private List<Integer> seenQuestions = new ArrayList<>();
public Cursor getUseenQuizQuestion(String cat,String level,String questionNo) {
Cursor cursor = getQuizQuiestion(cat, level, questionNo);
while(cursor == null) { // This could be an infinite loop!!
cursor = getQuizQuiestion(cat, level, questionNo);
}
return cursor;
}
private Cursor getQuizQuiestion(String cat,String level,String questionNo){
String QUERY_SELECT_QUIESTION = "SELECT * FROM " +TABLE_QUIESTION +" WHERE "+COL_CAT+ " = '" +cat+"' AND "
+COL_LEVEL+ " = " +level+" ORDER BY RANDOM() LIMIT 1";
Cursor cursor = db.rawQuery(QUERY_SELECT_QUIESTION, null);
if(cursor.moveToFirst()) {
int resultId = cursor.getString(cursor.getColumnIndexOrThrow("_id"));
if(seenQuestions.contains(resultId)) {
cursor.close();
return null;
}
seenQuestions.add(resultId);
}
return cursor;
}
^ the code sample above has many flaws and could loop infinitely.
But the point is you need to keep track of what has been returned and query again if you have seen it.
Alternatively, you could allow your DB query to return all data and then use a Random value to select one of the items.
There is no way to create unique results if you are querying over and over again.
Since you are not using the questionNo parameter and return a cursor anyway: why not just remove the limit 1 and add the distinct clause to your statement?
If you do it that way, you can use your cursor to iterate over the unique questions:
String QUERY_SELECT_QUIESTION = "SELECT DISTINCT * FROM " +TABLE_QUIESTION +" WHERE "+COL_CAT+ " = '" +cat+"' AND "
+COL_LEVEL+ " = " +level+" ORDER BY RANDOM()";
Then you can iterate over the questions until you have none or whatever your conditions are:
Cursor cursor = db.rawQuery(QUERY_SELECT_QUIESTION, null);
try {
while (cursor.moveToNext()) {
//display question or copy them to a member or whatever
}
} finally {
cursor.close();
}
I am trying to do Order by to fetch the records from higher to lower values , but the sorting is not happening, i am getting the records randomly.
Here is my code , please let me know , where i am going wrong:
public void fetchTopRecords() {
int i = 0;
String where = "SELECT * FROM " + DATABASE_TABLE_2 + " ORDER BY "
+ COL_C + " ASC LIMIT 6";
Cursor c = db.rawQuery(where, null);
if (c != null) {
if (c.moveToFirst()) {
do {
String pckname = c.getString(COL_A);
array_pck.add(pckname);
int marks = c.getInt(COL_C);
i++;
} while (c.moveToNext());
}
}
use the below code it will work :
public void fetchTopRecords() {
String where = "SELECT * FROM " + DATABASE_TABLE_2 + " ORDER BY "
+ COL_C + " DESC LIMIT 6";
Cursor c = db.rawQuery(where, null);
if (c != null) {
if (c.moveToFirst()) {
do {
String pckname = c.getString(COL_A);
array_pck.add(pckname);
int marks = c.getInt(COL_C);
} while (c.moveToNext());
}
}
I'm messing around with some SQLite databases for an Android app. I have a 'player' table with several players, and a one-to-many 'skill' table which has each player's skill points, like Shooting and Rebounding.
I have one activity in the app for actually filling out textboxes and inserting a player into the database. When the user hits the 'Add Player' button, a row is inserted into the 'player' table and a row is inserted into the 'skills' table which has a foreign key that references the 'player' table. After these inserts, I did a query to check if I could read the 'Shooting' value from the 'skills' table and put it in a Toast notification. That worked fine, and the code I used is here:
SQLiteDatabase db2 = dbHelper.getReadableDatabase();
String[] projection = { "shooting" };
String sortOrder = "shooting" + " DESC";
Cursor c = db2.query(
"skills", // The table to query
projection, // The columns to return
null, // The columns for the WHERE clause
null, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
c.moveToFirst();
int shooting = c.getInt(c.getColumnIndexOrThrow("shooting"));
Toast.makeText(this, "" + shooting, Toast.LENGTH_SHORT).show();
After I saw that this was working, I commented it out and put in an Intent to make the app switch to the 'Roster' activity after the player and skills are inserted. On the 'Roster' activity, I want to get each player's 'Shooting' skill. When I use the exact same code from above (which works from the other activity) I get an error which says:
06-16 15:59:42.602: E/AndroidRuntime(31537): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.silverray.messaround/com.silverray.messaround.Roster}: java.lang.IllegalArgumentException: column 'shooting' does not exist
I can't figure out why it's saying the 'shooting' column doesn't exist when I know I included it in my SQL Create statement, and I was even able to read this exact same column with the same code from another activity.
Thanks for reading. Any ideas?
EDIT: This is the full code for the Roster activity:
public class Roster extends Activity {
int teamID = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_roster);
// CHECK ROSTER
DatabaseContract dbContract = new DatabaseContract();
DatabaseContract.DbHelper dbHelper = dbContract.new DbHelper(this);
SQLiteDatabase dbCheck = dbHelper.getReadableDatabase();
Intent intent = getIntent();
int ID = intent.getIntExtra("ID", 1);
teamID = ID;
String stringID = String.valueOf(ID);
String[] projection = { "_id, playerFirstName, playerLastName, playerPosition" };
String sortOrder = "playerFirstName" + " ASC";
Cursor c = dbCheck.query(
"player",
projection,
null,
null,
null,
null,
sortOrder
);
c.moveToFirst();
int rowsAffected = c.getCount();
if (rowsAffected < 1) {
TextView rosterList = (TextView) findViewById(R.id.txtListRoster);
rosterList.setText("Your team doesn't have any players!");
c.close();
dbCheck.close();
} else {
String players = "";
for (int l = 0; l < rowsAffected; l++) {
String playerName = c.getString(c.getColumnIndexOrThrow("playerFirstName"));
String playerLastName = c.getString(c.getColumnIndexOrThrow("playerLastName"));
String position = c.getString(c.getColumnIndexOrThrow("playerPosition"));
int playerID = c.getInt(c.getColumnIndexOrThrow("_id"));
String player_ID = String.valueOf(playerID);
String pos = "";
if (position.equals("Point Guard")) {
pos = "PG";
} else if (position.equals("Shooting Guard")) {
pos = "SG";
} else if (position.equals("Small Forward")) {
pos = "SF";
} else if (position.equals("Power Forward")) {
pos = "PF";
} else if (position.equals("Center")) {
pos = "C";
}
SQLiteDatabase db2 = dbHelper.getReadableDatabase();
String[] projection2 = { "shooting" };
String sortOrder2 = "shooting" + " DESC";
Cursor c2 = db2.query(
"skills",
projection2,
null,
null,
null,
null,
sortOrder2
);
c2.moveToFirst();
//** Everything works until this line:
int shooting = c2.getInt(c.getColumnIndexOrThrow("shooting"));
players += playerName + " " + playerLastName + " (" + pos + ") Shooting: ";
if (l != (rowsAffected - 1)) {
players += "\n";
}
TextView rosterList = (TextView) findViewById(R.id.txtListRoster);
rosterList.setText(players);
if (l != (rowsAffected - 1)) {
c.moveToNext();
}
c2.close();
}
c.close();
dbCheck.close();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.roster, menu);
return true;
}
public void addPlayer(View view) {
Intent goToAddPlayer = new Intent(this, AddPlayer.class);
goToAddPlayer.putExtra("ID", teamID);
this.startActivity(goToAddPlayer);
this.finish();
return;
}
}
int shooting = c2.getInt(c.getColumnIndexOrThrow("shooting"));
should be
int shooting = c2.getInt(c2.getColumnIndexOrThrow("shooting"));
You are now working on 2nd query but trying to get column index from 1st.
I'm not pretty sure if this question is for here, but I want to ask all of you guys, who really can give me some advices of how to optimize better this piece of code, to run better in proper way and faster. The thing that I'm doing is that I'm downloading data over internet as JSON, parsing it and insert it in sqlite database. If the json string is not big, there is not a big problem for me, but when my json contains a lot of arrays and objects in some situations I'm waiting like 10-13 minutes to download/parse/insert all data in database, which is too much time.
The code that I'm showing is some kind of test code, because I was trying to implement InsertHelper to see if there will be a bit difference in speed, but the result is the same for now. Here is the code :
UserDatabaseHelper userDbHelper = RPCCommunicator.rpcUserDbHelper;
SQLiteDatabase db = userDbHelper.getWritableDatabase();
InsertHelper ih = new InsertHelper(db, "cards");
ih.prepareForInsert();
//ContentValues values = new ContentValues();
ContentValues valuess = new ContentValues();
try {
int objectid = ih.getColumnIndex("objectId");
ih.bind(objectid, objectId);
//values.put("objectId", objectId);
Log.d("", "ObjectId: " + objectId);
int objectoid = ih.getColumnIndex("objectOid");
ih.bind(objectoid, objectOid);
//values.put("objectOid", objectOid);
String jsonData = new String(cardBuffer, "UTF-8");
Log.d("JSONDATA", "JSONDATA VALID OR NOT : " + jsonData);
json = new JSONObject(jsonData);
JSONObject jsonObj = (JSONObject) new JSONTokener(jsonData).nextValue();
int collectionID = ih.getColumnIndex("collectionId");
int collectionId = Integer.parseInt(jsonObj.optString("collection_id","0"));
Log.d("Collection Id ", "Show Collection Id : " + collectionId);
if(collectionId!=0)
ih.bind(collectionID, collectionId);
//values.put("collectionId", collectionId);
int categoryID = ih.getColumnIndex("categoryId");
int categoryId = Integer.parseInt(jsonObj.optString("category_id", "0"));
Log.d("Category Id ", "Show Category Id : " + categoryId);
if(categoryId!=0)
ih.bind(categoryID, categoryId);
//values.put("categoryId", categoryId);
int dateCreated = ih.getColumnIndex("dateCreated");
String date = jsonObj.optString("date_created");
if(date!=null)
ih.bind(dateCreated, date);
//values.put("dateCreated", date);
int titlee = ih.getColumnIndex("title");
String title = jsonObj.optString("title");
Log.d("Title", "Show Title : " + title);
if(title!=null)
ih.bind(titlee, title);
//values.put("title", title);
// ... some other variables to get from JSON
JSONObject stats = jsonObj.optJSONObject("statistics");
if (jsonObj.has("statistics")) {
ContentValues values2 = new ContentValues();
InsertHelper ihr = new InsertHelper(db, "cardstats");
Iterator<Object> keys = stats.keys();
while (keys.hasNext()) {
ihr.prepareForInsert();
String key = (String) keys.next();
JSONObject obj = new JSONObject();
obj = stats.getJSONObject(key);
int paramId = Integer.parseInt(obj.optString("param_id"));
int cardIdTable = ihr.getColumnIndex("cardId");
ihr.bind(cardIdTable, objectId);
values2.put("cardId", objectId);
int statKey = ihr.getColumnIndex("statKeyId");
ihr.bind(statKey, paramId);
values2.put("statKeyId", paramId);
int catIdTable = ihr.getColumnIndex("catId");
int catId = Integer.parseInt(obj.optString("cat_id"));
ihr.bind(catIdTable, catId);
values2.put("catId", catId);
int paramtitle = ihr.getColumnIndex("title");
String paramTitle = obj.optString("param_title");
ihr.bind(paramtitle, paramTitle);
values2.put("title", paramTitle);
String cardstats = "SELECT cardId , statKeyId FROM cardstats WHERE cardId="+objectId+" AND statKeyId="+catId;
Cursor cardStats = userDbHelper.executeSQLQuery(cardstats);
if(cardStats.getCount()==0){
//userDbHelper.executeQuery("cardstats", values2);
ihr.execute();
} else {
for(cardStats.moveToFirst(); cardStats.moveToNext(); cardStats.isAfterLast()){
//int card = Integer.parseInt(cardStats.getString(cardStats.getColumnIndex("cardId")));
int statId = Integer.parseInt(cardStats.getString(cardStats.getColumnIndex("statKeyId")));
if(paramId != statId){
ihr.execute();
//userDbHelper.executeQuery("cardstats", values2);
} else {
userDbHelper.updateSQL("cardstats", values2, "cardId=?", new String[]{Integer.toString(objectId)});
}
}
}
cardStats.close();
//userDbHelper.executeQuery("cardstats", values2);
}
}// end if
String sql = "SELECT objectId FROM cards WHERE objectId = " + objectId;
Cursor cursor = userDbHelper.executeSQLQuery(sql);
if (cursor.getCount() == 0) {
ih.execute();
//userDbHelper.executeQuery("cards", values);
} else {
for (cursor.move(0); cursor.moveToNext(); cursor.isAfterLast()) {
int objectID = Integer.parseInt(cursor.getString(cursor.getColumnIndex("objectId")));
Log.d("","objectId : objectID - "+objectId+" "+objectID );
if (objectId != objectID) {
ih.execute();
//userDbHelper.executeQuery("cards", values);
} else if(objectId == objectID){
userDbHelper.updateSQL("cards", valuess, "objectId=?", new String[] {Integer.toString(objectId)});
}
}
}
cursor.close();
} catch (Exception e) {
e.printStackTrace();
Log.d("Error", ": " + e);
}
db.close();
return true;
}
*Edit: *
And here is how I save the binary data (images) which I get from internet :
public static void saveToExternalStorage(String servername, int userId, String filename, byte[] buffer){
try {
File myDir=new File("/sdcard/.Stampii/Users/"+servername+"/"+userId+"/Storage");
myDir.mkdirs();
File file = new File(myDir, filename);
FileOutputStream fos = new FileOutputStream(file);
fos.write(buffer);
fos.flush();
fos.close();
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
So any kind of suggestions/advices are welcomed which will help me to improve this piece of code and make it run faster.
Thanks in advance!
Even if you have a lot of HTTP traffic (which you appear to have) you can still optimize your use of the database.
This naïve example that does 10000 inserts will show you the scale of improvement we're talking about here:
public class BombasticActivity extends Activity {
DBHelper mHelper;
SQLiteDatabase mDb;
InsertHelper mInsertHelper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mHelper = new DBHelper(this);
mDb = mHelper.getWritableDatabase();
mInsertHelper = new InsertHelper(mDb, "table1");
}
#Override
protected void onStart() {
super.onStart();
AsyncTask.SERIAL_EXECUTOR.execute(new MeasureTime(new Insert(10000, mInsertHelper)));
AsyncTask.SERIAL_EXECUTOR.execute(new MeasureTime(new DoInTransaction(mDb, new Insert(10000, mInsertHelper))));
}
#Override
protected void onDestroy() {
super.onDestroy();
mInsertHelper.close();
mDb.close();
mHelper.close();
}
static class MeasureTime implements Runnable {
final Runnable mAction;
MeasureTime(Runnable action) {
mAction = action;
}
public void run() {
final String name = mAction.getClass().getSimpleName();
System.out.println("Starting action (" + name + ")");
long t0 = System.currentTimeMillis();
try {
mAction.run();
} finally {
t0 = System.currentTimeMillis() - t0;
System.out.println("Time to complete action (" + name + "): " + t0 + "ms");
}
}
}
static class DoInTransaction implements Runnable {
final Runnable mAction;
final SQLiteDatabase mDb;
DoInTransaction(SQLiteDatabase db, Runnable action) {
mAction = action;
mDb = db;
}
public void run() {
mDb.beginTransaction();
try {
mAction.run();
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
}
}
static class Insert implements Runnable {
final int mNumberOfInserts;
final InsertHelper mInsertHelper;
Insert(int numberOfInserts, InsertHelper insertHelper) {
mNumberOfInserts = numberOfInserts;
mInsertHelper = insertHelper;
}
public void run() {
Random rnd = new Random(0xDEADBEEF);
ContentValues values = new ContentValues();
for (int i = 0; i < mNumberOfInserts; i++) {
values.put("text1", String.valueOf(rnd.nextDouble()));
values.put("text2", String.valueOf(rnd.nextFloat()));
values.put("text3", String.valueOf(rnd.nextLong()));
values.put("int1", rnd.nextInt());
mInsertHelper.insert(values);
if (i % 200 == 0) {
System.out.println("Done " + i + " inserts");
}
}
}
}
}
class DBHelper extends SQLiteOpenHelper {
DBHelper(Context context) {
super(context.getApplicationContext(), "bombastic", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE table1 (_id INTEGER PRIMARY KEY AUTOINCREMENT, text1 TEXT, text2 TEXT, text3 TEXT, int1 INTEGER)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
On an ICS device (you can run it on Gingerbread if you start a thread or threadpool instead of abusing AsyncTask.SERIAL_EXECUTOR) the non-transaction version takes almost 4 minutes to complete (229484ms) while the version running in the transaction only takes about 3 seconds (2975ms).
So put it shortly, do a lot of updates - do it in a transaction.
To optimize your HTTP you should ensure that you are keeping the HTTP connection alive (keep-alive) and downloading larger chunks. Much larger than the ones you are doing now - if possible switch to a JSON parser that supports reading from a stream instead of loading the entire thing into a String before parsing it.
There are two time consuming activity involved in your case.
a. Downloading data in packets (assuming it to be HTTP). For a single packet it should take you about 1-3 sec depending on the network latency.
For 200 = 2X100 = 200 seconds ~ 3 mins
You can save lots of seconds, if you download entire data in say not more than 3-5 round-trip calls.
b. Database insert
You need to do file operation specifically write file operation which takes time. Honestly you cannot much optimization here
Check my other answer here
Sorry if I repeat my question but I have still had no clues of what to do and how to deal with the question.
My app is a dictionary. I assume that users will need to add words that they want to memorise to a Favourite list. Thus, I created a Favorite button that works on two phases:
short-click to save the currently-view word into the Favourite list;
and long-click to view the Favourite list so that users can click on any words to look them up again.
I go for using a SQlite database to store the favourite words but I wonder how I can do this task. Specifically, my questions are:
Should I use the current dictionary SQLite database or create a new SQLite database to favorite words?
In each case, what codes do I have to write to cope with the mentioned task?
Could anyone there kindly help?
Here is the dictionary code:
package mydict.app;
import java.util.ArrayList;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.util.Log;
public class DictionaryEngine {
static final private String SQL_TAG = "[MyAppName - DictionaryEngine]";
private SQLiteDatabase mDB = null;
private String mDBName;
private String mDBPath;
//private String mDBExtension;
public ArrayList<String> lstCurrentWord = null;
public ArrayList<String> lstCurrentContent = null;
//public ArrayAdapter<String> adapter = null;
public DictionaryEngine()
{
lstCurrentContent = new ArrayList<String>();
lstCurrentWord = new ArrayList<String>();
}
public DictionaryEngine(String basePath, String dbName, String dbExtension)
{
//mDBExtension = getResources().getString(R.string.dbExtension);
//mDBExtension = dbExtension;
lstCurrentContent = new ArrayList<String>();
lstCurrentWord = new ArrayList<String>();
this.setDatabaseFile(basePath, dbName, dbExtension);
}
public boolean setDatabaseFile(String basePath, String dbName, String dbExtension)
{
if (mDB != null)
{
if (mDB.isOpen() == true) // Database is already opened
{
if (basePath.equals(mDBPath) && dbName.equals(mDBName)) // the opened database has the same name and path -> do nothing
{
Log.i(SQL_TAG, "Database is already opened!");
return true;
}
else
{
mDB.close();
}
}
}
String fullDbPath="";
try
{
fullDbPath = basePath + dbName + "/" + dbName + dbExtension;
mDB = SQLiteDatabase.openDatabase(fullDbPath, null, SQLiteDatabase.OPEN_READWRITE|SQLiteDatabase.NO_LOCALIZED_COLLATORS);
}
catch (SQLiteException ex)
{
ex.printStackTrace();
Log.i(SQL_TAG, "There is no valid dictionary database " + dbName +" at path " + basePath);
return false;
}
if (mDB == null)
{
return false;
}
this.mDBName = dbName;
this.mDBPath = basePath;
Log.i(SQL_TAG,"Database " + dbName + " is opened!");
return true;
}
public void getWordList(String word)
{
String query;
// encode input
String wordEncode = Utility.encodeContent(word);
if (word.equals("") || word == null)
{
query = "SELECT id,word FROM " + mDBName + " LIMIT 0,15" ;
}
else
{
query = "SELECT id,word FROM " + mDBName + " WHERE word >= '"+wordEncode+"' LIMIT 0,15";
}
//Log.i(SQL_TAG, "query = " + query);
Cursor result = mDB.rawQuery(query,null);
int indexWordColumn = result.getColumnIndex("Word");
int indexContentColumn = result.getColumnIndex("Content");
if (result != null)
{
int countRow=result.getCount();
Log.i(SQL_TAG, "countRow = " + countRow);
lstCurrentWord.clear();
lstCurrentContent.clear();
if (countRow >= 1)
{
result.moveToFirst();
String strWord = Utility.decodeContent(result.getString(indexWordColumn));
String strContent = Utility.decodeContent(result.getString(indexContentColumn));
lstCurrentWord.add(0,strWord);
lstCurrentContent.add(0,strContent);
int i = 0;
while (result.moveToNext())
{
strWord = Utility.decodeContent(result.getString(indexWordColumn));
strContent = Utility.decodeContent(result.getString(indexContentColumn));
lstCurrentWord.add(i,strWord);
lstCurrentContent.add(i,strContent);
i++;
}
}
result.close();
}
}
public Cursor getCursorWordList(String word)
{
String query;
// encode input
String wordEncode = Utility.encodeContent(word);
if (word.equals("") || word == null)
{
query = "SELECT id,word FROM " + mDBName + " LIMIT 0,15" ;
}
else
{
query = "SELECT id,content,word FROM " + mDBName + " WHERE word >= '"+wordEncode+"' LIMIT 0,15";
}
//Log.i(SQL_TAG, "query = " + query);
Cursor result = mDB.rawQuery(query,null);
return result;
}
public Cursor getCursorContentFromId(int wordId)
{
String query;
// encode input
if (wordId <= 0)
{
return null;
}
else
{
query = "SELECT id,content,word FROM " + mDBName + " WHERE Id = " + wordId ;
}
//Log.i(SQL_TAG, "query = " + query);
Cursor result = mDB.rawQuery(query,null);
return result;
}
public Cursor getCursorContentFromWord(String word)
{
String query;
// encode input
if (word == null || word.equals(""))
{
return null;
}
else
{
query = "SELECT id,content,word FROM " + mDBName + " WHERE word = '" + word + "' LIMIT 0,1";
}
//Log.i(SQL_TAG, "query = " + query);
Cursor result = mDB.rawQuery(query,null);
return result;
}
public void closeDatabase()
{
mDB.close();
}
public boolean isOpen()
{
return mDB.isOpen();
}
public boolean isReadOnly()
{
return mDB.isReadOnly();
}
}
And here is the code below the Favourite button to save to and load the Favourite list:
btnAddFavourite = (ImageButton) findViewById(R.id.btnAddFavourite);
btnAddFavourite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Add code here to save the favourite, e.g. in the db.
Toast toast = Toast.makeText(ContentView.this, R.string.messageWordAddedToFarvourite, Toast.LENGTH_SHORT);
toast.show();
}
});
btnAddFavourite.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
// Open the favourite Activity, which in turn will fetch the saved favourites, to show them.
Intent intent = new Intent(getApplicationContext(), FavViewFavourite.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
return false;
}
});
}
You need to have two tables
words
favorites
Words(id, word, meaning,...)
Favorites(id, word_id)
In the Favorites table have a foreign key that points the word from the Words Table.
I have only addressed the way you need to structure the table.
*EDITED*
words(id, name, meaning, timestamp)
favortie(id, word_id)