Collapse and enlarge views using threads in android - android

What I wish to do is:
On a screen have lets say three layouts WHICH ARE INITIALLY MINIMIZED. And when I click on any one of them, the one that is clicked is enlarged and the remaining two collapse but are still visible. How can this be achieved using threads and the Animation class? Any ideas?

You have to use a Handler to modify the UI from a not UI thread.
Yo have to create a Handler in the activity:
Handler handler = new Handler();
Then, your thread has to be something like:
Thread th = new Thread(){
public void run(){
//your non UI interaction code
handler.post( new Runnable(){
public void run(){
//your UI interaction code
}
});
}
};
th.start();
Any way, I think it is more elegant to use an AsyncTask for this actions.
Regards.

Related

How to make an image change when clicking on a button

I am displaying image on when clicking on a Button using interface but the image ic_launcher.png does not show up on the Button after some time the image_all.png is only shown.
How should I show my first image for some time using sleep and then show image2?
Should I show both the images on the same button but with time delay.
Any help would be appreciated.
try{
button1.setBackgroundResource(R.drawable.ic_launcher);
Thread.sleep(1000);
} catch(Exception e){
}
button1.setBackgroundResource(R.drawable.images_all);
When you use Thread.sleep(1000); you're actually "stopping" the UI thread, because you're calling sleep(1000); on the UI thread. This causes your application to halt completely for 1 second in your case.
So this isn't such a good idea :-)
Instead you should use something like a Handler for instance. A Handler can be called with a specified delay, so that the action will first be performed after the specified delay. And most importantly, the Handler doesn't "block" the UI thread, as the Thread.sleep(1000); does.
So using a Handler your code, could look something like this instead:
button1.setBackgroundResource(R.drawable.ic_launcher);
Handler uiHandler = new Handler();
uiHandler.postDelayed(new Runnable() {
#Override
public void run() {
button1.setBackgroundResource(R.drawable.images_all);
}
}, 1000);
Notice the 1000 in the end of postDelayed() which tells the Handler to post this "message" after 1000 milliseconds instead of immediately.
On a side-note: It's not good practice to "eat" the Exceptions like you do in your try-catch.
You should be able to see the R.drawable.ic_launcher change occur. My thoughts about this are around how you're doing the Thread.sleep(). Android isn't fond of performing blocking tasks (such as Thread.sleep) in the UI Thread. When you call the setBackgroundResource and then sleep, the thread that would update the UI is sleeping and cannot perform the update. This is how I would do it instead:
button1.setBackgroundResource(R.drawable.ic_launcher);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
button1.setBackgroundResource(R.drawable.images_all);
}
}, 1000);

What exactly does the post method do?

I've encountered a very weird feature.
When I'm trying to run an animation on the main thread, it does not start.
When I run said animation using
getView().post(new Runnable() {
#Override
public void run() {
getView().startAnimation(a);
}
});
It does start.
I've printed the CurrentThread before starting the animation and both print main.
Obviously, I am missing something here, as both should start the animation on the main thread...
My guess is that as post adds the task to the queue, it starts at a more "correct time", but I would love to know what happens here at more depth.
EDIT:
Let me clear things up - my question is, why starting the animation on post causes it to start, when starting the animation on the main thread does not.
post :post causes the Runnable to be added to the message queue,
Runnable : Represents a command that can be executed. Often used to run code in a different Thread.
run () : Starts executing the active part of the class' code. This method is called when a thread is started that has been created with a class which implements Runnable.
getView().post(new Runnable() {
#Override
public void run() {
getView().startAnimation(a);
}
});
code : getView().startAnimation(a);
in your code,
post causes the Runnable (the code will be run a in different thread) to add the message queue.
So startAnimation will be fired in a new thread when it is fetched from the messageQueue
[EDIT 1]
Why do we use a new thread instead of UI thread (main thread)?
UI Thread :
When application is started, Ui Thread is created automatically
it is in charge of dispatching the events to the appropriate widgets
and this includes the drawing events.
It is also the thread you interact with Android widgets with
For instance, if you touch the a button on screen, the UI thread
dispatches the touch event to the widget which in turn sets its
pressed state and posts an invalidate request to the event queue. The
UI thread dequeues the request and notifies the widget to redraw
itself.
What happens if a user press a button which will do longOperation ?
((Button)findViewById(R.id.Button1)).setOnClickListener(
new OnClickListener() {
#Override
public void onClick(View v) {
final Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
});
The UI freezes. The program may even crash.
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
}).start();
}
It breaks the android rule that never update UI directly from worker thread
Android offers several ways to access the UI thread from other threads.
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Handler
Like below,
View.post(Runnable)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
}
}).start();
}
Handler
final Handler myHandler = new Handler(Looper.getMainLooper());
(new Thread(new Runnable() {
#Override
public void run() {
final Bitmap b = loadImageFromNetwork();
myHandler.post(new Runnable() {
#Override
public void run() {
mImageView.setImageBitmap(b);
}
});
}
})).start();
}
For more info
http://android-developers.blogspot.com/2009/05/painless-threading.html
http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/
Is this being done on onCreate or onCreateView? If so, the app might not be in a state where the View is attached to the window. A lot of algorithms based on View metrics may not work since things like the View's measurements and position may have not been calculated. Android animations typically require them to run through UI math
View.post actually queues the animation on the View's message loop, so once the view gets attached to the window, it executes the animation instead of having it execute manually.
You are actually running things on the UI thread, but at a different time
Have a look here for a good answer. view.post() is the same as handler.post() pretty much. It goes into the main thread queue and gets executed after the other pending tasks are finished. If you call activity.runOnUiThread() it will be called immediately on the UI thread.
The problem I think could be the life-cycle method where you are calling the post() method. Are you doing it in onCreate()? if so look at what I found in the activity's onResume() documentation:
onResume()
Added in API level 1 void onResume () Called after
onRestoreInstanceState(Bundle), onRestart(), or onPause(), for your
activity to start interacting with the user. This is a good place to
begin animations, open exclusive-access devices (such as the
camera), etc.
https://developer.android.com/reference/android/app/Activity.html#onResume()
So, as Joe Plante said, maybe the view is not ready to start animations at the moment you call post(), so try moving it to onResume().
PD: Actually if you do move the code to onResume() then I think you can remove the post() call since you are already in the ui-thread and the view should be ready to start animations.

