I am sure there is an easy solution to this one but I figured I would check with all the folks here first.
I am working on a database creation and management application for android where the user creates and manages data along the line of what PHPMyAdmin does for regular computers.
I have the section where the user creates a database and can insert tables with the appropriate styled data into the system.
The next priority is selecting which DB to enter and modify its contents. Is there a way to display the available databases, along with its table contents, in the form of a list-view for the user to enter and edit the desired data??
I know that this is a rather dull question, but this is basically the last piece of the puzzle for me to fit into this app before it is operational in a raw format. If you need any further information, or any code to examine, I will be happy to provide.
Thanks again for everyone's assistance.
Here's a good tutorial on SQLite databases and displaying contents in a ListView:
http://www.vogella.com/articles/AndroidSQLite/article.html#databasetutorial
It doesn't go over editing that much, but it's easy to see where he puts the values into the database.
thenewboston on YouTube is a good resource for Android tutorials and he goes over SQLite databases:
http://www.youtube.com/watch?v=gEg9OdufXmM
It's pretty comprehensive and slow if you already kinda know what you're doing so here is where he goes over inserting data/editing the database if you just wanna jump to that:
http://www.youtube.com/watch?v=S3Z4e7KgNdU
I know this below can be optimized but for now just create such a method to do it automatically. The method...
Creates an empty database of a random name for a second,
Saves the new database's location - getDatabasePath,
Quikly deletes the empty database,
Removes filename form the saved path to get the directory path olny,
List all files in the database path excluding '-journal' files.
And it goes like this:
ArrayList<String> arr_list_of_db_files = getDBFILES();
pivate ArrayList<String> getDBFILES()
{
ArrayList<String> arr = new ArrayList<String>;
String db_path, rand_name, str_tmp;
//ad.1-2. random file name for db
rand_name = new Random().nextInt((4000000-2000+1)+2000).toString()+".db";
db_path = openOrCreateDatabase(rand_name, MODE_PRIVATE, null).getPath();
//ad.3.
deleteDatabase(rand_name);
//ad.4.
db_path = db_path.replace("/" + rand_name, "");
//ad.5.
File [] files = new File(db_path).listFiles();
if (files == null) { return null; }
//so now we get the filenames one by one
for (int i = 0; i < files.length; i++)
{
str_tmp = files[i].getName();
if (!str_tmp.endsWith("-journal"))
{ arr.add(str_tmp); }
}
return arr;
}
Btw, I cant test the code, but I hope it is fine and some of you find it useful.
Edited: I have optimized the above code.
Related
I'm making an Android application and want to create a "Favorites" list for some objects in the app. I wanna make the list accessible and editable in all my activities and I can't really figure out the best way to do this.
Shared preferences? Writing a small txt file to the device? What's the fastest way to do this?
Thanks in advance!
dependencies {
compile 'com.google.code.gson:gson:2.3.1'
}
Then when you want to save, convert your array into String:
ArrayList<Type> yourData = new ArrayList<Type>();
String dataStr = new Gson().toJson(yourData);
//put this dataStr in your shared preferences as String
To retrieve and convert back to an object is also simple:
String str = "";
//you need to retrieve this string from shared preferences.
Type type = new TypeToken<ArrayList<Type>>() { }.getType();
ArrayList<Type> restoreData = new Gson().fromJson(str, type);
If you want to create a Favorites list, use a SQLite Database.
There's really only four ways to store data.
Shared Preferences
Databases
Local files
Remote Server - Slowest since it depends on network connection, so let's skip this.
Between the remaining 3, SharedPreferences is a great option when used to store a single value. However, it's not a good option for storing a Favorites list, mainly because you can only store a single String.
You can still store it by combining all items in your list into one string, then splitting it each time. However, as your Favorites list gets larger, this single long String will too. Splitting and combining all the time isn't efficient.
SharedPreferences is still a decent option if you only have to store the Favorite's list, but since you want to edit it too, it becomes a less attractive solution.
Local Files and Databases are the better options, however local files require you to read in the file each time you want to use it. This process of reading and writing to a file isn't as efficient as using a Database, especially if you want to edit. For example, let's say you want to remove an item from the middle of your Favorite's list. This would require you to read in the file, edit it, then write the change into the file again. Not too pleasant when compared with the ease of the final solution.
Databases are the best option for this, mainly because it's designed to manage data. You can create a single Favorite's table and add each item as it's own individual row. Fetching the entire table becomes quick and easy. Fetching a single item becomes quick and easy. Adding a new item or removing a new item is also quick and easy.
I need some text data (street names of a 2 million town) to get into my android application. I think the best way to do this is to store it into a sqlite database read-only when it starts the first time. As I read, doing this with a pre-defined database is pretty tedious and not clean but you have to copy it from external storage or something and have the data twice then. So I thought about using a CSV file from raw resources and delete it after import, but this is not possible too because this data will be built into the sdk file and can't be deleted any more.
My target is it to make some kind of initial data transfer from local and delete this data source. Any ideas how to achieve that properly? I'd like to go without downloading the data from a server because this would mean that the only reason my application needs an internet connection is because of downloading the initial data. Otherwise it wouldn't need an internet connection.
What about putting the .csv file in you asset folder and read it.
String next[] = {};
List<String[]> list = new ArrayList<String[]>();
try {
CSVReader reader = new CSVReader(new InputStreamReader(getAssets().open("test.csv")));
for(;;) {
next = reader.readNext();
if(next != null) {
list.add(next);
} else {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
I'm thinking I'd compress the data in the initial installation resource and expand it on install. This answer sees to reference a 7zip open source java api.
Data compression on Android (other than java.util.zip ?)
Meanwhile I know that the data I will use in my app is too complex to populate the data by hand. Moreover the app needs internet access at any rate, so I will use a Json string to get the data.
I have an application, and I am trying to set up a fairly large SQLite database (one table with roughly 5000 rows) into it. I have built the DB classes and everything, and my app works when I tested on a smaller scale (400 rows), but now when I want to import my database, I get the out of memory error which I can't seem to find a way to get around.
The database is initially on MySQL on my web server, and I couldn't convert it for some odd reason but I managed to generate a text file with the queries to add all 5000 rows, which is 11.5mb in size. I have this file in my assets folder, and I am trying this to put it into my DB:
public void onHandleIntent(Intent intent) {
DBAdapter db = new DBAdapter(getApplicationContext());
db.open();
try {
InputStream is = getAssets().open("verbs_sql.txt");
db.executeSQL(convertStreamToString(is));
} catch (IOException e) {}
db.close();
// Run main activity
Intent i = new Intent(DatabaseReceiver.this, BaseActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
DatabaseReceiver.this.startActivity(i);
}
public static String convertStreamToString(InputStream is) throws IOException {
Writer writer = new StringWriter();
char[] buffer = new char[2048];
try {
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} finally {
is.close();
}
String text = writer.toString();
return text;
}
}
The out of memory error occurs on the StringWriter(), so it looks likes it putting that big file on to the memory. How can I solve this? I have also tried looping through all 5000 rows but after maybe 30 seconds I got the out of memory again.
I had the same problem. I tried so many ways to solve it but failed. At last i found the reason and i wondered. In my case the reason for the error was i was printing the entire response string in log cat. That data was very huge and it took heap memory.
Take care of the following
Remove Log cat printing of bulk data.
Try to use only one J-SON Array for all Operation under one resonse(Reuse it for all).
Try to avoid array-list usage.
Insert item when each item iterate from J-Son Array. That means don't follow the method in which we are taking the item as object and put it in to an array-list and passing array-list to DB-helper and from there iterate the object and insert.
Sqlite databases are just files, when you're trying to run thousands of inserts on the phone you're hitting the SD card over and over for file access.
What you'll want to do is create the sqlite database on your desktop and include the already created database in the app. If you need to regularly update the information in the database you could post it on a website and have the app download it, just make sure to only do large downloads over Wifi.
Check out this Tech Talk for more information.
Edit: See this for more information on creating an sqlite database in windows and including it in your app.
I believe you could do this in the way you want. The problem with the code you posted is that you are trying to convert the entire file to a string. I am fairly certain that this would fail even on a desktop machine.
I believe that you would have better luck if you tried to read in one line at a time and execute the SQL. Then read the next line. You could also reduce the size of the file by passing it through zip.
If I can find a couple of minutes, I will attach some code.
First, I have researched this question a lot. I learned how to read from my text file in the assets folder. The problem is that I don't want to end up with a string because the file is actually an arraylist written using json and inside that arraylist are objects. I need to access one object only. Here's what I mean:
I have a Book class, which has an int called chapter, an int called title, and an int called pageNum. I created several Book objects and added them to an ArrayList. Then I used the following code to write my ArrayList to a text file (in a regular java project):
ArrayList<Book> aList = new ArrayList<Book>();
aList.add(book1);
//etc...add more Book objects here...
File aFile = new File("books.txt");
FileOutputStream aFileStream = new FileOutputStream(aFile);
JSONOutputStream jsonOut = new JSONOutputStream(aFileStream);
jsonOut.writeObject(aList);
jsonOut.close();
That code creates a text file which I then put into the /assets folder in my Android project because I want it included with the app. In a non-Android java project I could simply use the following code to repopulate an ArrayList so that I could parse Book obects from specific indexes:
File bFile = new File("books.txt");
FileInputStream bFileStream = new FileInputStream(bFile);
JSONInputStream jsonIn = new JSONInputStream(bFileStream);
Arraylist<Book> bList = (ArrayList<Book>) jsonIn.readObject();
Book aBook = bList.get(253); //some arbitrary index
The json code I'm using comes from quickconnectfamily.org. You have to add a file called qc_json.jar to the build path of your project. http://www.quickconnectfamily.org/qcjson/more.html
The problem in Android is when I read the file using InputStream, I can only get the entire file into a string, the code above doesn't work in Android. I can't wrap JSONInputStreams around an InputStream, only around a FileInputStream. But it seems I am unable to use
FileInputStream.
So what I need is a way to create an ArrayList rather than a string in my Android app.
Without giving away too much about my app, the app basically generates a random number and creates a Book object from that index in the ArrayList. Then the user is quizzed with info from that specific book. Sounds silly, but the real app is much cooler.
I'm open to solutions, alternative methods of storing objects in a text file, etc. Please don't simply post criticism about my grammar, syntax, or application idea. I'm pretty new to app development and I couldn't care less about personal opinions. If anyone wants to see
more code I can upload it, but it doesn't seem necessary at this point. Thanks.
I figured out the solution. I connected my Evo 4G and tested the app and it worked. Here's what I did:
I used the following method to read from the file, which is what I was doing before:
InputStream is = appContext.getAssets().open("books.txt");
int size = is.available();
buffer = new byte[size];
is.read(buffer);
is.close();
String bufferString = new String(buffer);
When you do this, you end up with a String of the entire file. This is what I was able to do before, but what I wanted was a way to convert the String to an ArrayList of Book objects. Here's how I accomplished this:
//convert string to JSONArray
jsonArray = new JSONArray(bufferString);
//parse an Object from a random index in the JSONArray
JSONObject anObject = jsonArray.getJSONObject(randomNum);
Book aBook = new Book();
aBook.setTitle((String) anObject.get("title"));
//you can continue to set the different attributes of the Book object using key/value pairs from the Book class (e.g. setPageNum, setChapter, etc).
I don't know, maybe that was obvious to some people, but I really couldn't find any examples that did this. In a different question someone mentioned using the json library native to Android org.json and so I tried that and it worked.
I want to know a good way to create a list in my android app. I have all info in my DB and want to load data from it each time I start the app and make a list from it (id and title).
What is the best approach?
Should I make a PHP-script that responds with a JSON encoded array with all list items or should I make an XML-file that generates each time the data in the DB changes that I import to the app each time it starts? or any other good way to do it?
Since all stuff are made by XML-files in android it feels like importing a XML would be a good thing, is it? And how do I import an XML-file from a web server into the app?
// Daniel
You can use either JSON or XML.
You can use the web service approach or you can include your db with your application.
In fact, I most often choose to create a sqlite3 database of my data and include it in the assets folder, which can be copied to the app's data folder on startup.
As for copying your sqlite3 database from assets/ to the db data directory, I found these instructions helpful.
In your situation I would pick JSON over XML for all the reason's stated in the following post: http://ajaxian.com/archives/json-vs-xml-the-debate
Plus, in android, there are JSON Array's built in by default so you don't have to do any extra passing of the code.
return new JSONArray("my json string goes here...");
Since we are talking about a mobile device, I would always generate changes in your php script rather than have a full sync as this will be a lot smaller in size that a full sync. However, you will need to give your user a option to do a full re-sync if this is applicable to your app. I would use a SQLite database to store the data and only update the changes in that.
To also make the stream smaller, you can gzip compress your output from php as this can be natively read by the android device. In my app, I compress 500kb down to ~110kb before transmitting, a huge saving on performance. Here a partial example of how to read the stream:
InputStream in = null;
HttpURLConnection httpConn = null; // you will have to write your on code for this bit.
if (httpConn.getContentEncoding() != null)
{
String contentEncoding = httpConn.getContentEncoding().toString();
if (contentEncoding.contains("gzip"))
{
in = new GZIPInputStream(httpConn.getInputStream());
}
}
else
{
in = httpConn.getInputStream();
}
I hope that this all makes sense, it's been a long day programming :)
Stu