Android cursorwindow memory error in a specific fragment - android

I have an android app that uses a service to collect sensor data every 5ms and inserts it into a sqlite table. In a typical session there will be about 40mins of recordings. All of that code seems to be working fine.
I have a strange problem where if the user navigates to a particular fragment I get a CursorWindow: Window is full: requested allocation XXX error. I'm not sure what is special about this specific fragment that is causing that error, and only happens with this one fragment
The fragment in question contains a button, which when clicked will do a number of things:
Creates some directories on external storage
Copies all of the sensor data from the temporary table and inserts it into a more permanent table
Creates a copy of the entire .db file to external storage
Takes the contents of a table and writes it to a CSV file
Queries another table for sensor data, and writes all of that sensor data to another CSV file
Uses media scanner to scan all of the files in the export directory so they can be accessed via MTP
The fragment code looks like this (a lot of the catch blocks have been left out for brevity - they mostly just log information):
public class SaveFragment extends Fragment implements View.OnClickListener {
Button saveButton;
MainActivity mainActivity;
DBHelper dbHelper;
Boolean subjectDataExists;
MediaScanner mediaScanner;
static ProgressDialog dialog;
public SaveFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_save, container, false);
//Get save button view
saveButton = (Button) view.findViewById(R.id.saveButton);
saveButton.setOnClickListener(this);
//Get DBHelper
dbHelper = DBHelper.getInstance(getActivity(), new DatabaseHandler());
//Check if sensor data has been recorded
subjectDataExists = dbHelper.checkSubjectDataExists(Short.parseShort(dbHelper.getTempSubInfo("subNum")));
// Inflate the layout for this fragment
return view;
}
#Override
public void onClick(View v) {
//Alert dialog for saving/quitting
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mainActivity);
if (subjectDataExists) {
alertDialogBuilder.setTitle("Save and quit?");
alertDialogBuilder.setMessage("Are you sure you want to save the data and quit the current session?");
} else {
alertDialogBuilder.setTitle("Quit?");
alertDialogBuilder.setMessage("Are you sure you want to quit the current session? \n\n No data will be saved.");
}
alertDialogBuilder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
//Save if sensor data exists, otherwise quit
if (subjectDataExists) {
new ExportDatabaseCSVTask().execute();
} else {
quitSession();
}
}
});
alertDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog quitAlertDialog = alertDialogBuilder.create();
quitAlertDialog.show();
}
//Quit the current session and go back to login screen
private void quitSession(){
Intent intent = new Intent(getActivity(), LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
getActivity().finishAffinity();
}
//Message handler class for database progress updates
private static class DatabaseHandler extends Handler {
#Override
public void handleMessage (Message msg){
Double progressPercent = (Double) msg.obj;
Integer progressValue = 40 + (int) Math.ceil(progressPercent/2);
dialog.setProgress(progressValue);
}
}
//Async class for CSV export task
public class ExportDatabaseCSVTask extends AsyncTask<String, Integer, Boolean> {
#Override
protected void onPreExecute() {
//show a progress dialog
}
protected Boolean doInBackground(final String... args) {
//Create directories for the output csv files
String pathToExternalStorage = Environment.getExternalStorageDirectory().toString();
File exportDir = new File(pathToExternalStorage, "/Data");
File subjectDataDir = new File(exportDir, "/subjects");
publishProgress(5);
//The sleep is here just so the progress updates in the dialog are visually slower
SystemClock.sleep(100);
if (!exportDir.exists()) {
Boolean created = exportDir.mkdirs();
}
publishProgress(10);
SystemClock.sleep(100);
if (!subjectDataDir.exists()) {
Boolean created = subjectDataDir.mkdirs();
}
publishProgress(15);
SystemClock.sleep(100);
//If all directories have been created successfully
if (exportDir.exists() && subjectDataDir.exists()) {
try {
//Copy temp subject and sensor data to persistent db tables
dbHelper.copyTempData();
publishProgress(20);
SystemClock.sleep(200);
//Backup the SQL DB file
File data = Environment.getDataDirectory();
String currentDBPath = "//data//com.example.app//databases//" + DBHelper.DATABASE_NAME;
File currentDB = new File(data, currentDBPath);
File destDB = new File(exportDir, DBHelper.DATABASE_NAME);
publishProgress(25);
SystemClock.sleep(100);
if (exportDir.canWrite()) {
if (currentDB.exists()) {
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(destDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
}
}
publishProgress(35);
SystemClock.sleep(300);
//Export subjects table/tracking sheet
File trackingSheet = new File(exportDir, "trackingSheet.csv");
try{
dbHelper.exportTrackingSheet(trackingSheet);
} catch (SQLException | IOException e){
}
publishProgress(40);
SystemClock.sleep(300);
//Export individual subject data
String subNum = dbHelper.getTempSubInfo("subNum");
File subjectFile = new File(subjectDataDir, subNum + ".csv");
try{
dbHelper.exportSubjectData(subjectFile, subNum);
} catch (SQLException | IOException e){
}
publishProgress(90);
SystemClock.sleep(300);
//Scan all files for MTP
List<String> fileList = getListFiles(exportDir);
String[] allFiles = new String[fileList.size()];
allFiles = fileList.toArray(allFiles);
mediaScanner = new MediaScanner();
try{
mediaScanner.scanFile(getContext(), allFiles, null, mainActivity.logger);
} catch (Exception e) {
}
publishProgress(100);
SystemClock.sleep(400);
return true;
} catch (SQLException | IOException e) {
} else {
//Directories don't exist
if (!exportDir.exists()) {
} else if (!subjectDataDir.exists()) {
return false;
}
}
public void onProgressUpdate(Integer ... progress){
dialog.setProgress(progress[0]);
if (progress[0] == 100){
dialog.setMessage("Quitting...");
}
}
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
if (success) {
//Restart app and go back to login screen
quitSession();
}
}
//Recursive file lister for MTP
private List<String> getListFiles(File parentDir) {
ArrayList<String> inFiles = new ArrayList<>();
File[] files = parentDir.listFiles();
//Loop through everything in base directory, including folders
for (File file : files) {
if (file.isDirectory()) {
//Recursively add files from subdirectories
inFiles.addAll(getListFiles(file));
} else {
inFiles.add(file.getAbsolutePath());
}
}
return inFiles;
}
}
}
After a lot of sensor data has been recorded, I get the error every time the user navigates to the fragment. But when the button is clicked, I get the error continuously every 2 seconds.
The sensor recording service code can be found in my other question: Android sending messages between fragment and service
This fragment calls a number of methods from my DBHelper class (which is set up as a singleton):
public class DBHelper extends SQLiteOpenHelper {
SQLiteDatabase db;
CSVWriter csvWrite;
Cursor curCSV;
static Handler messageHandler;
private static DBHelper sInstance;
public static synchronized DBHelper getInstance(Context context) {
if (sInstance == null) {
sInstance = new DBHelper(context.getApplicationContext());
Log.d(TAG, "New DBHelper created");
}
return sInstance;
}
public static synchronized DBHelper getInstance(Context context, Handler handler) {
if (sInstance == null) {
sInstance = new DBHelper(context.getApplicationContext());
Log.d(TAG, "New DBHelper created");
}
messageHandler = handler;
return sInstance;
}
private DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
db = this.getWritableDatabase();
}
public boolean checkSubjectDataExists(Short subNum) throws SQLException {
//Check if sensor data, for this subject, exists in the temp data table
String query = "SELECT * FROM " + DATA_TABLE_NAME_TEMP + " WHERE " + DATA_SUBJECT + "=" + subNum;
Cursor c = db.rawQuery(query, null);
boolean exists = (c.getCount() > 0);
c.close();
return exists;
}
public void copyTempData() throws SQLException{
String copySubjectSQL = "INSERT INTO " + SUBJECTS_TABLE_NAME + " SELECT * FROM " + SUBJECTS_TABLE_NAME_TEMP;
db.execSQL(copySubjectSQL);
String copyDataSQL = "INSERT INTO " + DATA_TABLE_NAME + " SELECT * FROM " + DATA_TABLE_NAME_TEMP;
db.execSQL(copyDataSQL);
}
public void exportTrackingSheet(File outputFile) throws SQLException, IOException {
csvWrite = new CSVWriter(new FileWriter(outputFile));
curCSV = db.rawQuery("SELECT * FROM " + SUBJECTS_TABLE_NAME, null);
csvWrite.writeNext(curCSV.getColumnNames());
while (curCSV.moveToNext()) {
String arrStr[] = {curCSV.getString(0), curCSV.getString(1), curCSV.getString(2),
curCSV.getString(3), curCSV.getString(4), curCSV.getString(5), curCSV.getString(6)};
csvWrite.writeNext(arrStr);
}
csvWrite.close();
curCSV.close();
}
public void exportSubjectData(File outputFile, String subNum) throws IOException, SQLException {
csvWrite = new CSVWriter(new FileWriter(outputFile));
curCSV = db.rawQuery("SELECT * FROM " + DATA_TABLE_NAME + " WHERE id = " + subNum, null);
csvWrite.writeNext(curCSV.getColumnNames());
Integer writeCounter = 0;
Integer numRows = curCSV.getCount();
while (curCSV.moveToNext()) {
writeCounter++;
String arrStr[] = {curCSV.getString(0), curCSV.getString(1), curCSV.getString(2),
curCSV.getString(3), curCSV.getString(4), curCSV.getString(5),
curCSV.getString(6), curCSV.getString(7), curCSV.getString(8),
curCSV.getString(9), curCSV.getString(10), curCSV.getString(11),
curCSV.getString(12), curCSV.getString(13), curCSV.getString(14),
curCSV.getString(15), curCSV.getString(16), curCSV.getString(17),
curCSV.getString(18), curCSV.getString(19), curCSV.getString(20),
curCSV.getString(21), curCSV.getString(22), curCSV.getString(23),
curCSV.getString(24), curCSV.getString(25)};
csvWrite.writeNext(arrStr);
if ((writeCounter % 1000) == 0){
csvWrite.flush();
}
Double progressPercent = Math.ceil(((float) writeCounter / (float) numRows)*100);
Message msg = Message.obtain();
msg.obj = progressPercent;
msg.setTarget(messageHandler);
msg.sendToTarget();
}
csvWrite.close();
curCSV.close();
}
}
The DBHelper and any SQL connections are closed in onDestroy of my main activity
My media scanner class is also pretty straightforward:
public class MediaScanner {
protected void scanFile(final Context context, String[] files, String[] mimeTypes, final Logger logger) {
MediaScannerConnection.scanFile(context, files, mimeTypes,
new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
//Log some info
}
}
);
}
}
Can anyone see anything special about my fragment code that is causing this cursor window error?

