Updating UI from broadcastreceiver - android

I'm using the bump android sdk. I have a broadcast receiver and i would like to update some elements from my ui depending on different intent filters. for example
else if (action.equals(BumpAPIIntents.NOT_MATCHED)) {
Log.i("Bump Test", "Not matched.");
BumpTest inst = BumpTest.instance();
if(inst != null) {
inst.UpdateMyText("testing");
}
Problem is even though in logcat i can see the log entry the textview update method doesnt seem to be called
Am I doing something wrong?

You aren't allowed to update the UI from other threads (like the one that calls the BroadcastReceiver). You'll have to use a simple AsyncTask class. It was created for the sole purpose of updating the UI after performing actions that will take a long time to complete. It's a good idea to put things like requesting resources from the internet in an AsyncTask because it doesn't block the UI thread from executing. The nice side effect is it calls a function in your main program when it's done, and this call is done on the UI thread.

Related

What constitutes "UI interactions" for AsyncTask?

AsyncTask is a standard way to perform long running operations asynchronously on a background thread without holding up the UI thread. One should not perform any UI interactions from the doInBackground() method.
My question: What are examples of UI interactions that are forbidden? Would it be any of the following:
LayoutInflater.inflate()
View.findViewById()
TextView.setText()
I'm inclined to say yes, but we have some code right now that does all of these (and more) and is called from the doInBackground() method, and yet the code is working. I've seen other people indicate they receive an exception when attempting to perform UI activity from doInBackground(), but that is not our experience.
Our code is generating an on-screen report that is not visible until the entire operation is complete. On rare occasion (hard to reproduce) when attempting to cancel the operation very quickly, we will see the application get into a weird state, but it doesn't crash.
Before changing our code in hopes of finding this rare condition, I wanted to see if anyone had some thoughts on why our code is "working" as-is.
The only other tidbit of information that might be helpful is that our doInBackground method has the following code template:
protected Boolean doInBackground(Void... voids) {
if (null == Looper.myLooper()) {
Looper.prepare();
}
publishProgress(0.0);
// Perform ui/non-ui logic here
Looper myLooper = Looper.myLooper();
if (null != myLooper && Looper.getMainLooper() != myLooper) {
myLooper.quit();
}
return true;
}
The Looper is needed for some of the report generating code (omitted) that uses a new Handler() to generate data. I'm not sure if creating the Looper is somehow making our ui interactions legal.
(I do have a stack trace that clearly shows our UI activity being called from doInBackground, in case you thought we might be spinning off some separate threads to update our UI)
AsyncTask is not meant for really long running work, it should complete within a few seconds. It is a one-shot completely managed thread context, which should not have its own Looper attached to it. That actually will break the backing AsyncTask functionality - starving off other future AsyncTask operations you may be starting. If you have something which requires a Looper, you should be using your own Thread or ThreadPool rather than an AsyncTask. You'll also want to make sure you retain a reference to your AsyncTask so it can be cancelled appropriately - this is a source of many memory leaks and/or exceptions due to invalid state when onPostExecute() is called.
The intent of the publishProgress() method is to give your app the ability to get updates it can reflect on the UX. You are correct, setText(), etc. should not be run in the doInBackground() callback. That callback is executed in arbitrary thread context in which you do not control and cannot make UI updates.
You may be able to use inflateLayout() and findViewById(), but this is not a good practice to do this outside of initialization as these are potentially expensive operations. Inflation has to parse the binary layout and create view objects on the fly. Finding by ID walks the entire view hierarchy to find the component you desire. A better practice would be to cache these at creation (for an Activity or Fragment) or when creating a view as part of an adapter (such as a ViewHolder in RecyclerView.

My Activity stops updating some Views that are updated via handler.post or runonuithread

My app consists of
1) An Activity
2) A service (forground)
3) A contentProvider... Writes to it inside the service, reads from it (cursor and observer) in the activity
The service maintains a Bluetooth connection to a device that is reporting data about once every second. The service then writes a tag/value pair to the content provider database.
The activity consists of some textviews, some buttons and some imageviews. It is also using the SpeedView dials package. However if I dont use the speedview the problem still happens.
The activity subscribes to the contentprovider for cursor loadercallbacks to init the screen and then uses a contentObserver to listen for changes.
Inside the contentObserver onChange(self,uri) {} .. it will see a change, request the value of the URI and then proceed to try to update the corresponding View.
OK so here is the problem. Because the callback is as if I think I understand "not" in the main looper, it cannot directly call some of the UI apis directly... For example trying to change the text of a TextView.
In the past this was not a biggie what I simply would do is create a handler and simply do something along these lines...
TextView mytextview...
Handler mHandler = null;
onCreate() { ... mytextview = findviewbyid(...)...
mHandler = new Handler();// No looper means main thread I think
}
onChange(self,uri) {
....
mHandler.post(new Runnable() {
#Override
run() {
mytextview.setText("the new text from the content provider");
}
});
.....
}
So what is the problem? Well at first nothing.. This works.. Well at least for several minutes. Not totally predictable sometimes quick sometimes after about 15 minutes .. But eventually the handler.post() wont work anymore. I placed a Log before the handler.post and a log inside the run() at the start and finish... I always see the log finish and the GUI update but then for some reason I wont see any logs except the one prior to the handler.post (meaning the content provider callback is still working!)
I am a bit at wits end as to why this will run for several minutes and simply stop. Its like some sort of internal looper queue is filling up.
My other attempts to use handeler.post(runnable)) to change a text view or other views didn't have these issues (at least maybe I didn't see them if the activity wasn't showing that long or for some other reason??!!
Well this isnt a true answer to the solution.. However what I discovered is that my updates from the Observer calling the handler.post was about at a rate of 50ms.
thats a bit fast though it still doesnt explain why no crashing or errors.
My workaround that seems to be working is instead of using an Observer update to call the handler.post that updates the UI is to do a crude POLLING of the observer class and poll at 100ms. Using a handler.postDelayed() and inside there doing the updates to the UI by checking the observer class for changes (polling) of each variable to see if any of them changed and if so then update the UI.

