I've been investigating alternative methods for saving my game's data between turns, and wonder if anyone can point me in the right direction.
I have approximately 32k of data which must be saved during onPause. I ruled out preferences due to the sheer quantity of data. I spent a few days playing around with SQLite but couldn't get the data to save in less than two seconds (although the time certainly hasn't been wasted).
I've decided that I'll use the database for loading constant data at the beginning of the game. This will certainly make it easier to tweak various parameters and default values in the game. But this still leaves me looking for the ideal method for writing data.
The data that needs to be saved is basically nine occurrences of class A and nine occurrences of class B. I'm an intensive month into the learning curve of Android (and the nuances of Java, coming from a C++ background) and have been googling like crazy. This brought two possibilities to mind -
1) Serialization (ObjectOutputStream)
I thought this would be the perfect solution but, having read several other posts regarding the subject, gather that it isn't highly recommended on the Android platform due to speed and memory allocations provoking the garbage collector into a potential rage.
2) DataOutputStream class
My current thought is to add Load and Save functions to both classes and to use DataOutputStream and DataInputStream calls in them to write and read the data respectively.
The data in the classes are primitives (strings and ints mostly) and arrays of primitives, so there's nothing too complicated in there to break down. Would this second solution seem a good, viable one? Or are there other solutions that I am unaware of as yet?
You should use an Async task to save the data, I used this method to fetch highscores at the start a game:
new HighscoreTask().execute(this);
the Async task looks like this:
public class HighscoreTask extends AsyncTask<MainView, Void, Void> {
protected void onPreExecute() {
}
protected void onPostExecute(final Void unused) {
}
#Override
protected Void doInBackground(MainView... params) {
HighScoreFactory.syncScores();
return null;
}
}
All the database interaction happens in HighScoreFactory.syncScores() this can take as long as it needs because it happens in the background. In my case it sends an HTTP request to an external server and loads these into a database. It's never caused any problems and works seamlessly.
Why do you have a 2 second limit on your database write? If it is purely for the sake of UI responsiveness, then there is another approach you can take.
You don't actually have to perform the save within your onPause method itself, you could just kick off a new Thread that actually does the save for you.
private void backgroundSave(){
Thread backgroundThread = new Thread() {
#Override
public void run() {
//do save here
}
};
backgroundThread.start();
}
#Override
protected void onPause() {
super.onPause();
backgroundSave();
}
You could alternatively use an AsyncTask for this.
You might have to consider the case when a user attempts to restart your app before the save is complete, but that shouldn't be too hard to take into account.
Have you tried insert data to the database in transaction?
try{
db.beginTransaction();
//here insert data to database
db.setTransactionSuccessful();
} finally {
db.endTranscation();
}
That can speed up operation.
Create a new Thread that does the data writing using Context.openFileOutput(String name, int mode) with this as the context. You can then write it in the background with the new thread and retrieve it with: Context.openFileInput(String name) again with this as the context. Hopefully this helps.
Related
My question is very simple, what is the best approach to work with Parse using the local store at the time I want to query the saved objects.
Is it better to trigger several queries to the local store directly on the main thread and avoid nesting a lot of anonymous classes or using a background thread?
It's important thing to notice is that this method is going to be called very frequently and the pattern will be repeated in several places with different queries. I'm evaluating both efficiency and code quality in readability. These methods will be called synchronously so we can assume the data will be consistent at any time.
As the objects are being saved locally I would expect the queries to be very fast in response. Here's a rough sample of how the code would look like in both cases.
Option one:
public void processBatches() {
ParseQuery<Batch> batchQuery = Batch.getQuery();
int batchCount = batchQuery.fromLocalDatastore().count();
List<Batch> batches = batchQuery.fromLocalDatastore().find();
for(Batch b : batches) {
// do whatever I need to do
}
}
Option two:
public void processBatches() {
ParseQuery<Batch> batchQuery = Batch.getQuery();
int batchCount = batchQuery.fromLocalDatastore().countInBackground(new CountCallback() {
#Override
public void done(int i, ParseException e) {
if (i > 0) {
batchQuery.findInBackground(new FindCallback<Batch>() {
#Override
public void done(List<Batch> list, ParseException e) {
for (Batch batch : list) {
// do whatever I need to do
}
}
});
}
}
});
}
Well since in option one you are blocking the UI thread, there could be a delay in the user's ability to interact with your application. This is not a very good option since even if it is for just a moment, users don't want to be waiting unless they know operations are happening. But, if you know that at any time there will be little to no delay, go ahead and do it.
Nevertheless, I argue that option two is going to be the best option. This is because, in general, all network operations should be performed in the background. Although in your case you are performing local datastore queries, suppose a user has gone to their application task manager and cleared the data (very rare this will happen) what happens now when you perform the find from local data store and processing of Batch objects? Well, the app crashes. Again, this is not a very good option for the usability for your application.
Choose the second option, and allow an AsyncThread to run the find() and count() query operations to the network if there is nothing found from local data store queries. Also, from the Parse documentation for find:
public Task<List<T>> findInBackground()
Retrieves a list of ParseObjects that satisfy this query from the source in a background thread.
This is preferable to using ParseQuery.find(), unless your code is already running in a background thread.
Returns:
A Task that will be resolved when the find has completed.
Parse's creators prefers that the users of their API use a background thread to perform operations.
It really depends.
Is the user triggering the update? If so then do it on the main thread because you don't want them waiting
If not, then is the data access a result of fetching data from the web (and hence you should already be on a background thread) so could probably just remain on the background thread
Also what happens in "// do whatever I need to do"? Is it an update to the UI or more background processing?
I have severals URLs I need to get data from, this should happen in order, one by one. The amount of data returned by requesting those URLs is relatively big. I need to be able to reschedule particular downloads which failed.
What is the best way to go? Shall I use IntentService, Loaders or something else?
Additional note: I would need not only to download, but also post process the data (create tables in db, fill it with data, etc). So DownloadManger can't be of help here.
I would use an IntentService.
It has a number of advantages that are suitable for your needs, including being able to download the data without your application running and supporting automatic restart of the service using setIntentRedelivery().
You can set a number of identifiers for the particular job, you need to perform using Intent extras, and you can keep track of the progress using SharedPreferences - that way you can also resume the work if it's been cancelled previously.
The easiest way is probably to use the system DownloadManager http://developer.android.com/reference/android/app/DownloadManager.html
(answering from my phone, so please excuse the lack of formatting)
I would suggest a service for this. Having service resolves many problems
It would allow reporting of progress asynchronously to the application so you can enable or disable a specific gui in application based on the download status of data
It will allow you to continue the download even if the user switches to other application or closes the application.
Will allow you to establish independent communication with server to prioritize downloads without user interaction.
Try a WakefulIntentService for creating a long-running job that uses wakelocks to keep your task alive and running https://github.com/commonsguy/cwac-wakeful .
Also, if your whole app process is getting killed, you may want to look into persisting the task queue to disk, using something like Tape, from Square
I think the way to go is loading urls in an array, then starting an AsyncTask, returning a boolean to onPostExecute indicating if the operation has success or not. then, keeping a global int index, you can run the AsyncTask with the next index if success, or the same index otherwise. Here is a pseudocode
private int index=0;
//this array must be loaded with urls
private ArrayList<String> urlsArray;
new MyDownloaderAsyncTask().execute(urlsArray.get(index));
class MyDownloaderAsyncTask extends AsyncTask<String,String,Boolean>{
#Override
doInBackground(String... input){
//downlaod my data is the function which download data and return a boolean
return downloadMyData();
}
#Override
onPostExecute(Boolean result){
if(result)
new MyDownloaderAsyncTask().execute(urlsArray.get(++index));
else
new MyDownloaderAsyncTask().execute(urlsArray.get(index));
}
}
hope this help
I have just completed an open source library that can do exactly what you need. Using droidQuery, you can do something like this:
$.ajax(new AjaxOptions().url("http://www.example.com")
.type("GET")
.dataType("JSON")
.context(this)
.success(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
//since dataType is JSON, params[0] is a JSONObject
JSONObject obj = (JSONObject) params[0];
//TODO handle data
//TODO start the next ajax task
}
})
.error(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
AjaxError error = params[0];
//TODO adjust error.options before retry:
$.ajax(error.request, error.options);
}
}));
You can specify other data types, which will return different object types, such as JSONObject, String, Document, etc.
Similar to #Murtuza Kabul I'd say use a service, but it's a little complicated than that. We have a similar situation related to constant internet access and updates, although ours places greater focus on keeping the service running. I'll try to highlight the main features without drowning you in too much detail (and code is owned by the company ;) )
android.permission.RECEIVE_BOOT_COMPLETED permission and a BroadcastReceiver listening for android.intent.action.BOOT_COMPLETED to poke the service awake.
Don't link the service to the Activity, you want it running all the time. eg we call context.startService(new Intent(context.getApplicationContext(), OurService.class))
The service class is just a simple class which registers and calls an OurServiceHandler (as in our case we fire off repeated checks and the Handler manages the 'ticks')
We have an OurServiceRunnable which is a singleton which is checked and called by the Handler for each test. It protects against overlapping updates. It delegates to an OurServiceWorker to do the actual lifting.
Sounds heavy handed, but you want to ensure that the service is always running, always ticking (via the Handler) but only running a single check at a time. You're also going to run into database issue if you use the standard SqlLite DbHelper paradigm, as you can't open the DB on multiple threads and you definitely want the internet access off the main thread. Our hack was a java.util.concurrent.locks.ReentrantLock protecting access to the DB, but you could probably keep DB access on the UI thread and pass DB operations via the Handler.
Beyond this it's just a matter of keeping the downloads atomic in terms of "get task, download task, complete task" or enabling it to pick up from a failed state eg downloaded OK, attempt to complete.
You should take a look at the volley library :
http://www.javacodegeeks.com/2013/06/android-volley-library-example.html
There is also an interesting video of the author that took place at google io 2013 :
http://www.youtube.com/watch?v=yhv8l9F44qo
Mainly because it eases the process of managing a lot of these fastidious tasks that are connection checking, connection interruption, queue management, retry, resume, etc.
Quoting from the javacodegeeks "Advantages of using Volley :
Volley automatically schedule all network requests. It means that Volley will be taking care of all the network requests your app executes for fetching response or image from web.
Volley provides transparent disk and memory caching.
Volley provides powerful cancellation request API. It means that you can cancel a single request or you can set blocks or scopes of requests to cancel.
Volley provides powerful customization abilities.
Volley provides Debugging and tracing tools"
Update from dennisdrew :
For large file, better use a variant of volley which authorize using another http client implementation. This link gives more details :
The volley article about this modification :
http://ogrelab.ikratko.com/android-volley-examples-samples-and-demos/
The github file detail :
https://github.com/ogrebgr/android_volley_examples/blob/master/src/com/github/volley_examples/toolbox/ExtHttpClientStack.java
public class FetchDataFromDBThread implements Runnable {
/*
* Defines the code to run for this task.
*/
#Override
public void run() {
// Moves the current Thread into the background
android.os.Process
.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
FetchDataFromDB();
}
}
I'm currently developing an application on Android platform that needs to contact the main server multiple times to do various stuff. I'm now coping with the issue of software design in terms of making every request to the server in a separate thread (otherwise, I get a NetworkOnMainThreadException and it's not recommended to do so).
So I have 3 classes in my example:
The requester class that wants to, say, fill up a Spinner with data from a database located in a server.
The middle class that asks a DBConnection to perform a new connection, then wait for it to finish and parse the data to the appropriate format.
The lower class that makes the connection to the database and retrieves a raw String, which then is passed to the middle class to be parsed.
I know that for every connection made to the server, I'll have to create a new thread, so that's made in the class that establishes the connection (lower class) and waits for results. This way I don't overload the top layers of my software with AsyncTasks and stuff that they shouldn't be aware of.
The problem is that after I receive the data I have to parse it, and the do stuff with it. Also I have to fill up the spinner (as in the example).
I know it might be a good idea to make a DataFromServerListener interface or something like that, but I think it's gonna get cluttered with methods all around to handle data from server. On the other hand, I'd have to make every top class start the separate thread with an AsyncTask and might not be the best solution.
I'd really appreciate any suggestions on this subject. :D
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
return "Executed";
}
#Override
protected void onPostExecute(String result) {
}
}
This is kind of what I needed. Actually, it solves problems I didn't take care of before.
http://www.codeproject.com/Articles/162201/Painless-AsyncTask-and-ProgressDialog-Usage
Folks,
I'm looking for a design pattern that enables a UI thread to interact with a client-side SQLite database that may have bulk inserts (taking 10s of seconds), quick inserts, and reads, and doesn't block the UI thread.
I would like advice on whether or not I am using the optimal design pattern for this, as I have been recently debugging deadlock and synchronization issues and I am not 100% confident in my final product.
All DB access is now bottlenecked through a singleton class. Here is pseudocode showing how I am approaching writes in my singleton, DataManager:
public class DataManager {
private SQLiteDatabase mDb;
private ArrayList<Message> mCachedMessages;
public ArrayList<Message> readMessages() {
return mCachedMessages;
}
public void writeMessage(Message m) {
new WriteMessageAsyncTask().execute(m);
}
protected synchronized void dbWriteMessage(Message m) {
this.mDb.replace(MESSAGE_TABLE_NAME, null, m.toContentValues());
}
protected ArrayList<Message> dbReadMessages() {
// SQLite query for messages
}
private class WriteMessageAsyncTask extends AsyncTask<Message, Void, ArrayList<Messages>> {
protected Void doInBackground(Message... args) {
DataManager.this.mDb.execSQL("BEGIN TRANSACTION;");
DataManager.this.dbWriteMessage(args[0]);
// More possibly expensive DB writes
DataManager.this.mDb.execSQL("COMMIT TRANSACTION;");
ArrayList<Messages> newMessages = DataManager.this.dbReadMessages();
return newMessages;
}
protected void onPostExecute(ArrayList<Message> newMessages) {
DataManager.this.mCachedMessages = newMessages;
}
}
}
Highlights:
First: all public write operations (writeMessage) happen via an AsyncTask, never on the main
thread
Next: all write operations are synchronized and wrapped in
BEGIN TRANSACTIONS
Next: read operations are
non-synchronized, since they need not block during writes
Finally: the results of read operations are cached on the main
thread in the onPostExecute
Does this represent the Android best practice for writing potentially large volumes of data to a SQLite database while minimizing impact to the UI thread? Are there any obvious synchronization issues with the pseudocode you see above?
Update
There is a significant bug in my code above, and it is as follows:
DataManager.this.mDb.execSQL("BEGIN TRANSACTION;");
That line acquires a lock on the database. However, it is a DEFERRED lock, so until a write happens, other clients can both read and write.
DataManager.this.dbWriteMessage(args[0]);
That line actually modifies the database. At this point, the lock is a RESERVED lock, so no other clients may write.
Note there are more possibly expensive DB writes after the first dbWriteMessage call. Assume that each write operation happens in a protected synchronized method. That means that a lock is acquire on DataManager, the write happens, and the lock is released. If WriteAsyncMessageTask is the only writer, this is fine.
Now let's assume that there is some other task that also does write operations, but does not use a transaction (because it's a quick write). Here's what it might look like:
private class WriteSingleMessageAsyncTask extends AsyncTask<Message, Void, Message> {
protected Message doInBackground(Message... args) {
DataManager.this.dbWriteMessage(args[0]);
return args[0];
}
protected void onPostExecute(Message newMessages) {
if (DataManager.this.mCachedMessages != null)
DataManager.this.mCachedMessages.add(newMessages);
}
}
In this case, if WriteSingleMessageAsyncTask is executing at the same time as WriteMessageAsyncTask, and WriteMessageAsyncTask has executed at least one write already, it is possible for WriteSingleMessageAsyncTask to call dbWriteMessage, acquire the lock on DataManager, but then be blocked from completing its write due to the RESERVED lock. WriteMessageAsyncTask is acquiring and giving up the lock on DataManager repeatedly, which is a problem.
The takeaway: combining transactions and singleton object-level locking could lead to deadlock. Make sure you have the object-level lock prior to beginning a transaction.
The fix to my original WriteMessageAsyncTask class:
synchronized(DataManager.this) {
DataManager.this.mDb.execSQL("BEGIN TRANSACTION;");
DataManager.this.dbWriteMessage(args[0]);
// More possibly expensive DB writes
DataManager.this.mDb.execSQL("COMMIT TRANSACTION;");
}
Update 2
Check out this video from Google I/O 2012:
http://youtu.be/gbQb1PVjfqM?t=19m13s
It suggests a design pattern making use of the built-in exclusive transactions and then using yieldIfContendedSafely
I can't really say much about the synchronization/deadlock part, that would be hugely dependent on the rest of your code. Since DataManager class doesn't really interact with the UI, you might want to use a service (IntentService) rather than an AsyncTask. You can show notifications when you are done syncing. You don't really need onPostExecute() if you are not calling UI code.
You may want to consider this info from the SDK (http://developer.android.com/reference/android/os/AsyncTask.html)
When first introduced, AsyncTasks were executed serially on a single
background thread. Starting with DONUT, this was changed to a pool of
threads allowing multiple tasks to operate in parallel. Starting with
HONEYCOMB, tasks are executed on a single thread to avoid common
application errors caused by parallel execution.
If you truly want parallel execution, you can invoke
executeOnExecutor(java.util.concurrent.Executor, Object[]) with
THREAD_POOL_EXECUTOR.
FYI, every SQL statement ran on SQLite is ran under a transaction even if you don’t specify one.
Check below threads if you are doing Bulk Insert in SQLite:
Android Database Transaction
SQLite Bulk Insert
Hey, I have an application which logs onto a few sites using defaulthttpclient and I've found I'm going to need to use the AsyncTask as the requests hold up the UI thread. In my code, I create an instance of a state class i.e. State state = new O2State(); with different states for different sites.
I then call state.logon(String username, String password); which returns a string containing details of the result so:
String result = state.logon(username, password);
I've been trying to implement asynctasks to run this code in another thread and return the string back to the UI thread on completion. The idea is I will display a progress dialog, run the thread, and on complete, will display a dialog with the result.
I've been looking at this example:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
Where I'm stuck is:
I don't think I'll need any arguments, but doinbackground seems to require a list of parameters. I'm also unfamiliar with this time of method argument declaration.
Secondly:
I'm not sure how to return the resulting string when the thread is finished executing. Should I just create a "DoThisWhenTheThreadIsFinished(String result)" and call this from onPostExecute?
Anyway, I hope this isn't too confusing to read and I'd really appreciate any help you can offer.
Thanks
Where you don't need parameters just specify the type (e.g. String) and ignore it, or you could use the Void class (note the capital V).
What you suggest for how to return control back to the UI thread to reflect the update is a good approach. i.e. in onPostExecute() call a method on the activity to update the UI.
As a general rule if any operations will take more than a couple of hundred milliseconds, use a separate thread. You may also want to use a rotating progress indicator to show the app is doing something.
(when people answer your questions, always rate the ones you like, and pick one as the "best" answer. you get points doing this, and it helps others later).