I want to save all the messages received in the onMessageReceived of the service inside a SQLite db.
I was planning to open the db, insert the data and close the db. This would work well with an intent service as all the calls to the onMessageReceived would be queued and thus execute one by one.
However if the onMessageReceived gets called concurrently for multiple messages, it could cause issues of the Db being closed while another call is trying to write thus leading to issues.
Can anyone confirm what kind of behaviour i should expect.
If it is not an intent service, i might have to look at the DB singleton pattern and synchronization blocks
Currently, FirebaseMessagingService extends Service directly, so it is not an IntentService.
Source
Snapshot:
You can check LinkedBlockingDeque<> class which queues your requests and can be performed in background sequentially.
Check below sample class of mine -
public class Processor implements Runnable {
private final LinkedBlockingDeque<Task> mTaskQueue = new LinkedBlockingDeque<Task>();
private boolean mExecuteTask = true;
#Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// You can put some end condition if needed
while (mExecuteTask) {
Task task;
try {
// Waits if necessary until an element becomes available
task = (Task) mTaskQueue.take();
} catch (InterruptedException e) {
continue; // re-test the condition on the eclosing while
}
if (task != null) {
task.runnable.run();
}
}
}
// Call this method to put Runnable in Queue.
public synchronized void put(int id, Runnable runnable) {
try {
Task task = new Task();
task.runnable = runnable;
task.id = id; // someUniqueId to avoid duplication
// Check Id of tasks already present in Queue
mTaskQueue.addLast(task);
} catch (IllegalStateException ie) {
throw new Error(ie);
}
}
private static class Task {
public Runnable runnable;
// Unique Id of task
public int id;
}
}
Related
I have an App (Client) that performs remote calls using AIDL to a second App (Server). Each call to through the Binder is executed in the Server app in a different thread (TID) as designed by AIDL solution.
Is it possible to make all calls executed in the Server app be executed in just one thread? We have control over all callers (Client apps) and they will perform call in a serial mode and we don't need Server app perform the calls in a multithread way.
So, if the Client App 1 performs a remote call to a method that takes 30 seconds and before it, a second Client App 2 performs a call to the same method (or even other method) we want this second call be executed in the same Thread of the first call.
Messenger is not an option for now.
=== Updated ====
Message is not an option (for now). Here more details: We have a service with 2 type of binders: a) TransacionManager (tm) and DAOImpl (dao).
We first do a call to tm.begin() in the client and even its processed synchronously, on the Service side its is executed in a thread from Thread Pool (android aidl code). This thread TID #1 performs the begin transaction command in SQLite database.
Then we do a call to dao.selectNextId() - synchronously - and in the Service it is executed in the TID #2. In the selectNextId() method we check if the database is inTransaction and it returns false.
To confirm that the threads was the problem, we put everything in a single call to another binder (allDAO). So when we call allDAO.do() it runs on the Service side in another thread TID #3 and performs begin transc and insert very well.
Not sure if the problem is SQLite that manage different threads as separated requests (how to deal with)... We just want the Service (using aidl) perform every call from any clients in a same single thread everytime.
I was working with Mario on this issue and using the #pskink's code snippet we solved the multithreading issue.
The issue was solved redirecting all aidl calls to the main thread. To do this, we used a Handler thats receives the MainLooper and a Runnable that extends CountDownLatch.
The code of our solution bellow:
// SyncHandler.class
public class SyncHandler {
private SyncRunnable mRunnable;
public SyncHandler() {
super();
}
public SyncHandler start(#NonNull SyncRunnable runnable) {
mRunnable = runnable;
final Looper looper = Looper.getMainLooper();
Handler handler = new Handler(looper);
handler.post(mRunnable);
try {
mRunnable.await();
} catch (InterruptedException e) {
Log.e(this, "Error when SyncHandler was awaiting.", e);
}
return this;
}
public static class ReturnValue<T> {
public T value;
}
}
// SyncRunnable.class
public final class SyncRunnable extends CountDownLatch implements Runnable {
private Runnable mRunnable;
public static SyncRunnable create(Runnable runnable) {
return new SyncRunnable(runnable);
}
private SyncRunnable(Runnable runnable) {
super(1);
mRunnable = runnable;
}
#Override
public void run() {
Log.d(this, "SyncRunnable.run() executed on thread: " + Thread.currentThread());
mRunnable.run();
countDown();
}
}
//And the database call:
// TransactionManager.class
public synchronized void begin(final int ownerHashCode, String ownerName) throws RemoteException {
SyncHandler handler = new SyncHandler().start(SyncRunnable.create(new Runnable() {
#Override
public void run() {
if (mOwner == null) {
mOwner = ownerHashCode;
for (Database database : mDatabases) {
database.beginTransaction();
}
} else if (mOwner == ownerHashCode) {
throw new DbTransactionException("Error: TransactionOwner == owner");
}
}
}));
}
// DaoHelper.class
public synchronized long insert(Dao dao) {
final SyncHandler.ReturnValue<Long> value = new SyncHandler.ReturnValue<>();
SyncHandler handler = new SyncHandler().start(SyncRunnable.create(new Runnable() {
#Override
public void run() {
Log.d(DaoHelper.this, "db.inTransaction: " + mManagerDb.getDatabase().inTransaction());
value.value = mManagerDb.getDatabase().insert(mTable, null, mContentValues);
}
}));
return value.value;
}
I have an Android app from which I receive BLE data (every 62ms via notifications). The app can save data via a BufferedWriter to a file. Upon each onCharacteristicChanged() callback, I call either an AsyncTask, Thread or an IntentService to do a file write if the user enabled file save.
The AsyncTask seems to work fine. But the docs say execute must be invoked on the UI thread, and I'm calling it from the BLE callback. Is that a problem? And how should I fix it?
Using Thread causes this error: GKI_exception out of buffers https://code.google.com/p/android/issues/detail?id=65455 (except my code is not scanning but receiving notifications) and if the file save is long, I need to power cycle the Nexus 7 (the app and BLE become totally unresponsive). Why does the Thread not work and how can I fix it?
The IntentService never goes to the onHandleIntent(). What are the issues here?
Here is some code:
...
_context = this.getApplicationContext();
...
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
...
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
...
int mode = 1;
if (mode==0) // Asynctask
new doFileWriteTask().execute(strBuild.toString());
else if (mode==1) // Thread
{
final String str = strBuild.toString();
new Thread(new Runnable() {
public void run() {
try {
_writer.write(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
else if (mode==2) // intentService
{
Intent mServiceIntent = new Intent(_context, writeFileService.class);
mServiceIntent.putExtra("foo", strBuild.toString());
startService(mServiceIntent);
}
}
...
};
private class doFileWriteTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... strings) {
try {
_writer.write(strings[0]);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private class writeFileService extends IntentService {
public writeFileService() {
super("writeFileService");
}
#Override
protected void onHandleIntent(Intent workIntent) {
String dataString = workIntent.getStringExtra("foo");
try {
_writer.write(dataString);
} catch (Exception e) {
e.printStackTrace();
}
}
}
...
But the docs say execute must be invoked on the UI thread, and I'm calling it from the BLE callback. Is that a problem? And how should I fix it?
The framework triggers the AsyncTask callback methods on the same thread it was called from (presumed to be the main thread). It doesn't really affect the background work, but you could see problems if you started trying to use onPostExecute() and the like. AsyncTask probably isn't the best choice to be called from a thread that you don't have control over.
Why does the Thread not work and how can I fix it?
I can't say exactly why you are still seeing errors, through spawning a series of private unsynchronized threads will probably lead to other headaches. If you want to use a single worker thread, a better choice would be to use a single HandlerThread that you can post to from your event callbacks using a Handler, something like:
…
_workerThread = new HandlerThread("Worker");
_workerThread.start();
_handler = new Handler(_workerThread.getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
String str = (String) msg.obj;
_writer.write(str);
return true;
}
});
…
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
…
Message msg = Message.obtain(_handler, 0, strBuild.toString());
_handler.sendMessage(msg);
…
}
That solution is quite a bit more code, but given the frequency of writes this is probably the most efficient choice.
The IntentService never goes to the onHandleIntent(). What are the issues here?
You should pretty much never implement a top level Android component (activity, service, content provider, receiver) as an inner class, because they have to be declared in your manifest as well (and the XML syntax for inner classes is ugly). If your service does not have a matching entry in the manifest, then you will never see it start. You might want to have a look at the docs on using services.
At a minimum, a Service written as an inner class must be public static to work. Otherwise the framework cannot see it and cannot instantiate it using a default constructor (non-static inner classes mess with the constructor). Unless you are calling startService() inside of a try/catch right now, I'm surprised it isn't crashing when you attempt this.
IntentService is probably the simplest of your three choices because it is the most decoupled and the framework will handle queueing up work and tearing down the threads when all the incoming work is done.
Below you see some code that works fine - but only once. It is suppsed to block until the runOnUIThread is finished. And it does, when it runs the first time it is called. But when called the second time, it runs through to the end, then the runOnUIThread starts running. It could be, that after the methos was run the first time, the thread that caled it still has the lock, and when it calls the method the second time, it runs through. Is this right? And what can I do to fix that? Or is it a timing problem, the second time the caller gets the lock first?
static Integer syn = 0;
#Override
public String getTanFromUser(long accid, String prompt) {
// make parameters final
final long accid_int = accid;
final String prompt_int = prompt;
Runnable tanDialog = new Runnable() {
public void run() {
synchronized(syn) {
tanInputData = getTANWithExecutionStop(TransferFormActivity.this);
syn.notify() ;
}
}
};
synchronized(syn) {
runOnUiThread(tanDialog);
try {syn.wait();}
catch (InterruptedException e) {}
}
return tanInputData;
}
Background: The thread that calls this method is an asynctask inside a bound service that is doing transactions with a bank in the background. At unregular intervalls the bank send requests for user verification (captche, controll questions, requests for pin, etc.) and the service must display some dialogs vis a weak-referenced callback to the activities in the foreground. Since the service is doing several nested while-loops, it is easier to show the dialogs synchroniously than stopping an restarting the service (savind/restoring the state data would be too complex).
You could try if using a Callable inside a FutureTask instead of a Runnable works better. That combination is as far as I understand meant to provide return values from threads.
public String getTanFromUser(long accid, String prompt) {
// make parameters final
final long accid_int = accid;
final String prompt_int = prompt;
Callable<String> tanDialog = new Callable<String>() {
public String call() throws Exception {
return getTANWithExecutionStop(TransferFormActivity.this);
}
};
FutureTask<String> task = new FutureTask<String>(tanDialog);
runOnUiThread(task);
String result = null;
try {
result = task.get();
}
catch (InterruptedException e) { /* whatever */ }
catch (ExecutionException e) { /* whatever */ }
return result;
}
A Callable is like a Runnable but has a return value.
A FutureTask does the synchronization and waits for the result. Similar to your wait() / notify(). FutureTask also implements Runnable so it can be used for runOnUiThread.
I have created IntentService with infinite loop inside the onHandleIntent then add static methods start,resume,pause,stop to directly call it within my Activities.
The scenario is, inside the infinite loop, I am calling callback methods which is creating a new thread to execute long process.
The problem is, I am worrying about continuously creating Threads due to infinite loop. I am pretty sure that there is better way to manage it. I am thinking of ThreadPool or something enable to use only one thread in a sequential manner. So that, I am saving time,memory,overheads etc..
OTHER APPROACH ARE VERY WELCOME. Ask me other information as needed. Then, I will update here.
Here are my codes(take a look at SampleCallback):
IntentService
import android.app.IntentService;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class SampleCallbackIntentService extends IntentService {
private final String LOG_LOGCAT_TAG = "SampleCallbackIntentService";
private Handler _handler;
public SampleCallbackIntentService(String name) {
super(name);
}
#Override
public void onCreate() {
super.onCreate();
// initialize variables for pause & resume thread
_mPauseLock = new Object();
_mPaused = false;
_mFinished = false;
// initialize handler to switch to UI/Main thread
_handler = new Handler()
{
#Override
public void handleMessage(final Message msg)
{
_callback.doSomethingFromUIThread(msg);
}
};
}
private final SampleCallback _callback = new SampleCallback() {
#Override
public void doSomethingFromCurrentThread(final Object object) {
new Thread(new Runnable() {
#Override
public void run() {
//do long running process.
// I will access object here.
}
}).start();
}
#Override
public void doSomethingFromUIThread(final Message msg) {
//may update UI here.
}
};
private final int CALLBACK_MESSAGE = 1;
#Override
protected void onHandleIntent(Intent arg0) {
Log.i(LOG_LOGCAT_TAG, "loop started");
while (!_mFinished) {
// do stuff here
// create the object variable. Then pass to callback method
_callback.doSomethingFromCurrentThread(object);
// process and create the result to pass
String someResult = "some result here";
_handler.sendMessage(_handler.obtainMessage(CALLBACK_MESSAGE, someResult));
synchronized (_mPauseLock) {
while (_mPaused) {
try {
Log.i(LOG_LOGCAT_TAG, "loop paused");
_mPauseLock.wait();
Log.i(LOG_LOGCAT_TAG, "loop resumed");
} catch (InterruptedException e) {
Log.e(LOG_LOGCAT_TAG, "error occured on pause", e);
}
}
}
try {
//using sleep here might be not good design.
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(LOG_LOGCAT_TAG, "error occured on sleep", e);
}
}
Log.i(LOG_LOGCAT_TAG, "loop ended");
}
private static Object _mPauseLock;
private static boolean _mPaused;
private static boolean _mFinished;
public static void start(Context context) {
Intent service = new Intent(context, SampleCallbackIntentService .class);
if(context.startService(service)==null) {
Log.e(LOG_LOGCAT_TAG, "Service cannot be started");
} else {
Log.i(LOG_LOGCAT_TAG, "start() called");
}
}
/**
* Call this on pause.
*/
public static void pause() {
Log.i(LOG_LOGCAT_TAG, "pause() called");
synchronized (_mPauseLock) {
_mPaused = true;
}
}
/**
* Call this on resume.
*/
public static void resume() {
Log.i(LOG_LOGCAT_TAG, "resume() called");
synchronized (_mPauseLock) {
_mPaused = false;
_mPauseLock.notifyAll();
}
}
public static void stop() {
if(_mPauseLock == null) return;
synchronized (_mPauseLock) {
Log.i(LOG_LOGCAT_TAG, "stop() called");
_mFinished = true;
}
}
}
SampleCallback
import android.os.Message;
public interface SampleCallback {
public void doSomethingFromCurrentThread(final Object object);
public void doSomethingFromUIThread(final Message msg);
}
UPDATES1
I am using location api aside from google api. I will create a android library project and use that api to get the latest location (e.g. every 2secs) in the background.
On the application side, just need to call static methods to use it (e.g. start(context, callback), pause(), resume(), stop()). It has callbacks to obtain the location. After obtaining the needed information from the location object, I will create a new thread to call my own created callbacks (which implemented by the application side).
You can use AsyncTask instead of creating a new thread every time? AsyncTask manages a fixed pool of threads (or one background thread - depending on Android version) and allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
However I wonder why do you need to create an infinite loop inside the onHandleIntent method? By doing that you prevent your IntentService from receiving further Intents. Since in IntentService:
All requests are handled on a single worker thread -- they may take as
long as necessary (and will not block the application's main loop),
but only one request will be processed at a time.
I think you want to execute some long-running code out of the UI thread in the IntentService. But that doesn't require the creation of an infinite loop in the IntentService worker thread. Just send the requests as needed to the IntentService using Context.startService(Intent) call. If you want IntentService to send back some result or just call a callback in the UI thread you can pass a Messenger (or a ResultReceiver) object with the Intent.
Activity:
final Handler uiHandler = new Handler(Looper.getMainLooper());
private void postTask() {
Intent intent = new Intent("com.yourservice.DOACTION");
intent.putExtra("messenger", new Messenger(handler));
intent.putExtra("object", YourObject()); // pass other Parcelable objects
startService(intent);
}
IntentService:
protected void onHandleIntent(Intent intent) {
Messenger messenger = intent.getParcelableExtra("messenger");
YourObject object = intent.getParcelableExtra("object");
//... do work here ...
Message msg = Message.obtain();
msg.what = CALLBACK_MESSAGE;
msg.setData(someResult);
messenger.send(Message.obtain());
}
Look into the docs for ExecutorService (not to be confused with Android Services) and the Executors package. There are a few examples there on how to use thread pools.
So wait, why do you need to use all these callbacks? Can't you just have each intent encode what needs to be done and then have your onHandleIntent execute different code based on the information of the intent. This is the way IntentService is intended to be used.
You shouldn't be doing any of the thread handling in the IntentSerivce. The IntentService is supposed to be handling all the threading code (and you should let it because it's probably highly optimized).
Is it possible for a background thread to enqueue a message to the main UI thread's handler and block until that message has been serviced?
The context for this is that I would like my remote service to service each published operation off its main UI thread, instead of the threadpool thread from which it received the IPC request.
This should do what you need. It uses notify() and wait() with a known object to make this method synchronous in nature. Anything inside of run() will run on the UI thread and will return control to doSomething() once finished. This will of course put the calling thread to sleep.
public void doSomething(MyObject thing) {
String sync = "";
class DoInBackground implements Runnable {
MyObject thing;
String sync;
public DoInBackground(MyObject thing, String sync) {
this.thing = thing;
this.sync = sync;
}
#Override
public void run() {
synchronized (sync) {
methodToDoSomething(thing); //does in background
sync.notify(); // alerts previous thread to wake
}
}
}
DoInBackground down = new DoInBackground(thing, sync);
synchronized (sync) {
try {
Activity activity = getFromSomewhere();
activity.runOnUiThread(down);
sync.wait(); //Blocks until task is completed
} catch (InterruptedException e) {
Log.e("PlaylistControl", "Error in up vote", e);
}
}
}