UI thread Handler not receiving messages prior to first Activity onCreate()

I have a Handler on the UI thread (created using new Handler(Looper.getMainLooper())) which has a sequence of messages sent to it as soon as the application starts (specifically, after the Application class' onCreate). What I have noticed is that this Handler doesn't seem to receive messages until around the time of the onCreate of the very first Activity. Prior to that point, messages sent to it appear to be lost.
Is this because the UI thread's Looper is not yet ready to execute messages until the first Activity is visible?
Supplementary information
I'm just adding this information in relation to comments below -- it's not part of the specific question.
This Handler is used as part of a mechanism that allows various long-running tasks to cause progress information to appear over the current Activity, using my own version of Eclipse's IProgressMonitor.
When the application starts, a piece of initialisation work is done. This work is a long-running task which involves building data structures based on contents of a file. This piece of initialisation work might have to be repeated later on during use of the application, depending on user operations.
In this application I have my own implementation of IProgressMonitor, an idea based on the class from the Eclipse Platform API. With this, various long-running tasks in the application, including the initialisation work, can grab simply grab an IProgressMonitor from a manager class, and call progress update methods on it (like done(), percentDone(), and so on). If any Activity is visible, this causes visible progress notifications to be visible (using the Crouton library).
The actual implementation behind the IProgressMonitor uses a Handler to transfer the done(), percentDone() etc. updates onto the UI thread. Then, the manager class gets the updates via the Handler and it causes visible status updates if an Activity is visible (and has registered with the manager).
What has brought me to the above question is that when the application starts and the initialisation happens for the first time, calls on the IProgressManager don't seem to find their way through to the manager via the UI-Thread Handler until the first Activity is visible. This doesn't matter whatsoever from a functionality point of view because without a visible Activity the manager can't display anything anyway. But I am just curious about the cause.
the messages are not "lost" as you said, they are delivered, just later. That's because even thou you have have several Handler object, the queue the messages are going to is just one, the Lopper queue. And when your activity is launch, the Android system already queue-up all the other stuff it has to do in order to show the activity to the user.
On a side note: If it's not used for any UI related stuff, DO NOT PUT IT ON THE UI THREAD! Makes sense right?
Some options, might vary depending on what they're doing exactly:
use lazy initialisation, meaning, only init those components first time the user actively needs them.
create a HandlerThread with low priority to perform those operations that are not UI related. Maybe even delay them for a couple of seconds to let the whole UI be built first, before executing any of them.
edit based on your extra information:
I do not advise on the approach you're taking in building this and the reason is: that's not what Handlers are for and the Android framework have its own implementations for long running tasks and how to communicate back with the currently active Activity
"This work is a long-running task" in Android, long running tasks, specially tasks that have nothing to do with the UI, should be delegate to a Service Probably you should look into a IntentService that automatically have a HandlerThread that executes long tasks in a background thread the order they are received and auto-destroy when there's nothing more to execute.
To get update information about on going tasks that are being executed on the service there're two possible approaches.
1 - more complex, but more complete approach, You bind the Activity to the Service and direct call methods on it like setListener. That involves some ServiceConnection callbacks, but also allows a close interaction between activity and Service.
2 - a simpler unidirectional approach is to have dispatch updates to the LocalBroadcastManager and make the activity listen to them, I'll show you a quick example below:
service code, for example to send a progress update on build data structure job
Intent i = new Intent(MY_APP_UPDATE);
i.putExtra("serviceType", BUILDING_DATA_STRUCTURE);
i.putExtra("updateType", ON_UPDATE);
i.putExtra("updateValue", progress_percent);
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
then on your activity you create a BroadcastReceiver inner class and onResume/onPause you listen for updates.
private BroadcastReceiver myReceiver = new BroadcastReceiver(){
#Override public void onReceive (Context context, Intent intent){
int serviceType = intent.getIntExtra("serviceType", 0);
int updateType = intent.getIntExtra("updateType", 0);
int updateValue = intent.getIntExtra("updateValue", 0);
// here you can properly handle the updates being sure that your activity isResumed
}
}
then onResume/onPause you register/unregister
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, new IntentFilter(MY_APP_UPDATE));
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
but all that is because I like to play inside the Framework rules and builtin features as they tend to be slightly more hassle free than re-inventing the wheel.

