In my application, I am using an AsyncTask to write some data to a database in a transaction. This database is also accessed from the UI thread. While looking through the available database methods, I came across yieldIfContendedSafely(). It seems like this method should be used for any cases where a transaction is being made from a separate thread. But there is hardly any documentation on this method other than the following:
Temporarily end the transaction to let other threads run. The transaction is assumed to be successful so far. Do not call setTransactionSuccessful before calling this. When this returns a new transaction will have been created but not marked as successful. This assumes that there are no nested transactions (beginTransaction has only been called once) and will throw an exception if that is not the case.
Here is how I would assume that you would use this method from a thread:
try {
db.beginTransaction();
//insert some stuff into the database here
...
// is this how you use this method?
boolean yielded = db.yieldIfContendedSafely();
if (yielded) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
db.setTransactionSuccessful();
} catch (SQLException e) {
return false;
} finally {
db.endTransaction();
db.close();
}
Is this the correct way to use this method? Is it alright to use db.yieldIfContendedSafely() more than once in the same transaction, in between multiple writes to different tables in the database? Any suggestions?
Pulling some example code from the Android libraries it seems much simpler to use than that...
This is taken from com.android.providers.calendar.SQLiteContentProvider.java
#Override
public int bulkInsert(Uri uri, ContentValues[] values) {
int numValues = values.length;
mDb = mOpenHelper.getWritableDatabase();
mDb.beginTransactionWithListener(this);
try {
for (int i = 0; i < numValues; i++) {
Uri result = insertInTransaction(uri, values[i]);
if (result != null) {
mNotifyChange = true;
}
mDb.yieldIfContendedSafely();
}
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
onEndTransaction();
return numValues;
}
Also looking into the source code for the function itself, it seems that, if yielded, the call will defer execution of your thread for a short period in any case.
Related
Is it possible that the android OS may delay or suspend my asynctask for some reason. If so what can I do to ensure that my task (e.g fetching data from database) is not delayed or suspend. Run it on a UI thread maybe but I have read that it is not a good idea as it can freeze the UI and cause lag.
Is it possible that the android OS may delay or suspend my asynctask for some reason.
It might be blocked by another instance of an AsyncTask. By default they run on a single background thread: https://developer.android.com/reference/android/os/AsyncTask.html
If so what can I do to ensure that my task (e.g fetching data from database) is not delayed or suspend.
Investigate what exactly causes the delay. Is it something inside doInBackground method or maybe delay happens before or after the background operation. It can be anything, hard to tell without debugging the code.
Run it on a UI thread maybe but I have read that it is not a good idea as it can freeze the UI and cause lag.
Although AsyncTask is not a good solution in this case, it should work fine if you implement it correctly. Other approaches to consider will be Loaders, or AsyncQueryHandler with ContentProvider. Depends on your use case.
#Override
protected void onPreExecute() {
holdWait = false;
stop = false;
}
#Override
protected Void doInBackground(Void... params) {
synchronized (this) {
while(true) {
if(Work) return null;
if(HaveWork) {
//make some
} else {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
return null;
}
public void mynotify() {
synchronized (this) {
if(holdWait) {
notify();
holdWait = false;
}
}
}
public void setStopWork() {
synchronized (this) {
stop= false;
if(holdWait) {
notify();
holdWait = false;
}
}
}
}
i got a really weird problem, it makes no sense at all. Im using an Async Task in Android to print some data on my UI. The doInBackground-Part looks like this:
#Override
protected Void doInBackground(Void... arg0) {
Double lastVal = 0.0;
while (!stopTask){
try{
popDataSemaphore.acquire();
if (data.size() > 0){
Double data = me.data.pop();
if (!data.equals(lastVal)) {
publishProgress(data);
lastVal = data;
}
}
popDataSemaphore.release();
}
catch (InterruptedException e){
e.printStackTrace();
}
}
return null;
}
In this task you can see the "me.data.pop()". Data is a modified LinkedList. The only modification is, that at a given size, it wont add any more values. It just ignores them. The LinkedList ist filled by another Async Task.
As you can see, im using a Semaphore. This is cuz before android 3.0, Async Tasks were executed on more than one thread.
Strange thing is, from time to time a "NoSuchElementException" is thrown at the Line "Double data = me.data.pop()". How is that possible?
In my modified LinkedList i only override the add-Method:
#Override
public boolean add(E o) {
if(limit == size())
return false;
super.add(o);
return true;
}
Thanks in advance.
EDIT:
Well, i didnt really solve the problem - i still dunno why this is happening - but i found another way. I just used an ArrayList and made the same modification as for the LinkedList. With the ArrayList, no exception occures. Must be something about the LinkedList. Well, thx for the help.
This question already has answers here:
How can I avoid concurrency problems when using SQLite on Android?
(10 answers)
Closed 9 years ago.
I'm confused a little bit when tried to establish a multithreading work with my SQLite db, so I have a service which periodically load a data from server and insert it in different db tables, also any user in any time can store his own data in db when pressed "save button" in app windows, so based on the rules that only one thread at time can write a data in db I'd'd like to make a thread-cooperation. At first I have created a singleton which have only one db instance, and all goes pretty good with my read-db methods, cause all threads can read data in the same time, but what about writing? I use a thread inside write-function, and don't give a start another until previous thread has finished it work.(also I do it for calls from ui thread when user press save button)
Question: All I want to do is consider two situations - first is when threads call's same function to write data then I used synchronized, second - when threads call different write functions I should use a lock, right? So now I came to decision, but is it correct and right to do like that?
Code (Updated):
// Sync method for processing 1st situation
public synchronized void addPoints(final ArrayList<Point> points, final OnDBOperationListener listener) {
if (listener != null) {
// Lock for others write-threads in 2nd situaton
synchronized (mWriteLock) {
while (mWriteWait) {
try {
mWriteLock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mWriteWait = true;
try {
SQLiteDatabase db = getDatabase();
// write a data
listener.onSuccess();
} catch (Exception e) {
e.printStackTrace();
listener.onError();
} finally {
closeDatabase();
synchronized (mWriteLock) {
mWriteWait = false;
mWriteLock.notifyAll();
}
}
}
}
}
After a long search i finally found a gret answer for my broblem, so anyone who want to creat e multithreading acess to db should read this first What are the best practices for SQLite on Android?
I am using the Drive API v2 for android, and when I execute the following method my app seems to pause or wait, and no data is returned.
public About getAbout() throws InterruptedException, ExecutionException {
FutureTask<About> future = new FutureTask<About>(new Callable<About>() {
public About call() throws IOException {
About about = null;
try {
about = _driveService.about().get().execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return about;
}
});
About about = future.get();
return about;
}
Does anyone have any idea what I'm doing wrong?
You are creating a FutureTask, but you are never executing it (not on the current thread and not on any other). Then you call future.get() which will block until the operation is completed. Since you never actually perform the operation, it will wait forever.
To execute an operation on a background thread you could for example use http://developer.android.com/reference/android/os/AsyncTask.html
I must use Thread in an Android project. Sometimes, it works corectly, however sometimes does not; it does not start (does not call SendToServer() method)or it starts but return to another function suddenly (return updated; line)before the thread does not finish.
Note: affected value is bigger than 0, it gives condition and it goes to if statement.
Here is the my code sample;
public static Boolean MyUpdateFunction(MyObject myobject){
Boolean updated=false;
//Code for updating local database
int affected= SqliteDb.update(....);
if(affected>0)
{
//Send updated data to server
//For this I must use Thread(I can't use AsyncThread)
updated=true;
SendToServer();
}
return updated;
}
public static void SendToServer()
{
try{
;
Thread th=new Thread(new Runnable() {
public void run() {
try {
//Create data and send it to server
//.......
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
th.start();
th.join();
}
catch(SQLException e)
{
Toast.makeText(myContext,"ERROR: "+e.getMessage(), Toast.LENGTH_LONG).show();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Other people are correct in that an AsyncTask is the way forward, but the direct problem due to what you're experiencing is this (and as such, I would recommend reading up on how Threading works):
When you start the thread, it begins a new process. The UI thread (which is generally where the majority of your code is) continues. So your code will fire the thread with SendToServer(), and then by definition will immediately return updated, as the UI thread immediately goes to the next line.
What you need is a callback from your Thread, which is handled in the onPostExecute() method of an AsyncTask. There's a good tutorial on how to use them and what they do here
Edit:
I've just seen from a comment above that you can't use Asynctasks, fair enough, but you still need a callback/event fired from your Thread to return any results
Instead of using threads and your variables (updated and affected), you can use AsyncTasks: see: http://developer.android.com/reference/android/os/AsyncTask.html
With AsyncTask, you have some methods which are doing exactly what you want:
onPreExecute
doInBackground
onPostExecute
So, what you can do is to check your condition in onPreExecute, then do your SendToServer in the doInBackground and onPostExecute do what you need.