Hi all I am a beginner in android programming and I am having a little trouble trying to understand how HandlerThread works. Specifically, I am not sure if the method in the custom view class is executed in the background thread (or non-UI thread) whenever I call the method in a runnable that is added to the thread's message queue.
I have a custom view and HandlerThread initialized in mainactivity:
HandlerThread mainHandlerThread = new HandlerThread("mainhandler");
mainHandlerThread.start();
Handler mainHandler = new Handler(mainHandlerThread.getLooper());
myCustomView mcv = (MyCustomView) findViewById(R.id.customView);
And in MyCustomView class (which extends view), i have a method called update():
public void update(int number, String txt) {
//perform some calculations
invalidate(); //redraw the view
}
Everytime MainActivity detects a change, it will use mainHandler.post() to call MyCustomView's update method:
mainHandler.post(new Runnable() {
#Override
public void run () {
mcv.update(123,"test")
}
});
Does the above code cause the custom view to be redrawn from the HandlerThread(which is a non-UI thread)? I was able to draw the view using both invalidate() and postInvalidate(), hence I am confused on whether the update() method is running on the UI-thread or on the HandlerThread I created.
Related
I was dealing recently with a question I'm not sure how to answer.
I wrote a code example for some AsyncTask that I want to perform. I read somewhere on the net that someone has implemented the AsyncTask and the Handler as inner classes and I wanted to scale that a little bit and make less coupling so I made separated class for those so I can reuse them with more than one Activity.
Because I had to do some different UI things on each Activity I decided to make those activities implement an interface so I can react to each event with same methods.
What I don't understand is why do I need the handler object that will handle the messaging for event occurrence? can't I just use the listeners observer pattern? and then the question that I asked my self and can't understand the answers around the web is what is the difference between my listener observer implementation and the handler object we get from Android.
Here is my code example:
Activity 1:
public class SomeActivity extends Activity implements MyListener{
MyAsyncTask myTask;
MyHandler handler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new MyHandler();
myTask = new MyAsyncTask(handler);
// initilize the activity views etc...
}
#Override
public void do1(){
// DO UI THINGS FOR ACTIVITY 1 IN A CALLBACK TO DO1 EVENT
}
#Override
public void do2(){
// DO UI THINGS FOR ACTIVITY 1 IN A CALLBACK TO DO2 EVENT
}
}
Activity 2:
public class OtherActivity extends Activity implements MyListener{
MyAsyncTask myTask;
MyHandler handler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new MyHandler();
myTask = new MyAsyncTask(handler);
// initilize the activity views etc...
}
#Override
public void do1(){
// DO UI THINGS FOR ACTIVITY 2 IN A CALLBACK TO DO1 EVENT
}
#Override
public void do2(){
// DO UI THINGS FOR ACTIVITY 2 IN A CALLBACK TO DO2 EVENT
}
}
Listener interface:
public interface MyListener{
void do1();
void do2();
}
AsyncTask implementation:
public class MyAsyncTask extends AsyncTask<Void,Void,String>{
private MyModel m;
public MyAsyncTask(Handler h){
m = new MyModel();
m.setHandler(h);
}
protected String doInBackground(Void... params) {
// do something in background with MyModel m
return null;
}
}
Handler implementation:
public class MyHandler extends Handler {
Vector<MyListener> listeners = new Vector<>();
#Override
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
// do something for case 1
fireMethod1();
break;
case 2:
// do something for case 2
fireMethod2();
break;
}
}
public void registerListener(MyListener l){
listeners.add(l);
}
public void unregisterListener(MyListener l){
listeners.remove(l);
}
private void fireMethod1(){
for(MyListener l : listeners){
l.do1();
}
}
private void fireMethod2(){
for(MyListener l : listeners){
l.do2();
}
}
}
Some demo model I created:
public class MyModel{
private Handel h;
public MyModel(){
// at some point send message 1 or message 2 ...
}
public void setHandler(Handler h){
this.h = h;
}
private void sendMessage1(){
h.obtainMessage(1, null);
}
private void sendMessage2(){
h.obtainMessage(2, null);
}
}
if it is too hard to read the code let me know, and if you don't want to read the code please help me to answer what is the difference between Handler and listening to events with the observer pattern? are they pretty much different solutions for same problem? thanks!
what is the difference between Handler and listening to events with the observer pattern?
The difference is that when you use a listener you call a method synchronously on the same thread. When you use a Handler you synchronously add a message to the MessageQueue but it is handled only after those messages that are already in the queue.
For example, if you are using a UI handler and you already called finish() on the activity and then added your message, it will be inserted after onStop() and onDestroy(). You can't achieve this with a listener.
The advantage of handlers is that you just add messages to queues and you don't care about threading. You can easily add a message to the UI handler from the background thread. If you use a listener from the background thread, it will be called on a background thread synchronously.
are they pretty much different solutions for same problem?
No, they are not. Handlers help you to decouple android components which is critical for Android, I think. If you use listeners you will be relying on strong references only which in some cases is not possible because you might leak a memory.
Handler is UI-threaded component. Usage of simple listener may cause CalledFromWrongThreadException if you want to touch some UI.
AsyncTask although have onPreExecute, onPostExecute and onProgressUpdate, which are just methods, which are running on UI thread. doInBackground runs on separate thread
Is there a way of calling a method inside a fragment once all UI elements are displayed? I am having trouble at the moment trying to figure out which method in the fragment lifecycle should I put my code in. Basically, I am waiting for some input on my socket by calling inStream.read(buffer) where inStream is an inputStream and buffer is a byte[] already initialised. My problem is that this call prevents the UI from being fully displayed whether I call it in onResume, onStart, onActivityCreated (it always waits until it has received something before the UI is fully displayed). Is there a specific fragment lifecycle method for this? (So the socket kinda works in the background just waiting for input instead of hogging the foreground, since the data received will be used to fill some textboxes in the UI of the fragment).
You are blocking the UI Main thread who is responsible for drawing UI components, open and read your Socket in a separeated Thread like AsyncTask
sockeqwe is spot on, you should perform that task in a separate thread so as not to block the UI thread.
To answer the question in the title in case anybody arrives here for that reason, a global layout listener can be used to get a callback when layout is complete. In onCreateView use any view in your layout:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// do whatever you need
// remove the layout listener if not needed anymore
removeOnGlobalLayoutListener(view, this);
}
});
Here's a static helper method to remove the layout listener
public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener victim) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
removeLayoutListenerJB(v, victim);
} else removeLayoutListener(v, victim);
}
#SuppressWarnings("deprecation")
private static void removeLayoutListenerJB(View v, ViewTreeObserver.OnGlobalLayoutListener victim) {
v.getViewTreeObserver().removeGlobalOnLayoutListener(victim);
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static void removeLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener victim) {
v.getViewTreeObserver().removeOnGlobalLayoutListener(victim);
}
I'm making a custom ImageView . One of the methods is to load an image from a URL. And I want to retrieve the Bitmap in a Thread and load the bitmap in the UI thread.
How can I make a runOnUIThread() call for painting the bitmap?
Is there some kind of built in function? Or should I create a Handler in the constructor and use it for running runnables in the UI thread?
Download the Image via AsyncTask and set to your view in its onPostExecute method
OR
From a separate image downloading thread use the post method of View which will always run its Runnable on UI-thread:
yourImageView.post(new Runnable() {
#Override
public void run() {
// set the downloaded image here
}
});
You can do something like this:
new Thread(new Runnable() {
public void run() {
final Bitmap bm = getBitmapFromURL(myStation.getStation().imageURL);
((Activity) context).runOnUiThread(new Runnable() {
public void run() {
icon.setImageBitmap(bm);
}
});
}
}).start();
This will work outside of an activity, like in a ListAdapter.
Create a class that extends from AsyncTask. Pass the ImageView in the constructor. In the doInBackground method, download the image. In the postExecute method, set the image to the ImageView.
I have a long running method that is called during onCreate, this method populates textviews so interacts with the UI, and updates maybe 70 labels (about 3-20 seconds depending on device).
I want to display a progressdialog as this method executes.
Ideally I want to fire my method on the UI thread once the Activity has been displayed and the progress is displayed, this I cannot do, the Activity won't paint until the method has finished.
I hoped to find an event which was fired after the activity was displayed, and I found the one below, but it still leaves the screen black until the method has finished.
#Override
public void onPostCreate(Bundle savedInstanceState)
I am normally a WP7 developer, and in .NET you add an event handler for onLoadComplete which is fired after the ui is displayed, but before the user has a chance to interact withthe UI, how do I do this in Android JAVA?
Thanks
Put a ProgressBar in the View.
Then in the onCreate() or onResume() method do this:
new Thread() {
public void run() {
yourLargeMethod();
}
}.start();
Now you can do this inside your method to update the progressBar
public void yourLargeMethod() {
// doSomething
...
runOnUiThread(new Runnable() {
public void run() {
// update the progress from the thread
progressBar.setProgress(x); // x is your progress, 0 <= x <= progressBar.getMax()
}
});
}
I'm having trouble getting the GPS's onLocationChanged to run on a different thread. I understand how to manage UI thread when I'm calling a function but with the GPS, I don't actively call the function.
My intent is to have a light flash every time the GPS receives a reading. I have put this function in a Runnable. I passed this function to a class that implements LocationListener. Then in the main class, I started a new thread that calls requestLocationUpdates. I was hoping that onLocationChanged of the LocationListener would run in a different thread, post to the callback and make the necessary UI effects in the UI thread. Unfortunately, the program crashes every time it tries to call requestLocationUpdates. What's the proper way of doing it?
Right now it looks something like this
Main class:
final Runnable changeLight = new Runnable(){
public void run(){
// do stuff
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.capture);
status = (ImageView) findViewById(R.id.status);
database = new DatabaseManager(this);
new Thread(){
public void run(){
location = (LocationManager) getSystemService(LOCATION_SERVICE);
listener = new GPSManager(database, changeLight, light, status);
location.requestLocationUpdates("gps", 10000L, 0, listener);
}
}.start();
}
LocationListener class:
public void onLocationChanged(Location location) {
if (location.getAccuracy() <= 32.0){
light = lightColors.Green;
status.post(callback);
database.insertData(location);
}
else{
light = lightColors.Yellow;
status.post(callback);
}
}
The exception says Can't create handler inside thread that has not called Looper.prepare()
The thread where you call location.requestLocationUpdates must have a Looper ( see here ).
You can use HandlerThread instead of Thread.
I was running in to the same problem. The solution turns out to be that the new thread where you want to receive Location updates from the Location Manager has to be a Looper thread. To do so, all you should do is add following lines in the run() function of your thread.
Looper.prepare();
Looper.loop();
Could your problems be arising from improper synchronization of the main thread? Do you get any exceptions before the app crashes? Can you post an sscce.org compliant example?
In general when you're processing asynchronous events on the GUI you should have proper synchronization: http://developer.android.com/resources/articles/painless-threading.html