Implementing a cyclic executive in android?

I am writing an android app and I need to be able to do certain things periodically/continuously. I am coming from a C/C++ embedded firmware background and this new-fangled way of doing things is going to take some getting used to. It seems that there is no such thing as a "main loop" in Android, that everything is event-driven... I also understand that by default all code you write operates on the GUI thread, and I should probably make a new thread to execute the equivalent of a "main loop"...
So far what I have is an implementation of the AsyncTask class who's "doInBackground" method contains an infinite loop (my main loop), I create an instance of this class and run it immediately when my app starts. The problem I am having is in the interaction between this thread and the user interface... when something occurs in my main loop thread and I want to update the GUI understand that I must call "publishProgress", which is executed on the GUI thread. There are a few problems with this, primarily that many things I have tried to do in this "onProgressUpdate" method do not work, or do not occur in a predictable amount of time.
My question, is there a better way to accomplish what I am trying to do? In general, what do most people do when they have code that they want to run periodically and/or continuously while their application is running, code that must interact with the user interface in a timely manner (by timely I mean with zero delay).
Thank you.
public class MainLoopThread extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0)
{
while(true)
{
//Do stuff
//Update GUI
publishProgress();
}
}
protected void onProgressUpdate(Void...voids)
{
//Update GUI
}
}
It is unclear what you are trying to do, however just let me say using AsyncTask in this way may have negative consequences.
AsyncTask internally uses a thread pool pattern for running the stuff from doInBackground(). On Android OS before 1.6 and starting from 3.0 the pool size is just 1, meaning no parallel computations for a bunch of AsyncTasks. More details on this here.
So, this may result that only this current AsyncTask is running, while others even if started will have to wait untill the current one is done.
Depending on your needs for things to be done periodically Android exposes:
AlarmManager
Handler - it allows to post a runnable on UI thread with a delay or periodically
Timer + Activity.runOnUiThread(Runnable action) inside of TimerTask
UPDATE: basing on your comments it looks like you need a Service, that starts a thread that periodically sends broadcasts with the data for UI. Then your UI (Activity) registers broadcast receivers to catch those broadcasts, extract the data and use for UI updates.
So your saying that onProgessUpdate() isn't working? That seems weird because it should.
Another option that you have is just to make a Thread that loops.
The trick is that if you want to update the UI thread you will have to make a call to view.post() and give it a runnable that will actually perform the update. The idea here is that you must schedule an update on the UI thread, you can't just take it and say NOW!

Does posting a Runnable with a Handler make things asynchronous?

I am updating an activity's UI from a BroadcastReceiver that I register in the same activity. The API docs say:
[...] The function [onReceive()] is normally called within the main thread
of its process [...]
so I suppose updating the UI is okay.
The docs also say:
[...] you should never perform long-running operations in it (there is
a timeout of 10 seconds [...]
I am just setting some text on a TextView so I suppose that won't ever take longer than 10 seconds.
But, and here comes finally my actual question: Does it make any sense at all to add a Runnable to the main thread's message queue using a Handler, so that onReceive() can return immediately and the UI update happens at some later point in time, as the docs suggest:
There are two main uses for a Handler: (1) to schedule messages and
runnables to be executed as some point in the future; [...]
?
If you're just setting text on TextViews then you won't have issues. No need to over-complicate things with Handlers.
Though I will say that some people like using handlers just because it keeps things organized if multiple calls to a specific UI method need to be called. Using a handler will guarantee that that executed code will be initially placed on the UI thread, so it avoids having to check which thread you are running on.
The important thing to keep in mind is that all UI actions should be performed on the UI thread, and any sort of intensive processing should be done on a background thread.
Yes, using a Handler to schedule a Runnable is the standard.

Categories

Resources