Related

Listview gets popuplated from the database everytime I start the activity

I am fetching some json data into an EventApp and I am trying to store in SQLite database some of the events. I am showing the events in another activity, not the main one and whenever I go back from that activity to the main one and the I go back to the activity with the listview, the data gets duplicated every time. SO if I click to go to that activity 10 time, my data gets 10 times in the listview and in the database as well. How can I fix this?
SQLiteDatabase db = getWritableDatabase();
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
//Add new row to the database
public void addEvent(Event ev){
ContentValues contentValues = new ContentValues();
contentValues.put(DatabaseHelper.TITLE, ev.getTitle());
contentValues.put(DatabaseHelper.START_DATE, ev.getStartTime());
contentValues.put(DatabaseHelper.END_DATE, ev.getEndTime());
contentValues.put(DatabaseHelper.IMAGE_URL, ev.getImageURL());
contentValues.put(DatabaseHelper.URL, ev.getUrl());
contentValues.put(DatabaseHelper.SUBTITLE, ev.getSubtitle());
contentValues.put(DatabaseHelper.DESCRIPTION, ev.getDescription());
db.insert(TABLE_NAME, null, contentValues);
//db.close();
}
//Delete event from database
public void deleteEvent(String eventTitle){
db.execSQL("DELETE FROM " + TABLE_NAME + "WHERE " + TITLE + "=\"" + eventTitle + "\";" );
}
public int deleteEvents() {
return db.delete(DatabaseHelper.TABLE_NAME, null, null);
}
//Print the database as string
public String databaseToString(){
String dbString="";
//points to a location in results
Cursor c = getEvents();
while (c.moveToNext()){
if(c.getString(c.getColumnIndex("Title")) != null){
dbString += c.getString(c.getColumnIndex("Title"));
dbString += "\n";
}
}
//db.close();
return dbString;
}
public Cursor getEvents(){
return db.query(TABLE_NAME, ALL_COLUMNS, null, null, null, null, null, null);
}
}
This is the activity where I show the data from the database
public class StoredEventsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stored_events);
ListView listView = (ListView) findViewById(R.id.lv_stored_events);
Intent intent = getIntent();
ArrayList<Event> events = new ArrayList<Event>();
events = (ArrayList<Event>) intent.getSerializableExtra("storedEvents");
EventAdapter adapter = new EventAdapter(this, R.layout.list_view_row, R.id.stored, events );
listView.setAdapter(adapter);
}
}
Here is the method that returns the stored events
public static ArrayList<Event> returnStoredEvents(){
long id = -1;
//getStoredEvents();
Cursor c = eventsDB.getEvents();
while (c.moveToNext()){
id = c.getInt(c.getColumnIndex(eventsDB.ID));
String title = c.getString(c.getColumnIndex(eventsDB.TITLE));
String start = c.getString(c.getColumnIndex(eventsDB.START_DATE));
String end = c.getString(c.getColumnIndex(eventsDB.END_DATE));
organizeEvents.add(new Event(title, start, end, true));
}
c.close();
Log.d("DATABASE", organizeEvents.toString());
return organizeEvents;
}
Here is where I actually add some of the events:
private void readEvents(String str){
Event ev = null;
try {
JSONObject geoJSON = new JSONObject(str);
JSONArray jsonEvents = geoJSON.getJSONArray("events");
for (int i = 0; i < jsonEvents.length(); i++) {
JSONObject event = jsonEvents.getJSONObject(i);
JSONArray timeJsonEvent = event.getJSONArray("datelist");
JSONObject time = timeJsonEvent.getJSONObject(0);
title = event.getString("title_english");
Date date = new Date(time.getLong("start"));
startDate = dateFormat.format(date);
date = new Date(time.getLong("end"));
endDate = dateFormat.format(date);
imageURL = event.getString("picture_name");
url = event.getString("url");
subtitle = event.getString("subtitle_english");
description = event.getString("description_english");
if (title.charAt(0) == 'T') {
ev = new Event(title, startDate, endDate, true);
eventsDB.addEvent(ev);
}else {
ev = new Event(title, startDate, endDate, false);
}
// Process a newly found event
final Event finalEv = ev;
handler.post(new Runnable() {
public void run() {
addNewEvent(finalEv);
}
});
}
}catch (Exception e) {
Log.d(null, e.getMessage());
}
}
And here is my main:
public class MainActivity extends AppCompatActivity{
DatabaseHelper eventsDB;
ListFragment listFragment;
SimpleCursorAdapter adapter;
Intent intent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
eventsDB = new DatabaseHelper(this);
//storedEvents.addAll(EventsListFragment.returnStoredEvents());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getTitle().equals("Sort by name")){
Toast.makeText(this, "ITEM 2 CLICKED", Toast.LENGTH_LONG).show();
EventsListFragment.sort(-1);
}else if (item.getTitle().equals("Sort by date")) {
EventsListFragment.sort(1);
}else if (item.getTitle().equals("Stored events")){
showSavedEvents();
Toast.makeText(this, "ITEM 3 CLICKED", Toast.LENGTH_LONG).show();
}
return true;
}
public void showSavedEvents(){
intent = new Intent(this, StoredEventsActivity.class);
intent.putExtra("storedEvents", EventsListFragment.returnStoredEvents());
startActivity(intent);
}
}