Android: Rotating Button on a thread

Could someone provide a sample implementation for rotating a button on a thread ? As of now I am rotating my button on the UI thread using the following code:
Animation ranim = (Animation) AnimationUtils.loadAnimation(getBaseContext(),
R.anim.rotation);
buttonRotate.setAnimation(ranim);
following should work for you.
Thread thread = new Thread()
{
#Override
public void run() {
try {
Animation ranim = (Animation) AnimationUtils.loadAnimation(getBaseContext(),
R.anim.rotation);
buttonRotate.setAnimation(ranim);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
you might eventually have to create an AsyncTask which can run independently without disturbing UI Thread.
in your UI thread define
Handler mainHandler = new Handler();
then inside your thread, use this:
mainHandler.post(new Runnable()
{
public void run()
{
//your piece of code
}
});
This has served me well so far in several cases, hope it does for you too! :D
EDIT:
mainHandler.post(new Runnable()
{
public void run()
{
while(someBoolean==true)
{
//your piece of code
}
}
});
if you'd define 'someBoolean' inside your class, just like you did with the handler, the thread is supposed to get it, I believe.
this way, after processing your data, simply set someBoolean to false, and the rotating stops.
Unfortunately I don't have access to my IDE at the moment, so I am going to list the steps for you rather that put buggy code up here.
1) Implement "AnimationListener" in the same class that extends Activity.
2) Set a click listener on your button.
3) Create an AsyncTask class.
4) Override doInBackground (of AsyncTask) and place your resource intensive logic there.
5) In onAnimationStart (of AnimationListener), implement the logic to call your AsyncTask, i.e. new MyTask().execute();
6) Define the animation and set it to your button.
This is how it should go: You click the button, onAnimationStart is called, your AsyncTask logic and animation both start. This way you can have your button rotate at the same that that your background thread is performing resource intensive operations - i.e. concurrently.
And just for fun, you may want to disable your button from being clicked again before the background task has finished.
Sorry for the lack of code, but this should be pretty straight forward from here.

Show progress Dialog while the UI gets customized

