Call Function in GattCallback from UI thread - java

My Situation :
I'm communicating with a sensor using BLE, sending 'Session' objects, as strings, from the sensor to the android device.
When all the sessions are on the android device, I call a session on the UI thread that uploads them to a server using Volley. (call 'uploadSessions()')
When all the sessions are on the server, (After I receive a Response from the server confirming they have been received), I need to erase the sensor's memory. (onResponse calls 'sessionsSuccessfullyUploaded()')
PROBLEM : I can't access functions in the GattCallback from the UI thread (cannot call 'eraseDevice()' from 'sessionsSuccessfullyUploaded()')
What I've tried: I've tried looping,
I do this in the callback :
public void waitForServerResponse() {
int WAIT_INTERVAL = 500;
new Handler().postDelayed(new Runnable() {
#Override
public void run () {
if(sessionCountUploadedToServer == IBSessionCount) {
eraseDevice();
} else waitForServerResponse();
}
},WAIT_INTERVAL);
}`
I get this error :
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

Look into Broadcast Intents and Receivers. This document can help:
http://www.techotopia.com/index.php/Android_Broadcast_Intents_and_Broadcast_Receivers
It would also help to put the callback in a special Bluetooth Service Class that extends Service

mHandler is created from non-UI thread. If you want to do any UI operations then make sure you create it on the main thread.
If you do not intend to do UI Operations then call Looper.Prepare() as the error suggests to you - in the thread which is constructing the handler.
Create the mHandler as below :
HandlerThread mHandlerThread = new HandlerThread("tHandlerThread");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
Alternatively you can also consider using AsyncTask or IntentService - these might be more suited for what you are trying to do - background operations.

Related

Why android room inserts an object at the end of the asynctask generating it (the object)?

Summary
Room immediately inserts entities generated through UI, but delays those sent by an asynctask until the (far) end of the generating asynctask : the entity objects received are usable and displayed on UI, but without any id from database, hampering any other operation relying on id.
The insert operation happens only when the generating asynctask is properly stopped: Why? And how to solve this?
More context
The generating asynctask
We use an asynctask to monitor a socket and send back some events (as Room entity) to the application repository (as intended by android architecture components). This asynctask basically runs continuously in background (with some sleep regularly set) and is only stopped a while before the end of use of the application (if done right). So far it hasn't caused any issue for us to deviate so much from the original concept of short-lived asynctask.
I am pretty much aware we could improve the design, but this is another subject/question/time-hole ;-).
Room insert operation
Insertion happens through a dedicated asynctask, where the returned id of the entry in database is affected back to the entity just inserted (see code below). This is logged and entities from UI are persisted "immediately", they get back their ID and all is well. The asynctask-generated entities, well they wait for their "parent" task to stop and are then all inserted.
Entity composition
At first, the entity was generated inside the asynctask and sent through progress message. Then the construction of the object was moved outside of the asynctask and at the same level of the UI event construction, yet same behavior.
These events are some longs (timestamps) and several strings.
From the generating asynctask all starts from here:
#Override
protected void onProgressUpdate(OnProgressObject... values) {
OnProgressObject onProgressObject = values[0];
if (onProgressObject instanceof OnProgressEvent) {
eventRecipient.sendAutoEvent(((OnProgressEvent) onProgressObject).autoEvent);
}
}
The eventRecipient is the EventsRepository:
public void sendAutoEvent(AutoEvent autoEvent) {
Log.d(LOG_TAG, "got an autoevent to treat...");
EventModel newEvent = EventModel.fromCub(
autoEvent.cubTimeStamp,
autoEvent.description,
autoEvent.eventType
);
addEvent(newEvent);
}
public void addEvent(EventModel event) {
new insertEventAsyncTask(event).execute(event);
// other operations using flawlessly the "event"...
}
private class insertEventAsyncTask extends AsyncTask<EventModel, Void, Long> {
private EventModel eventModel;
public insertEventAsyncTask(EventModel eventModel) {
this.eventModel = eventModel;
}
#Override
protected Long doInBackground(EventModel... eventModels) {
// inserting the event "only"
return eventDao.insert(eventModels[0]);
}
#Override
protected void onPostExecute(Long eventId) {
super.onPostExecute(eventId);
// inserting all the medias associated to this event
// only one media is expected this way though.
eventModel.id = eventId;
Log.d(LOG_TAG, "event inserted in DB, got id : " + eventId);
}
}
I am pretty much aware we could improve the design, but this is another subject/question/time-hole
Since I suspect that it is the cause of your current problem, perhaps you should not dismiss this.
My interpretation of your problem is: you have an outer AsyncTask (the one with the onPublishProgress() method shown in the first code listing). You are executing that with execute(). Inside of that outer AsyncTask you have an inner AsyncTask (the one from your repository). You are executing that with execute(). And, your complaint is that the inner AsyncTask does not run until the outer AsyncTask completes.
If so, your problem is that execute() is single-threaded, and you are tying up that thread by having an AsyncTask run indefinitely. Until your outer AsyncTask completes its background work and returns from doInBackground(), the inner AsyncTask is blocked.
The "can we keep using hacks?" solution is to continue using AsyncTask but switch to executeOnExecutor() instead of execute(), supplying a thread pool to use. AsyncTask.THREAD_POOL_EXECUTOR would be a candidate.
The "OK, can we clean this up a little bit?" solution is to replace both AsyncTask instances with either simple Thread objects or the direct use of some multi-thread thread pool (see Executors). AsyncTask is obsolete, but to the extent that it is useful, only use it when you need to do work on the main application thread (onPostExecute()) after completing the background work (doInBackground()). Neither of your AsyncTask implementations need to be doing work on the main application thread after the background work is complete, so you do not need an AsyncTask for either of them. So, for example, your run-forever thread could be a Thread, while you use a thread pool inside of your repository for your DAO calls.
(the "hey, can we get modern on our threading, to go along with our use of Architecture Components?" solution is to switch to RxJava or Kotlin coroutines, in conjunction with LiveData — this is much more work, but they each have their own merits over manual thread management)
Why ?
Basically, it was written in the AsyncTask documentation : all asynctasks are executed serially on a unique background thread.
My code, even without nested asynctask, was blocking this thread with an almost never-ending task, delaying all database operations until its completion (or app crash, hence some data loss).
A quick solution : moving an AsyncTask to a Thread
Other alternatives were nicely listed by (CommonsWare)[https://stackoverflow.com/a/56925864/9138818], here are the steps I followed that solved this issue.
The main difficulty was to redirect code that was executed on UI thread (onPreExecute, onProgressUpdate, onPostExecute) through a Handler associated to the main thread.
First step was get a reference to a handler :
// Inside Runnable task's constructor :
// get the handler of the main thread (UI), needed for sending back data.
this.uiHandler = new Handler(Looper.getMainLooper());
Then, the "doInBackground" is refactored to fit a Runnable main method signature :
// previously "public String doInBackground()"
// returned value handled through publishProgress.
#Override
public void run() {
// recommended by Android Thread documentation
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// code previously in doInBackground
Now, code in the onProgressUpdate (that was called by publishProgress inside doInBackground method) was moved into a Runnable posted on the UI thread handler :
// asynctask method onProgressUpdate was renamed publishProgress =>
// doInBackground's body is almost untouched.
private void publishProgress(final OnProgressObject... values) {
uiHandler.post(new Runnable() {
#Override
public void run() {
// move here code previously in the AsyncTask's publishProgress()
}
});
}
At last, I had to change the way the task was created, runned and stopped by using Thread.interrupted instead of isCancelled and by creating the Runnable task before the thread :
public void startCUBMonitoring() {
if (autoEventThread == null) {
Log.d(LOG_TAG, "startCUBMonitoring");
addUIEvent("CUB MONITORING STARTED", "CUB_connexion");
SessionRepository sessionRepository =
ElabsheetApplication.getInstance().getSessionRepository();
// Creation of the task
AutoEventTask autoEventTask = new AutoEventTask(
this,
sessionRepository,
sessionRepository.getCUBConfig()
);
autoEventThread = new Thread(autoEventTask);
autoEventThread.start();
}
}
public void stopCUBMonitoring() {
if (autoEventThread != null) {
Log.d(LOG_TAG, "stopCUBMonitoring");
addUIEvent("CUB MONITORING STOPPED", "CUB_connexion");
autoEventThread.interrupt();
autoEventThread = null;
}
}
Hoped it could help...

Handling the closing of App By Android

I have created an App which requires to run a operation in background for quite some time suppose 10 - 15 mins.
I am running this operation in An AsyncTask. So during this time the user is minimizing the Screen and using his other apps in his phone as usual.
When this operation is started I am creating a Progress Dialog box and then keep updating it regularly.
But this is the error which I am receiving sometimes very rarely once the operation is over
Fatal Exception: java.lang.IllegalArgumentException
View=DecorView#1234567[ABC:] not attached to window manager PackageName
And this is the detailed stack log
Fatal Exception: java.lang.IllegalArgumentException
View=DecorView#1234567[ABC:] not attached to window manager PackageName
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:508)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:417)
at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:136)
at android.app.Dialog.dismissDialog(Dialog.java:446)
at android.app.Dialog.dismiss(Dialog.java:429)
at android.app.Dialog.cancel(Dialog.java:1353)
at PACKAGENAME
at android.app.Activity.runOnUiThread(Activity.java:6078)
at PACKAGENAME
at PACKAGENAME
at android.os.AsyncTask.finish(AsyncTask.java:667)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:684)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6823)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1557)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
To my knowledge this error is because the Android OS wanted to release some memory hence my App was closed since this was not visible to the user. But is there any way to tackle this thing?
Any help would be really appreciated.
EDIT: This is the code which I am using
public class load extends AsyncTask<Void, Void, Void> {
#Override
public Void doInBackground(Void... voids) {
for(int i=0;i<number;i++){
PerformSomeOperation();
UpdateTheProgress();
}
return null;
}
#Override
protected void onPostExecute(Void n) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mProgressDialog.cancel();
CreateAnotherDialog();//This dialog is created to show the user completion of the progress.
}
});
}
You're having this crash because you're trying to update the UI when it's in the background so your Activity could be destroyed at that point. By the way, onPostExecute runs your code on the main thread already but as you're sending a separate message to the main looper you're postponing your logic a bit which can also cause a problem. Moreover, But the main question - why to update the UI if it's not visible to the user anyways?
Also, because you're using the AsyncTask as an inner class you may leak (though temporarily) your Activity object as it's referenced implicitly by the task.
From Android Documentation:
AsyncTasks should ideally be used for short operations (a few seconds
at the most.) If you need to keep threads running for long periods of
time, it is highly recommended you use the various APIs provided by
the java.util.concurrent package such as Executor, ThreadPoolExecutor
and FutureTask.
So, don't use AsyncTasks for long-running operations. A better approach would be to use:
IntentService together with BroadcastReceiver to communicate with your Activity / Fragment (in API >= 26 you should use JobIntentService as IntentService may misbehave due to new restrictions on background services).
RxAndroid (or just ExecutorService/Thread) together with Architecture-Components (more specifically with LiveData) - this way a result of your task can be cached or it can survive the config change.
My personal favourite is option 2.
There are few things to say: (1) the "onPostExecuted()" method is already executed on the UiThread/MainThread, so "runOnUiThread()" is not required. (2) if the Activity is minimized/destroyed when the Asynctask reach the final pass you get an Exception. So you have to check if the View is attached using "View. IsAttachedToWindow()" before execute some GUI methods like "mProgressDialog.cancel()". (3) you have to create a Thread or a Service to do a task that should run/work more than few seconds, or the System could kill it at anytime.

Multiple threads reading from same socket

I am developing an app which displays data from a server. The server is not mine and it is not very stable. Making too many connections crashes the server.
I have one socket to the server in my main activity, but at times I want to open sub activities which read the data and display it. My problem is that I am unable to achieve this with the same socket and have to open a new socket for every activity.
Every activity has a thread which does the reading from the socket and updates the UI elements on that activity as needed.
To use the same socket in multiple activities, I tried to close the inputReader of an activity before starting the new activity, but that simply make the application hang. If I leave it open, then the new thread in the new activity never receives any data. Killing the thread before starting the new activity is not possible because the thread is generally blocked by the read() function.
Is there anyway that I can have a centralized thread which does the reading and then sends the data to all the other threads in other activities so that I don't have to open new sockets in every activity?
I feel that this is a very basic thing that I am asking, but yet I am unable to find a solution.
A pretty straightforward and simple approach is the following:
You create a new Service which runs in the background and communicates with the server through your socket
The Service receives data from the socket and forwards/broadcasts it to all of your Activities which are interested in receiving it (for example to update the UI) by using the LocalBroadcastManager
All of your Activities implement a BroadcastReceiver and receive the data from your Service inside the onReceive() method
To accomplish that, you should read the introduction to Services and BroadcastReceivers to get an idea of how they work. Also to get a basic overview first, you should read about the available App Components.
EDIT, to answer the question in the comment:
You can always stop the Service by calling stopService() but you can also do it differently if you don't want/need all the functionality of a Service. Instead of a Service you could also create a simple Thread or a HandlerThread which communinicates with the server. From inside of your Thread, you can then forward/broadcast the data to your Activities by using the technique mentioned above (LocalBroadcastManager).
Just to give you an example of the basic structure (code untested though):
class SocketThread implements Runnable
{
static final String SOCKET_DATA_RECEIVED = "com.your.package.SOCKET_DATA_RECEIVED";
static final String SOCKET_DATA_IDENTIFIER = "com.your.package.SOCKET_DATA";
private Context context;
SocketThread(Context c) {
context = c.getApplicationContext();
}
#Override
public void run() { // code running in your thread
// fetch data from socket ...
Intent intent = new Intent();
intent.putExtra(SOCKET_DATA_IDENTIFIER, data); // store data in your intent
// send data to registered receivers
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
// your code ...
}
}
Then you have your Activities, for example MyActivity1, MyActivity2, ... MyActivityN. They all register their embedded SocketDataReceiver to receive the broadcast intent SOCKET_DATA_RECEIVED, which is sent by your thread.
Inside your onReceive() methods you can then extract the data from your intent object by using the identifier SOCKET_DATA_IDENTIFIER.
public class MyActivity1 extends Activity
{
private SocketDataReceiver socketDataReceiver;
#Override
protected void onResume() {
super.onResume();
socketDataReceiver = new SocketDataReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(
socketDataReceiver, new IntentFilter(SocketThread.SOCKET_DATA_RECEIVED));
}
#Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(socketDataReceiver);
}
private class SocketDataReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
// intent contains your socket data,
// get data from intent using SocketThread.SOCKET_DATA_IDENTIFIER
}
}
}
Basically you answered your question yourself:
I can have a centralized thread which does the reading and then sends the data to all the other threads in other activities.
Meaning: of course, such a thing is possible. But you have to sit down, design and implement it. You would start by defining a reasonable interface that allows your other threads to communicate with that central service, something like:
enum RequestType { DO_THIS, DO_THAT };
interface ServerConnectionService<T> {
List<T> performRequest(RequestType request);
}
Meaning: instead of having your different threads do "low level" talking on that socket, you create an abstraction that allows you to say: "when I need this kind of information, then I use my service; and it returns some specific answer to me). Of course, this is a very generic answer, but well, your question isn't exactly specific either.
The next step would then be to have some central (maybe singleton) implementation of that interface; which runs on its own thread, and can be used by other threads in a synchronized, well-defined way.
Final word of warning: if you don't own that server, and it has low quality and is causing trouble for you - that is not a good setup. Because no matter what you do in your code, if the server doesn't do a good job, users will perceive your app to be the problem. Users don't care if an operation fails because some remote server crashes. So the other aspect in your question is: right now, you are in a bad spot. You should spent some serious time to find ways out of there. Otherwise you will be wasting a lot of time to build workarounds for that server you are dealing with.

Wait for sensor data android - do we always need a new thread?

I have a simple Android app, which is supposed to get several readings from a sensor at a certain time interval.
I currently have two threads:
UI thread that initiates the sequence (via a message to a worker thread handler), and also keeps track of its state (whether I am doing the first measurement, or a repeated measurement).
A worker thread, which runs in a background and communicates with the main thread via main thread handler.
My intent is to keep all the logic about when to do the measurements within the main UI thread (those are simple number comparisons, and no time consuming work, so should be suitable for UI thread), and set up a worker thread as a thread that only knows how to respond to a request to read data from sensor and return the result of such reading.
My issue is in this worker thread. It receives a request to do a measurement via a message, and handles this request in its handleMessage method:
public boolean handleMessage(Message msg) {
if (msg.what == StartMeasurementCmd) {
Log.d(TAG, "Starting measurement");
// register sensor event listener
// wait for onSensorChanged
// unregister sensor event listener
Log.d(TAG, "Measurement finished");
// Notify UI thread via uiHandler
Message newMsg = uiHandler.obtainMessage();
newMsg.what = DoneMeasurementCmd;
// add whatever information is needed to the newMsg
newMsg.setTarget(uiHandler);
newMsg.sendToTarget();
}
return false;
}
Here StartMeasurementCmd and DoneMeasurementCmd are simple constants.
Once worker thread receives the request to measure data, it needs to register a sensor listener (first comment line above), but then it needs to wait until the reading is available (second comment line above). After reading is available, it will unregister the listener (third comment line above), and send a message to UI thread to notify that new data is available.
I can think of two ways to fill in the second comment line:
I can do reading in yet another thread (and then simply use wait() to synchronize this worker thread) - based on these two posts:
Android sensor registerListener in a separate thread
A method for waiting for sensor data
Alternatively, I can simply put a while loop after registering listener and check on a flag that I can trip in onSensorChanged method. Since the worker thread is running in background it should be ok to block it, but I don't like the fact that I am using a "busy" wait.
My question is - is there a way to get the reading within the same worker thread, but without doing a "busy" wait in while loop? Or is one of the above methods actually a recommended one?
Thanks!
If i understand correctly, it is OK to block the worker thread. Then you don't need a separate thread, it would suffice to make the listener object a monitor (i.e. with synchronized methods) and wait on that.
For instance, something along the lines of (with the handling of the actual data roughly sketched):
class ListenerMonitor implements WhateverListenerInterface {
private boolean gotData;
... some variable(s) to record the actual data
public synchronized void onSensorChanged(...) {
...
gotData=true;
notifyAll();
}
public synchronized SuitableReturnType readSensor(...) throws InterruptedException {
// register sensor event listener
gotData = false;
while(!gotData) wait();
// unregister sensor event listener
return the data?
}
}
and use it in the worker thread:
...
ListenerMonitor listenerMonitor = new ListenerMonitor(...);
...
public boolean handleMessage(Message msg) {
if (msg.what == StartMeasurementCmd) {
Log.d(TAG, "Starting measurement");
... = listenerMonitor.readSensor(...);
Log.d(TAG, "Measurement finished");

Android Main Thread Looper concern

I'm writing a library, which does some intensive network work. So, I'm using a HandlerThread to carry out this operation like this:
Looper.prepare();
libraryThread = new LibraryHandlerThread(context);
libraryThread.start();
libraryThread.getLooper();
LibraryHandlerThread does the network operations and other time consuming operations.
When I call this code from a worker thread (any thread other than Main thread), it works fine. But complains about "can't initialize another looper when one is already active". I believe that a Looper runs on Main thread by default, and complains about Looper.prepare(). I can do something like following to make it working from Main thread:
Looper.getMainLooper().quit();
Looper.prepare();
libraryThread = new LibraryHandlerThread(context);
libraryThread.start();
libraryThread.getLooper();
My question is: what would be the impact on Main thread. In my ideal world, I want to run my library's operations on a separate thread without impacting the main thread. How can I achieve this without much destruction?
Try the below code:
private static final HandlerThread sWorkerThread = new HandlerThread("network-operations");
static {
sWorkerThread.start();
}
private static final Handler sWorker = new Handler(sWorkerThread.getLooper());
What you will want to look into is using a Asynctask to run this in the background which will allow your main thread to keep working http://developer.android.com/reference/android/os/AsyncTask.html
Or you can create a service if this is something that you will need constantly running. http://developer.android.com/reference/android/app/Service.html

Categories