I'm creating an android application and i want when user press back button show an quick animation and then finish current activity.
I'm using following code for do this:
public void onBackPressed() {
Thread t = new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
animate();
}
});
}
};
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.finish();
}
But it doesn't work.
Don't use join. Using join pauses the main thread until it is finished. But you can't redraw until the main thread returns to the Looper and processes invalidate events. So the entire thing won't work- your code is basically doing the same thing as if you hadn't run a thread at all.
Never wait on the UI thread- that means not only sleep but also join. Instead, when the animation is finished you call finish then, and just return after you call thread.start. But all of this is extremely overly complicated, for what you're doing just post a message to a Handler.
I'm creating an android application and i want when user press back button show an quick animation and then finish current activity.
Personally, I do not recommend this. Think of it this way: when you press the BACK button in a desktop Web browser, how angry would you be if the Web site decided to display an ad before taking you back to the preceding page?
But it doesn't work.
onBackPressed() is called on the main application thread. You then create and start() a background thread. You then immediately call join(), to block the main application thread until the background thread ends.
This has two problems:
The background thread is pointless, as you are blocking the main application thread until that background thread is done.
runOnUiThread() takes your Runnable and arranges to run it on the main application thread. That cannot happen immediately, because you are blocking the main application thread.
Your code has the same effect as this:
public void onBackPressed() {
runOnUiThread(new Runnable() {
#Override
public void run() {
animate();
}
});
this.finish();
}
As a result, animate() will not be called until after the activity has finished.
A typical solution is to attach a listener to the animation, to be invoked when the animation is complete. Then, the listener can call finish(). Another solution is to schedule a Runnable, using postDelayed() on some View, to be invoked after a certain amount of time, using a value that matches your expected animation run time. Then, the Runnable you pass to postDelayed() could call finish().
But, again, I do not recommend interfering with BACK button processing. I do not know what the user experience will be like on an Android 7.0+ multi-window environment (e.g., Chrome OS devices, Samsung DeX).
Related
I've got this piece of code:
public void updateOptionLists() {
Log.d("UI", "Called update");
if (updating){
return;
}
updating = true;
runOnUiThread(
new Runnable() {
#Override
public void run() {
updating = false;
updateOptionList();
scrollToLastTapped();
Log.d("UI","Updating");
}
});
Log.d("UI", "Posted update");
}
What I'd expect from logcat would be something like this:
Called update
Posted update
Updating
As far as I know runOnUi should be asynchronous, right? And considering that the functions called alter the views, which takes a while, this should be running asynchronous. Right?
So I look at my logcat:
Called update
Updating
Posted update
Why does this happen? And how do I make sure this runs asynchronous?
runOnUiThread will execute your code on the main thread, which (in this example) also appears to be where it's called from. This explains the ordering of the log statements you see - all code is executing on a single thread, so is synchronous per the documentation (my emphasis):
Runs the specified action on the UI thread. If the current thread is the UI thread, then the action is executed immediately. If the current thread is not the UI thread, the action is posted to the event queue of the UI thread.
runOnUiThread is typically used to execute code on the main thread from a different (i.e. background thread). The use of this separate background thread is what will make a task asynchronous. Calling back to the UI thread at the end of that task is required if you want to modify UI with the results of your background thread calculations.
Android provides several mechanisms for doing work on a background thread and then posting back to the main thread (not all use runOnUiThread explicitly for the latter operation). Good things to read up on include Thread, Handler, AsyncTask, Service, etc.
As far as I know runOnUi should be asynchronous, right?
runOnUiThread, as the name states, runs on UI thread, which is a main thread of an application. It runs synchronously with other code running within that thread and asynchronously with code in other threads.
The word 'asynchronous' has no meaning without a context: some code can run asynchronously with other parts of the code, which means these parts of the code run in different threads. Saying that something 'should be asynchronous' makes no sense without this kind of context.
is updateOptionLists running on the UI Thread?
If this is the case, i would expect this behavior to be ok.
In a normal case you use runOnUiThread from a background thread to come again to the Ui Thread..
Because you call upadetOptionLists() on ui prosess, upadetOptionLists() and runUiThread() both run in the same thread.
To separte theam you need run content in other new thread as following
public void updateOptionLists() {
new Thread(new Runnable() {
#Override
public void run() {
Log.d("UI", "Called update");
if (updating){
return;
}
updating = true;
runOnUiThread(
new Runnable() {
#Override
public void run() {
updating = false;
updateOptionList();
scrollToLastTapped();
Log.d("UI","Updating");
}
});
Log.d("UI", "Posted update");
}
}).start();
}
For accessing the view, you must be in the UI Thread (the main one). So, runOnUiThread will be executed on it.
You must do the long work in an other thread and only call runOnUiThread for little thing like changing a color or a text but not to calculating it.
From the documentation:
Runs the specified action on the UI thread. If the current thread is the UI thread, then the action is executed immediately. If the current thread is not the UI thread, the action is posted to the event queue of the UI thread.
http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)
Multi Threaded Programming: Theory vs Actual
Puppy Photos Explain is the Best pic.twitter.com/adFy17MTTI— Cian Ó Maidín (#Cianomaidin) 6. april 2015
But joke aside.
If you want to test how the threads work in correlation, try:
runOnUiThread(
new Runnable() {
#Override
public void run() {
updating = false;
updateOptionList();
scrollToLastTapped();
Thread.sleep(100);
Log.d("UI","Updating");
}
});
There are some links in my app. It will start browsable intent like this:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(link));
startActivity(intent);
Then it will open a browser. At the same time, something is running in background and need to update UI. So I get this:java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
I know the reason about this Exception. But how to fix it? It would be better that background task can keep running. However, pausing them is also acceptable.
If you are using AsyncTask you really dont need runOnUiThread() method. AsyncTask provides you with everything you need. It encapsulates two methods: preExecute() and postExecute() which run on the main thread, so you can update the UI components within these methods. Even if you need to update the UI progressively AsyncTask handles that in onProgressUpdate() method which again runs on main thread. This way your code is much cleaner then inserting:
getActivity().runOnUiThread(new Runnable() {
public void run() {
}
});
You can even cancel an ongoing task: asyncTask.cancel() for example onPause() method of your activity in order to avoid any unnecessary UI updates while the activity is not visible.
why would you want to do if the UI is not visible to user??
anyway,
for updating UI from background tasks try the runonUiThread
getActivity().runOnUiThread(new Runnable() {
public void run() {
//access UI here
}
});
http://android.okhelp.cz/java_android_code.php?s=runOnUiThread
In the callback used to update the UI, check if the activity is paused or stopped, and don't perform the UI update logic. You can use a flag isForeground which you set true in onResume() and false in onStop().
Alternatively, I found that you can avoid the exception if you use commitAllowingStateLoss when committing fragment transactions.
I'm new to android, I need to start a Thread Multiple times to do a regular work as the listen a thing. But I searched and found that can't do this. So I decided to put
while(true){
listen some thing
do another something depends for listen
}
in the run() method.
But How can I implements this idea? Is it possible ? and How?
You should use Handler.post() whenever you want to do operations in the UI thread.
So let's say in the callback (which is running in separate thread) you want to change a TextView's text, you should use Handler.post(). In Android, as in many other UI frameworks, UI elements (widgets) can be only modified from main thread.
mHandler = new Handler();
new Thread(new Runnable(
#Override
public void run () {
// Perform long-running task here
// (like audio buffering).
// you may want to update some progress
// bar every second, so use handler:
mHandler.post(new Runnable() {
#Override
public void run () {
// make operation on UI - on example
// on progress bar.
}
});
}
)).start();
Of course, if the task you want to perform is really long and there is a risk user might switch to some another app in the meantime, you should consider using Service.
If you start your thread inside a while loop with true condition, it'll kill your device. You'r device will hang. Your code should be event triggered. You can have a Service running in the background to do that and listen for your events.
I want stop main thread, while alertDialog is open, and wait user's choice for continue the program (depending on the button pressed buttons (positive or negative)). When trying to stop thread after. show (); dialog is not draw; if hang listener's onDestract onClose it works, but the code is horrible.
You can't stop "main" thread, since it's gui thread - your alertDialog will become irresponsive. You need to use callback to perform desired operations.
Why you need to stop main thread? Is this some game?
You must use many thread, and never block main thread. For example, thread for logic, thread for draw.
If you need to stop drawing, simple set your noDraw=true property:)
Like this:
SomeDrawer extends View {
#override
public void onDraw(...){
if(noDraw) return;
redrawMyGame(...);
}
}
I want to force android to wait AND continue processing something at the same time. I have seen the Thread wait function, but that just makes things hang for a while not actually letting the app do anything. Subsequent processes are simply queued up waiting their turn.
I want to force the timing of a process. This is kind of a combination between having a thread with a wait AND an asynctask
insight appreciated
public class yourActivity extends Activity{
final WebView yourWebview; //this is the webview
Context mContext = this;
public void onCreate(Bundle B){
setContentView(R.id.somethingtoshow);//this will be shown while webview working
Runnable yourRun = new Runnable(){
public void run(){
yourWebview = new WebView(mContext);
//do whatever you want with it
//loadUrl and whatever you want
//when your done
runOnUiThread(new Runnable(){
public void run(){
setContentView(yourWebView);
}
});
}
};
Thread T= new Thread(yourRun);
T.start();
}
}
'Waiting' means to put the thread in a suspended state - do you mean having the app simply do nothing until the process is completed?
You never want to make the main event thread hang or wait, that will make the user think the app is frozen. To do what you are wanting, you will probably spawn an async thread that loads the page from the main activity. The activity will continue to display whatever you had it doing last, and will not hang up or freeze while the async is going in the background. However, the user will still be able to press buttons, and might mess you up.
So to get the app to appear unfrozen and allow a process to occur in the background, you will want to enter into some loading screen or limit the user's options on the main layout. This will allow activity to continue occurring but allow the user a smooth experience.