Android convert sqlite single record to csv

I want to convert a single row to a .csv file. How am I going to do that? All I've seen in the Internet are most of them the whole sqlite db is being converted/exported to a .csv file. But my requirement is only a single record? Do you have ideas as to how am I gonna achieve this? Help is much appreciated. Thanks!
Update:
public class CSVCreationActivity extends Activity {
TextView empidtxt,empnametxt,empsaltxt;
EditText empidet,empnameet,empsalet;
Button insetbt,viewbt;
SQLiteDatabase myDatabase=null;
String DataBase_Name="employeedata";
String Table_Name="employeedetails";
Cursor c1,c2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
empidtxt=(TextView)findViewById(R.id.tv1);
empnametxt=(TextView)findViewById(R.id.tv2);
empsaltxt=(TextView)findViewById(R.id.tv3);
empidet=(EditText)findViewById(R.id.et1);
empnameet=(EditText)findViewById(R.id.et2);
empsalet=(EditText)findViewById(R.id.et3);
insetbt=(Button)findViewById(R.id.bt1);
viewbt=(Button)findViewById(R.id.bt2);
try {
myDatabase=this.openOrCreateDatabase(DataBase_Name, MODE_PRIVATE, null);
System.out.println("databse has been created.....");
myDatabase.execSQL("create table if not exists " + Table_Name + "(empid integer(10),empname varchar(50),empsal integer(10))");
System.out.println("table has been created.....");
c1 = myDatabase.rawQuery("select * from " + Table_Name, null);
c1.moveToFirst();
int count1 = c1.getCount();
System.out.println("columns --->" + count1);
if (count1 == 0) {
myDatabase.execSQL("insert into "+Table_Name+ "(empid,empname,empsal)" +"values(101,'asha',20000)");
System.out.println("data base has been inserted.....");
}
c2 = myDatabase.rawQuery("select * from " + Table_Name, null);
c2.moveToFirst();
int count2 = c2.getCount();
System.out.println("columns --->" + count2);
final int column1 = c2.getColumnIndex("empid");
final int column2 = c2.getColumnIndex("empname");
final int column3 = c2.getColumnIndex("empsal");
insetbt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (c2 != null) {
do {
int id = c2.getInt(column1);
String name = c2.getString(column2);
int salary = c2.getInt(column3);
System.out.println("empID --> "+id);
System.out.println("empNAME --> "+name);
System.out.println("empsalalry --> "+salary);
} while(c2.moveToNext());
}
}
});
viewbt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
new ExportDatabaseCSVTask().execute("");
} catch(Exception ex) {
Log.e("Error in MainActivity",ex.toString());
}
}
});
}
catch(SQLException ex) { ex.printStackTrace(); }
/*finally {
if (myDB != null) { myDB.close(); }
}*/
}
public class ExportDatabaseCSVTask extends AsyncTask<String, Void, Boolean> {
private final ProgressDialog dialog = new ProgressDialog(CSVCreationActivity.this);
#Override
protected void onPreExecute() {
this.dialog.setMessage("Exporting database...");
this.dialog.show();
}
protected Boolean doInBackground(final String... args) {
File dbFile = getDatabasePath("myDatabase.db");
System.out.println(dbFile); // displays the data base path in your logcat
File exportDir = new File(Environment.getExternalStorageDirectory(), "");
if (!exportDir.exists()) { exportDir.mkdirs(); }
File file = new File(exportDir, "myfile.csv");
try {
file.createNewFile();
CSVWriter csvWrite = new CSVWriter(new FileWriter(file));
Cursor curCSV = myDatabase.rawQuery("select * from " + Table_Name,null);
csvWrite.writeNext(curCSV.getColumnNames());
while(curCSV.moveToNext()) {
String arrStr[] ={curCSV.getString(0),curCSV.getString(1),curCSV.getString(2)};
// curCSV.getString(3),curCSV.getString(4)};
csvWrite.writeNext(arrStr);
}
csvWrite.close();
curCSV.close();
return true;
} catch(SQLException sqlEx) {
Log.e("MainActivity", sqlEx.getMessage(), sqlEx);
return false;
} catch (IOException e) {
Log.e("MainActivity", e.getMessage(), e);
return false;
}
}
protected void onPostExecute(final Boolean success) {
if (this.dialog.isShowing()) { this.dialog.dismiss(); }
if (success) {
Toast.makeText(CSVCreationActivity.this, "Export successful!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(CSVCreationActivity.this, "Export failed", Toast.LENGTH_SHORT).show();
}
}
}
CSVWriter and CSVReader can be downloaded here
Better way to get specific record from database and then convert it to csv file ...
you just need to modify your query to achieve this
Replace this line
Cursor curCSV = myDatabase.rawQuery("select * from " + Table_Name,null);
with ur conditional query means using where operator or anything else...

Using listviews with a database

and good day. My project is having 2 activities, first one to insert data into the database which works well, but then I want to show a list view of the data within the database in another activity.
I've tried local data eg fred, george in an array and the list view works great however, when I try to use the database. The activity crashes. It seems that I am unable to use "database.open"
public class MyListActivity extends Activity{
DatabaseAdapter database;
//Creates item_details based on the ListItemDetails class
ListItemDetails item_details;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
//Uses the arraylist and set the result
ArrayList<ListItemDetails> result = GetSearchResults();
ListView lv = (ListView)findViewById(R.id.listView1);
lv.setAdapter(new CustomListAdapter(getApplicationContext(),result));
}
private ArrayList<ListItemDetails> GetSearchResults() {
ArrayList<ListItemDetails> results = new ArrayList<ListItemDetails>();
item_details = new ListItemDetails();
/*
database.open();
Cursor c = database.getAllContacts();
if (c.moveToFirst())
{
do {
item_details.setFirstName(c.getString(1));
results.add(item_details);
} while (c.moveToNext());
}
*/
return results;
}
}
Here is the main activity. The database opens fine when I use the buttonShow, so I tried buttonTest and storing them into the list but it got a bit confusing for me.
public class FamousPersonActivity extends Activity {
EditText editFirstName, editLastName;
Button buttonAdd, buttonShow, buttonTest;
ListView lv;
ListItemDetails item_details;
DatabaseAdapter database;
int request_Code = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_famous_person);
database = new DatabaseAdapter(this);
lv = (ListView)findViewById(R.id.listView1);
//ArrayList<ListItemDetails> result = GetSearchResults();
//lv.setAdapter(new CustomListAdapter(getApplicationContext(),result));
editFirstName = (EditText)findViewById(R.id.editFirstName);
editLastName = (EditText)findViewById(R.id.editLastName);
buttonAdd = (Button)findViewById(R.id.buttonAdd);
buttonShow = (Button)findViewById(R.id.buttonShow);
buttonTest = (Button)findViewById(R.id.buttonTest);
buttonAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Toast.makeText(getApplicationContext(), "added to database", Toast.LENGTH_SHORT).show();
database.open();
long id = database.insertContact("Test Contact", "Test Email") ;
database.close();
}
});
buttonTest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent("com.id11020260.exercise6part2.MyListActivity");
startActivityForResult(i, request_Code);
}
});
buttonShow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
try {
String destPath = "/data/data/" + getPackageName() +
"/databases";
File f = new File(destPath);
if (!f.exists()) {
f.mkdirs();
f.createNewFile();
//---copy the db from the assets folder into
// the databases folder---
CopyDB(getBaseContext().getAssets().open("mydb"),
new FileOutputStream(destPath + "/MyDB"));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//---get all contacts---
database.open();
Cursor c = database.getAllContacts();
if (c.moveToFirst())
{
do {
DisplayContact(c);
} while (c.moveToNext());
}
database.close();
}
});
}
private ArrayList<ListItemDetails> GetSearchResults() {
ArrayList<ListItemDetails> results = new ArrayList<ListItemDetails>();
item_details = new ListItemDetails();
database.open();
Cursor c = database.getAllContacts();
if (c.moveToFirst())
{
do {
item_details.setFirstName(c.getString(1));
results.add(item_details);
} while (c.moveToNext());
database.close();
}
return results;
}
public void CopyDB(InputStream inputStream,
OutputStream outputStream) throws IOException {
//---copy 1K bytes at a time---
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.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.famous_person, menu);
return true;
}
public void DisplayContact(Cursor c)
{
Toast.makeText(this,
"id: " + c.getString(0) + "\n" +
"Name: " + c.getString(1) + "\n" +
"Email: " + c.getString(2),
Toast.LENGTH_LONG).show();
}
}
This is the stack trace, I'm not sure if this is entirely correct
Try this:-
lv.setListAdapter(new ArrayAdapter(MyListActivity.this,
android.R.layout.simple_list_item_1,result));

