I'm designing out a module in Android that does some processing and then writes to the database using ORMLite transactions. In particular, my background code will be something like:
public class BackgroundOperation implements Runnable {
#Override
public void run() {
//Do some stuff
//Write to the database in a transaction
try {
ORMHelper h = ORMHelper.getDefaultOrmHelper();
final MyModel modelObj = h.myModelDao.queryForId(someId);
TransactionManager.callInTransaction(
h.getConnectionSource(),
new Callable<Void>() {
public Void call() throws Exception {
modelObj.col1 = 10;
modelObj.col2 = "hello";
h.myModel2Dao.update(modelObj);
h.myModel2Dao.create(new MyModel2("a", "b"));
return null;
}
}
);
}
catch (Exception e) {
return null;
}
}
}
This runnable will then be executed by being submitted to a ThreadPoolExecutor. I want to be able to cancel the background thread if needed and am trying to make sure that if the operation is cancelled, then the transaction will simply fail and do nothing. For example, if I do this:
Future f = myThreadPoolExecutor.submit(new BackgroundOperation());
//Some time later
f.cancel(true);
Can I be sure that it will be an all or nothing deal with the transaction in ORMLite. That is, there is no cleanup needed and my modelObj will have either both col1 and col2 set or neither set? Do I have to do anything special when catching the InterruptedException in the Runnable to handle the case when a task is cancelled in this way, or can I simply exit?
If you call f.cancel(true), all that does is interrupt the Thread which causes wait(), sleep(), and some other methods to throw InterruptedException. It will not cancel the database transaction underway.
If you want, you can check for the interrupted bit in the middle of your IO operations:
h.myModel2Dao.update(modelObj);
if (Thread.currentThread().isInterrupted()) {
throw new RuntimeException("Thread was interrupted");
}
h.myModel2Dao.create(new MyModel2("a", "b"));
For more information about what happens when a thread is interrupted see here:
What does java.lang.Thread.interrupt() do?
Transactions are for when you are updating multiple objects as a single unit or writing to multiple tables. See the documentation about transactions which has an example of updating an Account and an Order inside of a transaction.
Also, you do not need to use a transaction if you are updating multiple fields in the same row. The update statement is considered to be a single unit and the database should ensure that the row gets updated atomically. Only if you are updating multiple different rows either in the same table or in separate tables do you need a transaction.
ORMLite will utilize the sqlite transactions under the covers. This is most likely a double phase commit which only allows you to commit a transaction as an entire unit.
In short, you can be assured that col1 and col2 will only be modified as a single atomic unit. Also, it if is interrupted the commit will fail and the changes to col1 and col2 will be rolled back.
Related
Iam trying to figure out what RunInTransaction eventually does. Room documentation doesnt say much other than "Executes the specified Runnable in a database transaction".
From what i understand:
If we have an asynchronous operation like a query and then some insertion without the runInTransaction
roomDB.runInTransaction(new Runnable() {
#Override
public void run() {
query
}
});
insertions
insertions
The runInTransaction locks the database until the specified operation is completed. So at the first insertion the Thread pauses (please correct me) until the runInTransaction completes.
How can i control which procedure executes first?
But i think that database either way locks the tables and without using runInTransaction method. Please correct me if iam wrong.
Updated
#Dao
public interface RepoDao {
#Query("SELECT * FROM Table")
LiveData<List<Table>> getAll();
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(List<Table> table);
}
Main Activity
repo = ((BasicApp)getApplication()).getRepository();
repo.insertDataFromNetwork();
((BasicApp)getApplication()).getDatabase().repoMethods()
.getAll().observe(this, new Observer<List<Table>>() {
#Override
public void onChanged(#Nullable List<Table> message) {
Log.d("hello");
}
});;
insertDataFromNetwork
mDatabase.runInTransaction(new Runnable() {
#Override
public void run() {
mDatabase.repoMethods().insert(....);
mDatabase.repoMethods().insert(....);
mDatabase.repoMethods().insert(....);
mDatabase.repoMethods().insert(....);
mDatabase.repoMethods().insert(....);
}
}
});
A transaction symbolizes a unit of work performed within a database management system against a database. (Wikipedia)
It means that, if you, for example, will insert 10 users and update 10 other users not using runInTransaction method, Room will execute each insertion and update as a single action (transaction), and will update observers, who are observing changes on the Users table each time. While doing the same thing in runInTransaction method will perform all this changes as one action (transaction) and will notify listeners only once.
How can i control which procedure executes first?
Just run them sequentially in a single thread.
And don't run database transactions in the main thread.
I am using MPAndroidChart to draw some charts in android. The problem I'm facing is that the following code is executed in asynchronous way. E.g:
Log.d("Starting data load","Starting data load");
x1.setValueFormatter(new GraphXAxisValueFormatter(xLabels_nl,chart));
chart.setData(data);
chart.fitScreen();
Log.d("Finished data load","Finished data load");
"Starting data load" is logged to console
setValueFormatter is initiated
"Finished data load" is logged to console
setValueFormatter is still running
The problem is that when setValueFormatter is still running, if the described code is executed second time, the chart does not zoom/drag correctly to it's initial position.
Is there a way to wait till the first execution of "x1.setValueFormatter(new GraphXAxisValueFormatter(xLabels_nl,chart));" is finished when it is started second time ?
The GraphXAxisValueFormatter is class that overrides the following method:
#Override
public String getFormattedValue(float value, AxisBase axis) {
...
return <axis values for each point at position "value">
}
Thanks
The real solution is probably elsewhere, you should raise an issue on the open source library https://github.com/PhilJay/MPAndroidChart/issues
Hack Alert
But you can make arbitrary code wait for you if you want:
final CountDownLatch latch = new CountDownLatch(1);
Log.d("Starting data load","Starting data load");
final GraphXAxisValueFormatter graphFormatter = new GraphXAxisValueFormatter(xLabels_nl,chart)
x1.setValueFormatter(new IValueFormatter() {
#Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
String result = graphFormatter.getFormattedValue(value, entry, dataSetIndex, viewPortHandler);
latch.countdown();
return result;
}
});
try {
latch.await(); // this will make this Thread wait until countdown() is called
} catch (InterruptedException e) {
// uh oh, deal with error
}
chart.setData(data);
chart.fitScreen();
Log.d("Finished data load","Finished data load");
Note - you cannot make the MainThread wait too long or you will get an ANR (you shouldn't make it wait at all really)
MPAndroidChart classes like LineChart are subclasses of View and thus should be updated on the UI/main thread.
If you are performing processing of data on another thread (in, say, an AsyncTask or using RxJava) that is fine. However, modifications of the View object itself (such as mutating the DataSet or IValueFormatter for the chart) should be done on the UI/main thread or you will run into synchronisation problems like the one that seems to be occurring above. This is the standard pattern for most standard Android Views, not just MPAndroidChart. Note that none of the methods in LineChart etc. actually spawn another thread so it is the responsibility of the consumer to ensure they are using the correct thread.
Additionally, after you have updated the DataSet you will need to call ChartData#notifyDataSetChanged(); to get the library to recalculate the min/max.
I am new to threading and i went through many post in stack overflow and find many solution for my problem but i am not sure which one is best for which condition.
First thing first, my problem is that i want to update one JSON file
when all threads are done with the bitmap generation at a specific path so
that i can get that all those image and update JSON file. So in
simple word my i want to run some code when all thread are done with it
execution and major requirement is that i don't want my main to be blocked because of this.
What i have found out
thread. join
excutorServive
android-priority-jobQueue (link)
Mutex in threadpool ( also let me know if any other is there)
I am confused which one is the best way to tackle my problem. if any
android expert out there can summarise that for following the two
scenerio what is the best available in android.
wait till when all thread completes
don't wait and get informed when all completes
You can have counter for your threads, after each thread is complete check how many have already completed, if not all completed, increment the number of completed threads and the last thread to complete will then run the piece of code.
You can do it like this.
In your thread:
private Runnable runnableThread= new Runnable() {
#Override
public void run() {
try {
if (lastThreadDone){
handler.sendEmptyMessage("SUCCESS");
}
}
catch (Exception ex) {
throws ex;
}
}
};
lastThreadDone is boolean which will become true if the process is done, this is base on how you implement it.
then in you handler:
#SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
try {
switch (msg.what) {
case "SUCCESS": {
// your code here
break;
}
case "FAIL":
break;
default:
break;
}
}
catch (Exception ex) {
throw ex;
}
super.handleMessage(msg);
}
};
I would use a completion service and then poll until all tasks are finished. When they are done, the json file gets updated. The problem is that you need to do this async or you risk to block the ui. Therefore I would encapsulate the work with the completion service inside an intent service. If you need to update the ui you then can post local broadcasts from the intent service.
Furthermore for you cases
wait till when all thread completes
only do this when you are already on a background thread like intent service or async task
don't wait and get informed when all completes
implies the case above. Do the work async and notify the ui or some listening component with broadcasts, content observers, handlers or the 'onPostExecute' if you are using async task.
I am getting this error in my Activity where I use Parse SDK. The whole code is here, but the code is huge and the crash is not even giving me the line of code where it is occuring. I searched a lot but found nothing about this error. Can anyone tell me what exactly this error means?
Screenshot:
Since adding a code example, I will write an answer.
You are using AsyncTask to do multiple queries and to know when these finish.
Parse recently added Bolts to their API (1.7.0 or 1.7.1) https://github.com/BoltsFramework/Bolts-Android
With Bolts you can do the same as you can with Promises in javascript, in case you are familiar with that.
A simple example deleting all objects matching a query:
findAsync(query).continueWithTask(new Continuation<List<ParseObject>, Task<Void>>() {
public Task<Void> then(Task<List<ParseObject>> results) throws Exception {
// Collect one task for each delete into an array.
ArrayList<Task<Void>> tasks = new ArrayList<Task<Void>>();
for (ParseObject result : results) {
// Start this delete immediately and add its task to the list.
tasks.add(deleteAsync(result));
}
// Return a new task that will be marked as completed when all of the deletes are
// finished.
return Task.whenAll(tasks);
}
}).onSuccess(new Continuation<Void, Void>() {
public Void then(Task<Void> ignored) throws Exception {
// Every comment was deleted.
return null;
}
});
The return Task.whenAll(tasks); returns a task that fires onSuccess only when all the tasks in the tasks arraylist has completed.
Not only does this rely on ParseĀ“ own background management, this example also makes all the tasks run in parallel, so is generally faster.
In your situation, you would simple need to create an ordinary method that:
Use the new built-in functions to return a task for both query1 and query2
Add those to an arraylist of tasks
return Task.whenAll(tasks)
Lets say this method is loadPicsInBg, then to use it:
loadPicsInBg().onSuccess(new Continuation<Void, Void>() {
public Void then(Task<Void> ignored) throws Exception {
// all the queries completed
return null;
}
});
I know this is a huge refactor and maybe you can do fine with the simpler callback approach, but Bolt indeed gives more power over the complex queries if used correctly. Furthermore it avoids the problem with nested queries creating a ever increasing indentation in the code making it difficult to read.
I've just switched to using CursorLoaders and I'm having trouble writing tests that utilize them. Since using the CursorLoader methodology takes the querying off of the main thread getInstrumentation().waitForIdleSync() is returning before the adapter is being updated (or at least this is my theory). I'm trying to avoid this is all my tests
public void testUpdateList() throws InvalidRecord, InterruptedException {
ListView listView = frag.getListView();
// Verify list is empty
assertEquals(0, listView.getCount());
// Add transaction directly into database
transTable.addOccurrences(resolver, TestUtils.createMockTrans());
//Don't want to do this but it works.
synchronized (this) {
wait(500);
assertEquals(1, listView.getCount());
}
}
So my question is, is there a better way to test this functionality within the Android testing framework?
The solution I settled on was using the waitForCondition method within Robotium. Here is an example.
...
// Waits for 500 milliseconds for the condition to be meet.
// If it isn't meet within this time limit the result is false.
boolean isSatisfied = solo.waitForCondition( new Condition() {
public boolean isSatisfied() {
return listView.getCount() == 1;
}, 500);
//Then I check if the condition has been meet.
assertTrue(isSatisfied);
...