Read Large File and Insert inside Room Database - android

I am making an app that blocks inappropriate websites for parental control, I have the blocked websites in a text file which 50MB in size. I want to add them all to room database so that I can check if a url is blocked or not.
But reading and looping through each line in the text file taking forever, is there any better way I can read the file and add each line to room database?
FileInputStream inputStream = null;
Scanner sc = null;
try {
inputStream = new FileInputStream(path);
sc = new Scanner(inputStream, "UTF-8");
while (sc.hasNextLine()) {
String line = sc.nextLine();
// insert to room database
}
// note that Scanner suppresses exceptions
if (sc.ioException() != null) {
throw sc.ioException();
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (sc != null) {
sc.close();
}
}

Make it as json and place it your project..
And when starting the application show a syncing state and load data to db ..
Do this only once.

You have a few options. As previously stated you could load the websites into json. This website should help automate that a bit. https://pdfmall.com/txt-to-json. This approach would still lead to an O(n) time complexity for searching.
While it will take a bit of memory, the method I'd recommend would be to build a custom object that holds all of those lines as Strings. Every time you start the app you would need to rebuild this object, but that's better than scanning constantly. You could implement an Async thread to do this in the background.
If you take this approach I would recommend storing them in a Olog(n) data structure like a binary tree. You don't want to just throw them into an Arraylist of strings, because then you'd be doing the same thing and having to scan through the entire array. If you store them in a tree, ordered by alphabetical order or perhaps length - whatever you want to do- then you reduce your search complexity from O(n) to Olog(n). Keep in mind when using custom objects, if you intend to pass them between Activities, you will need to implement Parcelable or another method.
Third you could use an Sql database, but in your case I don't believe this would speed anything up, so I wouldn't recommend it.

Keep the urls in the text file sorted alphabetically.
Load the file in a string array list.
Do a simple binary search in the sorted list to check for an specific url.

Related

What is the best way to store parsed json data

i would like to ask, how to store json data. I have a JSON file, which i parse using JSON Library. Now i got the data from a file. But i want to store them and show them later again.
The question is, whats the best way to store data? And is it even worth to store them?
I'm thinking about sql database, because its simple and most used.
Official android docs have few examples, so far i searched but if u have better guide, let me know.
Thank you! :)
EDIT1:
Ok, i have json file with data, which i can add to my app using RAW resources. Those data wont change, its a list of recipes, i dont have to download it. I can read the data like this:
InputStream is = mContext.getResources().openRawResource(R.raw.package_01);
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
is.close();
//catchblock
.....
}
and then i can parse the data trought JSONLibrary like this:
try {
//representing []JSON
JSONArray jsonArray = new JSONArray(writer.toString());
if(jsonArray != null){...}
...}
Im sending a HashMap to ListView, which includes name and id. And if the user clicks the ListView/GridView item, there is new Activity started, which shows all parsed data. I need to get match those parsed data with the id.
There are about 200 recipes in the file. The data are parsed on start of the Activity, while Splashscreen is displayed. I´m not sure, if its good idea to parse the data everytime when app starts.
So, is it effitient to parse data everytime the app starts? And if yes, how to keep the parsed data "together"? Should i use HashMap?
I hope i clarified my question :) Thanks for help.
EDIT2:
So after i knew what to do, i tried the suggested solution to use HashMap. Problem was there i got Failed Binder Exception. I have images encoded in Base64, that means i have a very long String, example here. That is a lot of data, there is limit:
The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process.
I´ve tried to save it to
Set<String> titles = new HashSet<String>();
and then to SharedPreferences but the data for each recipe gets mixed.
**So, here it comes again, should i save the data to SQLite database or is there another effective option i can use? **
Thank you!
It really depends on a number of things like: How much data do you have now, how much will you have later, how complicated is the data. You could use something as simple as an array or hashmap; or something as complex as a database. You need to consider what you are trying to do , and find the simplest solution. If you are trying to persist data, you could use shared preferences, database, and internal/external storage (options outlined here).
Without more information it's hard to say what exactly to do. Keep it simple though. If you are getting JSON from a web service, I'd use an ArrayList or HashMap to store the data, rather than persisting it. It is simpler to implement and does the job.
EDIT:
To answer your question: Yes, using a HashMap and parsing each time is fine. You only have 200 fields, and you don't have images, so the time it will take to parse is minimal. Regardless of how you store the data, there is going to some level of "parsing" done. For example, if you store the data in a database, you are going to have to still pull the data, and put it into a HashMap.

Importing data at initial start of application in Android?

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.

android how to keep large List<String[]> while application runs

What is the best way to keep a List<String[]> while my application runs? I am having problems with my approach. It most of the time gives me an OutOfMemory Error since the list is too big.
The List<String[]> is the result of parsing a csv file that I have downloaded online. What I do is parse the csv in an activity then save its result in a static class member like:
String url = "http://xxx/pdf/pms/pms_test.csv";
try {
InputStream input = new URL(url).openStream();
CSVReader reader = new CSVReader(new InputStreamReader(input));
SchedController.sched = reader.readAll();
input.close();
}
...then access ClassName.sched on different activities.
I am doing this so that the parsed data will be available in every activity... And I don't have to parse again. What can I do to improve it?
I think you can have 2 approaches.
You save the file and parse it in a lazy loading way
You create a database and save your data.
I suggest you to create a database, this is not difficult and let you to manage well your data. You can do easily lazyLoading with cursor, or use a ORM (ORMLite / Greendao)... I think this is the best way and the fastest to load your data.
Hope this will help you.
Just to add to Paresh's comment.
I can suggest something similar I used in my app.
For example I need to display list of Items in a store. (Each item will have ID, name and cost).
To achieve this I first make a request to server to get number of items, say itemCount.
Now I set a limit to number of items displayed in a page say 100.
If the itemCount is greater than 100, I display an alert saying only 100 items will be displayed and a next button can be added to download next set of items.
Or if it is a search you can ask user to go back and refine the search.
If itemCount is less than 100 then you will not have any issues
This way Paging can be implemented to avoid OutOfMemory issues

Android Out of Memory Error: How to solve this?

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.

Create list in android app

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

Categories

Resources