How to pass data from sqlite listview to new intent?

(this is my lunch.class which populate the listview from database.tell me if there is any mistakes.im still new to this.)
public class Lunch extends Activity implements OnItemClickListener {
DBOpener dbopener;
#Override
protected void onCreate(Bundle savedInstanceState) {
//for fullscreen view
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.dinner);
dbopener = new DBOpener(this);
}
// Open the DB, query all subject codes and refresh the listview
// when app resumes
#Override
protected void onResume() {
super.onResume();
// Configure the listview
ArrayList<String> mealNames = new ArrayList<String>();
ListView lstDine = (ListView)this.findViewById(R.id.dine);
lstDine.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, mealNames));
// Open/create the DB
try {
dbopener.createDatabase(); // Create DB if necessary
dbopener.openDatabase(); // Open the DB
Cursor dinners = dbopener.getLunchNames();
while (dinners.moveToNext()) {
mealNames.add(dinners.getString(0)); // Get the current subj
// code, add to list
}
dinners.close();
// Update the listview
ArrayAdapter<String> ad = (ArrayAdapter<String>)lstDine.getAdapter();
ad.notifyDataSetChanged();
lstDine.setOnItemClickListener(this);
} catch (Exception e) {
Toast.makeText(this, "Could not open DB",
Toast.LENGTH_LONG).show();
}
}
// Close the DB when app pauses
#Override
protected void onPause() {
super.onPause();
dbopener.close();
}
// When user clicks on an item
public void onItemClick(AdapterView<?> parent, View v, int pos, long id) {
// Use subject code from listview to retrieve other
// details with the dbopener
switch(pos)
{
case 0 :
Intent newActivity = new Intent("com.edu.tp.iit.mns.Display");
newActivity.putExtra("1", "2"); // this is where im unaware of the codes.how to pass the strings of value to the next page
startActivity(newActivity);
break;
}
switch(pos)
{
case 1 :
Intent newActivity = new Intent("com.edu.tp.iit.mns.Display");
startActivity(newActivity);
break;
}
switch(pos)
{
case 2 :
Intent newActivity = new Intent("com.edu.tp.iit.mns.Display");
startActivity(newActivity);
break;
}
switch(pos)
{
case 3 :
Intent newActivity = new Intent("com.edu.tp.iit.mns.Display");
startActivity(newActivity);
break;
}
switch(pos)
{
case 4 :
Intent newActivity = new Intent("com.edu.tp.iit.mns.Display");
startActivity(newActivity);
break;
}
switch(pos)
{
case 5 :
Intent newActivity = new Intent("com.edu.tp.iit.mns.Display");
startActivity(newActivity);
break;
}
switch(pos)
{
case 6 :
Intent newActivity = new Intent("com.edu.tp.iit.mns.Display");
startActivity(newActivity);
break;
}
switch(pos)
{
case 7 :
Intent newActivity = new Intent("com.edu.tp.iit.mns.Display");
startActivity(newActivity);
break;
}
}
(this is the display.class (image 2) works like a template to display dynamic info like image,food name, food description and its rating.
public class Display extends Activity {
DBOpener dbopener;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.display);
dbopener = new DBOpener(this);
}
#Override
protected void onResume() {
super.onResume();
// Configure the listview
// ArrayList<String> mealNames = new ArrayList<String>();
// ListView lstDine = (ListView)this.findViewById(R.id.dine);
// lstDine.setAdapter(new ArrayAdapter<String>(this,
// android.R.layout.simple_list_item_1, mealNames));
// Open/create the DB
try {
// dbopener.createDatabase(); // Create DB if necessary
dbopener.openDatabase(); // Open the DB
Toast.makeText(this, " open DB",
Toast.LENGTH_LONG).show();
Cursor dinners = dbopener.getLunchNames();
while (dinners.moveToNext()) {
// mealNames.add(dinners.getString(0)); // Get the current subj
// code, add to list
}
dinners.close();
// Update the listview
// ArrayAdapter<String> ad = (ArrayAdapter<String>)lstDine.getAdapter();
// ad.notifyDataSetChanged();
//
// lstDine.setOnItemClickListener(this);
} catch (Exception e) {
Toast.makeText(this, "Could not open DB",
Toast.LENGTH_LONG).show();
}
}
// Close the DB when app pauses
#Override
protected void onPause() {
super.onPause();
dbopener.close();
}
}
and lastly my dpopener file:
public class DBOpener extends SQLiteOpenHelper {
private static String DB_PATH =
"/data/data/com.edu.tp.iit.mns/databases/"; //path of our database
private static String DB_NAME ="finals"; // Database name
private final Context myContext;
private SQLiteDatabase db;
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
public DBOpener(Context context) {
super(context, DB_NAME, null, 1);
myContext = context;
}
public void createDatabase() throws IOException {
boolean dbExists = checkDatabase();
if (dbExists) {
// Do nothing, DB already exists
Log.d("DBOpener", "DB exists");
} else {
// By calling this method an empty database will be created
// in the default system path of your application, which we
// will overwrite with our own database.
Log.d("DBOpener", "DB does not exit - copying from assets");
this.getReadableDatabase();
copyDatabase();
}
}
private boolean checkDatabase() {
SQLiteDatabase checkDB = null;
try {
// Try opening the database
String path = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
// If it fails, DB does not exist
}
if (checkDB != null)
checkDB.close(); // Close the DB; we don’t need it now
return checkDB != null;
}
private void copyDatabase() throws IOException {
InputStream istream = myContext.getAssets().open(DB_NAME);
OutputStream ostream = new FileOutputStream(DB_PATH + DB_NAME);
// Transfer bytes from istream to ostream
byte[] buffer = new byte[1024];
int length;
while ((length = istream.read(buffer)) > 0) {
ostream.write(buffer, 0, length);
}
// Close streams
istream.close();
ostream.flush();
ostream.close();
}
public void openDatabase() throws SQLiteException {
db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null,
SQLiteDatabase.OPEN_READWRITE);
}
#Override
public synchronized void close() {
if (db != null)
db.close();
super.close();
}
// Retrieve all subject codes
public Cursor getDinnerNames() {
if (db == null)
return null;
return db.query("dinner", new String[] {"name"},
null, null, null, null, null);
}
// Get details of specific subject
public Cursor getDinnerDetails(String name) {
if (db == null)
return null;
return db.query("dinner", new String[] {"name", "nutrition", "rating"},
"name = ?", new String[] {name}, null, null, null);
}
// Retrieve all subject codes
public Cursor getLunchNames() {
if (db == null)
return null;
return db.query("lunch", new String[] {"name"},
null, null, null, null, null);
}
// Get details of specific subject
public Cursor getLunchDetails(String name) {
if (db == null)
return null;
return db.query("dinner", new String[] {"name", "nutrition", "rating"},
"name = ?", new String[] {name}, null, null, null);
}
// Retrieve all subject codes
public Cursor getBreakfastNames() {
if (db == null)
return null;
return db.query("breakfast", new String[] {"name"},
null, null, null, null, null);
}
// Get details of specific subject
public Cursor getBreakfastDetails(String name) {
if (db == null)
return null;
return db.query("breakfast", new String[] {"name", "nutrition", "rating"},
"name = ?", new String[] {name}, null, null, null);
}
}
can u help me kick start with the case 0 so that i can complete the code. example, user click BBQ chicken sandwich. it will navigate to display.class and retrieve the info from db and shows image rating and stuffs.
To pass arguments to the new activity via intent you use the putExtra(), like you put on your code:
newActivity.putExtra("1", "2");
The first parameter should be an String constant to identify your parameter, you will use this String to get the value later. The second parameter is the value, android has methods for all the primitives.
On the new activity, you use getExtra("1", "2"), where 1 is the constant you used earlier and 2 is the default value, in case it doesn't finds the value or the constant you used.

Android Java JSON parser/insert database optimization

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

Categories

Resources