I already have idea on how to use a Progress Dialog when background action is being performed. But my question is how do I show a progress Dialog when I am dynamically inflating a huge layout.
Since I can't inflate a view in another Thread, I am using the main UI thread. Due to this my progress dialog is not getting priority and it doesn't show up. My UI hangs for several seconds until it gets loaded fully. I tried several approcahes but none seems to work.
progress.show(context,"","inflating UI...");
setNewContent(R.layout.my_profile,R.id.my_profile_menu_button,R.id.my_profile_all_elements_layout);
populateProfileList(); //Dynamic nested layouts being inflated.
I am basically looking for dynamic layout changes based on user actions. So I dont have any other way other than creating dynamic views. Can anyone suggest me a helpful idea.
I had an similar problem with ui-thread. I wanted to add much views to my layout at runtime, I wanted to show a ProgressDialog to inform the user, that it could take a while. I had tried it with AsyncTask, but the only chance to do this, was to implement my ui-methods into the onPostExecute-Method of AsyncTask. But this just freezes the ProgressDialog, because ProgressDialog even works on ui-thread. I found a solution, maybe not the best, but it works. Before starting ui-action, I show a Toast. Then, I created a Thread with a handler and delayed the execution. After ui-action was done, I showed a new Toast. Delay the thread, gives the Toast enough time to get showed:
Toast.makeText(ActivityContext.this,
R.string.start_message,
Toast.LENGTH_SHORT).show();
final Handler uiHandler = new Handler();
final Thread uiThread = new Thread(new Runnable() {
#Override
public void run() {
uiHandler.postDelayed(new Runnable() {
#Override
public void run() {
yourUIAction();
Toast.makeText(
ActivityContext.this,
R.string.finish_message,
Toast.LENGTH_SHORT).show();
}
}, 100);
}
});
uiThread.start();
You need to use a handler to be able to talk to the UI thread
//in some thread
uiHandler.sendEmptyMessage(1);
...
Handler uiHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if(msg.what == 1) {
//do somestuff
}
}
};
Using Async Task is much better idea to me, when you have to do something in background, while progress dialog shows up on screen and then when background task completes, update UI... for reference please follow the link...
http://labs.makemachine.net/2010/05/android-asynctask-example/
hope this helps...:-)

Android wait() not working

This is my first question here, so please forgive me if I disobeyed any of the forum rules.
I need my program to wait for 3 seconds and then change the Content View
My code is:
setContentView(R.layout.logout);
new Thread(new Runnable() {
#Override
public void run(){
try {
synchronized(this){
wait(3000);
}
}
catch(InterruptedException ex){
}
}
}).start();
setContentView(R.layout.main);
The program works with no errors, but there is no waiting. When it gets to this part, it just shows the "main" layout without showing the "logout" layout at all.
What is wrong in my approach?
As people noted, don't sleep on or otherwise block the UI thread, but you seem to be aware of this with the new thread you create.
Now for why it doesn't behave as you want:
Right now, you call setContentView(), start a new thread, call setContentView() a second time on the UI thread -- this happens in quick succession with no delay/wait/sleep inbetween. The wait(3000) happens in the new thread you started -- so that new thread starts, waits for 3000ms, then exits. It's an expensive no-op.
You would need to make the second call to setContentView() from inside that new thread's run() method to get the desired effect. Also, you should use sleep() instead of wait() -- wait() is a low-level tool for synchronizing threads while sleep() is the usual "don't continue for X amount of time".
Let me propose a better way:
An arguably nicer and much lighter approch is using Handler.postDelayed() -- this allows you to invoke a Runnable on the UI thread after a delay:
setContentView(R.layout.logout);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
setContentView(R.layout.main);
}
}, 3000);
Edit to reply to your comment:
Define and find the button before the Runnable as a final variable, this way you can access it later from inside the Runnable.
Please note that to reference the this instance of the surrounding class from inside an anonymous inner class (your new Runnable()), you need to prefix it with the class name of the surrounding class (your Activity class):
final View submitButton = findViewById(R.id.submit_button);
setContentView(R.layout.logout);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
setContentView(R.layout.main);
// adapt to your actual Activity class name:
submitButton.setOnClickListener(YourClassName.this);
}
}, 3000);
wait() doesn't wait for a certain amount of time, but rather has the current Thread wait for this to do a notify() for a maximum amount of time. What you are looking for, is Thread.sleep().
And at the moment the only thing that will be waiting, is the additional thread you are spawning, not the activity itself. That's why I'd suggest you look at Handler.postDelayed(), CountDownTimer or AsyncTask. Handling threads is very low-level.
Your code not work to sleep UI thread.To sleep UI thread try this code
new Handler().postDelayed(new Runnable()
{
public void run()
{
setContentView(R.layout.main);
}
}, 3000);
Try using Sleep() instead of Wait()
android.os.SystemClock.sleep(3000)
As far as i can understand the wait is happening in the new thread where as you are calling setContentView(R.layout.main) in the current thread.
Try
setContentView(..)
synchronized(this) {
this.wait(1000);
}
setContentView(..)
Please note sleeping or waiting in the UI thread is not a best practice though.

Categories

Resources