I am now working on an android app in which I need to display a text after some processing is done.
I'm using a Thread to run a process in the back while my progress dialog is being displayed to the user. The Thread works properly and I've followed it step by step and, apparently, it also ends fine; however, the method in which I call it does not seem to come to an end (at least, during a normal cycle) because the text I am setting afterward does display immediately, I have to wait and do some other action (like in order for it to display
Below is the piece of code I'm having trouble with:
private OnClickListener saldoDisp = new OnClickListener(){
public void onClick(View v){
int x = s2.getSelectedItemPosition();
branchSel = arrSucsId[x];
mainProc();
saldoAdminTex.setText(strSaldo); //The late one
}
};
public void mainProc(){
chekP = new Thread (null,doProc,"Background");
chekP.start();
mProgress =ProgressDialog.show(SivetaAsaldo.this, "","Obteniendo saldo...",true, false);
}
private Runnable doProc = new Runnable(){
public void run(){
if(getSaldoAdmin(levelSel,branchSel))
{
mProgress.dismis();
Log.i(TAG,"Task completed properly");
}else
handler.post(tosti);
}
};
So I do get the "Task completed properly" but seems like it still waits for something else, any clues guys?
Thanks for taking a bit of your time to check it out =).
saldoAdminTex.setText(strSaldo); //The late one
is going to get called immediately. It doesn't wait until after the Thread started in mainProc ends. You also cannot dismiss the Progress Dialog in your runnable. You can only do UI related things on the main UI thread.
It would help you to read the article on Painless Threading on the Android Dev site.
About your ProgressDialog, please see this answer about how to use a AsyncTask with a ProgressDialog.
Looking at your code, this:
saldoAdminTex.setText(strSaldo);
would potentially be executed before your thread finishes as the thread will be running in parallel to that line.
An alternative way would be to do this:
public void mainProc(){
mProgress =ProgressDialog.show(SivetaAsaldo.this, "","Obteniendo saldo...",true,false);
handler.post(new Runable(){
public void run(){
if(getSaldoAdmin(levelSel,branchSel))
{
mProgress.dismis();
saldoAdminTex.setText(strSaldo);
Log.i(TAG,"Task completed properly");
}else
handler.post(tosti);
}
});
}
Related
I've been writing android apps for some months now, and I'm at the point where I'm building an actual needed app.
As I want that to work nice and fast, I made a Workerthread to do all kinds of tasks in the background while the UI can...build up and work and stuff.
It's based on the Android Studio Drawer app blueprint.
In Main.onCreate I got my operator=new Operator(), which extends Thread.
Now, when loading a new Fragment, it sometimes calls MainActivity.operator.someMethod() (I made operator static so I can use it from anywhere), and after some time I realized, the only tasks actually running in background are those in the operators run() method and an Asynctask my login Fragment runs. Everything else the UI waits for to complete and therefore gets executed by the UI thread.
So I thought: no problem! My operator gets a handler which is built in run(), and I change those tasks:
public void run() {
Looper.prepare(); //Android crashed and said I had to call this
OpHandler = new Handler();
LoadLoginData();
[...Load up some Arrays with hardcoded stuff and compute for later use...]
}
public void LoadLoginData() {
OpHandler.post(LoadLoginDataRunnable);
}
private Runnable LoadLoginDataRunnable = new Runnable() {
#Override
public void run() {
if(sharedPreferences==null)
sharedPreferences= PreferenceManager.getDefaultSharedPreferences(context);
sessionID=sharedPreferences.getString("sessionID", null);
if(sessionID!=null) {
postenID = sharedPreferences.getString("postenID", PID_STANDARD);
postenName = sharedPreferences.getString("postenName", PID_STANDARD);
context.QuickToast(sessionID, postenName, postenID);
}
}
};
context is my MainActivity, I gave the operator a reference so I could send Toasts for Debugging.
But now, the Runnables seem to not run or complete, any Log.e or Log.d stuff doesn't arrive in the console.
After some googeling and stackoverflowing, everyone is just always explaining what the difference is between Handlers, Asynctask, and Threads. And the multitask examples always only show something like new Thread(new Runnable{run(task1)}).start times 3 with different tasks.
And so became my big question:
How to correctly, over a longer time (~lifecycle of the MainActivity), with different tasks, use a background thread?
Edit: to clarify, I would also like a direct solution to my special problem.
Edit 2: after reading nikis comment (thank you), the simple answer seems to be "use HandlerThread instead of thread". Will try that as soon as I get home.
Trying a HandlerThread now. It seems my OpHandler, initialized in run(), gets destroyed or something after run() has finished, not sure whats up here (this is btw another mystery of the kind I hoped would get answered here). I get a NullpointerException as soon as I try to use it after run() has finished.
Make your worker thread own a queue of tasks. In the run() method, just pop a task from the queue and execute it. If the queue is empty, wait for it to fill.
class Operator extends Thread
{
private Deque<Runnable> tasks;
private boolean hasToStop=false;
void run()
{
boolean stop=false;
while(!stop)
{
sychronized(this)
{
stop=hasToStop;
}
Runnable task=null;
synchronized(tasks)
{
if(!tasks.isEmpty())
task=tasks.poll();
}
if(task!=null)
task.run();
}
}
void addTask(Runnable task)
{
synchronized(tasks)
{
tasks.add(task);
}
}
public synchronized void stop()
{
hasToStop=true;
}
}
In android why should we use a asyntask and service, instead of using a new thread() and write the necessary background functionality?
I know that we should not run long running operations like downloading a file from server on the mainthread aka UI thread. And should use a asynctask or service.
But why cant we create a new thread() {which is eventually a new thread other than the main thread} and write necessarily long running operation in that thread.
why did google create the AsyncTask and Service without suggesting to use the regular New Thread()???
thanks in advance
edit1:
may be i wasn't clear in my question or not sure, if i am, even now. help me out.
i get it, the whole point starts from
Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread
why ?
1.how much can the UI thread handle ? how can we determine a breakpoint? how is a ANR point determined? can we track?
2. when a service component handles long running operations why can't a activity component handle?
Remember that if you do use a service, it still runs in your application's main thread by default, so you should still create a new thread within the service if it performs intensive or blocking operations
http://developer.android.com/guide/components/services.html
the above statement is from android documentation.
3.why cant a service start in a new thread straight away, if we are so concerned about main thread? don't get me wrong in question 3, i am trying to understand the advantage of starting the service in main thread. by default.
in the above statement , does it suggest the main thread's ability to start and handle a service's long running operation load? if so does it contradict with question 1.
Well let's look how you'd perform a simple task using a Thread.
The first step is to create a Thread using a Runnable. Something like this:
private void fetchResultsAsync() {
Runnable runner = new Runnable() {
#Override
public void run() {
List<String> results = fetchResultsFromWebServer();
}
};
new Thread(runner).run();
}
The thing is, we need to show the results so it would actually be more like this:
private void fetchResultsAsync() {
Runnable runner = new Runnable() {
#Override
public void run() {
List<String> results = fetchResultsFromWebServer();
workFinished(results);
}
};
new Thread(runner).run();
}
private void workFinished(List<String> results) {
// show the results on the UI
}
It looks good, but there's a problem; the callback method (workFinished) has to update the UI. If we do this from any non-main thread, there will be big problems. We need a thread-safe way to call that method, which is what Handlers are for. Let's also throw in a method for updating our progress, which is very common. The code would now look like this:
private final Handler myHandler = new Handler();
private void fetchResultsAsync() {
Runnable runner = new Runnable() {
#Override
public void run() {
List<String> results = fetchResultsFromWebServer();
workFinished(results);
}
};
new Thread(runner).run();
}
private void showProgress(int result) {
myHandler.post(new Runnable() {
#Override
public void run() {
// update a progress bar here
}
});
}
private void workFinished(final List<String> results) {
myHandler.post(new Runnable() {
#Override
public void run() {
// show the results on the UI
}
});
}
Compare this to the implementation using an AsyncTask:
private void fetchWithTask() {
new AsyncTask<Void, Integer, List<String>>() {
#Override
protected List<String> doInBackground(Void... params) {
return fetchResultsFromWebServer();
}
#Override
protected void onPostExecute(List<String> strings) {
// show the results on the UI
}
#Override
protected void onProgressUpdate(Integer... values) {
// update a progress bar here
}
}.execute();
}
It doesn't differ much by lines of code, but it's much more obvious what needs to happen and where. It protects you from nasty mistakes like forgetting to wrap UI-touching code in a Runnable that has to be posted to a UI-Thread-owned Handler.
Now imagine that you have several different types of small background tasks that need to be performed. It would be very easy to call the wrong showProgress or workFinished method from the wrong background Thread because you have to plug all those pieces together yourself.
There's also a very nasty bug lurking in the use of Handler's default constructor. If the containing class is first referenced by a non-UI thread during runtime, the Handler would belong to that Thread. AsyncTask hides always does things on the correct Thread. This is hard to catch!
At first blush AsyncTasks don't seem all that useful, but the callback plumbing is where they really pay off in spades.
"instead of using a new thread() and write the necessary background functionality?"
Why rewrite the background functionality? AsyncTask does it for you. As njk2 mentioned a Service is not really a fair comparison, though IntentService automatically creates a new thread for you in onHandleIntent().
edit: To answer your other questions, blocking the UI thread, will block all user interaction and the app will appear to "freeze". Definitely not something we want to do at all.
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...:-)
I can't understand the implementation of a while loop in android.
Whenever I implement a while loop inside the onCreate() bundle, (code shown below)
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView=(TextView)findViewById(R.id.TextView);
while (testByte == 0)
updateAuto();
}
nothing boots up, and the program enters a "hanging" state after a while and I can't understand why. Testbyte is as follows:
byte testByte == 0;
and updateAuto() is supposed to update the code per 1 second and display inside the textView portion. I've been using setText inside updateAuto() as shown below and everything works fine, but once i implement the while loop all i see is a black screen and then an option to force close after a few seconds due to it "not responding".
TextView.setText(updateWords);
I've changed it to a button format (meaning i have to click on the button to update itself for now), but i want it to update itself instead of manually clicking it.
Am i implementing the while loop in a wrong way?
I've also tried calling the while loop in a seperate function but it still gives me the black screen of nothingness.
I've been reading something about a Handler service... what does it do? Can the Handler service update my TextView in a safer or memory efficient way?
Many thanks if anyone would give some pointers on what i should do on this.
Brace yourself. And try to follow closely, this will be invaluable as a dev.
While loops really should only be implemented in a separate Thread. A separate thread is like a second process running in your app. The reason why it force closed is because you ran the loop in the UI thread, making the UI unable to do anything except for going through that loop. You have to place that loop into the second Thread so the UI Thread can be free to run. When threading, you can't update the GUI unless you are in the UI Thread. Here is how it would be done in this case.
First, you create a Runnable, which will contain the code that loops in it's run method. In that Runnable, you will have to make a second Runnable that posts to the UI thread. For example:
TextView myTextView = (TextView) findViewById(R.id.myTextView); //grab your tv
Runnable myRunnable = new Runnable() {
#Override
public void run() {
while (testByte == 0) {
Thread.sleep(1000); // Waits for 1 second (1000 milliseconds)
String updateWords = updateAuto(); // make updateAuto() return a string
myTextView.post(new Runnable() {
#Override
public void run() {
myTextView.setText(updateWords);
});
}
}
};
Next just create your thread using the Runnable and start it.
Thread myThread = new Thread(myRunnable);
myThread.start();
You should now see your app looping with no force closes.
You can create a new Thread for a while loop.
This code will create a new thread to wait for a boolean value to change its state.
private volatile boolean isClickable = false;
new Thread() {
#Override
public void run() {
super.run();
while (!isClickable) {
// boolean is still false, thread is still running
}
// do your stuff here after the loop is finished
}
}.start();
onCreate(Bundle savedInstanceState){
// show dialog A if something is not correct
new Thread(){
public void run(){
if(something is wrong) {
runOnUIThread(new Runnable(){
public void run(){
showDialog(A);
}
});
}
}
}.start();
// show dialog B
showDialog(B);
}
I want to know
which dialog will be shown first, and is the order indeterminate? why?
if the order is indeterminate, how can i reproduce the case that A is shown before B?
Thanks!
Which dialog will be shown first is not defined and you should not rely on one occurring before the other as above. The thread scheduler is not identically deterministic in all situations.
You need to lock on a mutex (or any other locking device) to make sure one is shown before the other.
Your question about which dialog will show first is indeterminate. There are cases where the order will flip flop. But generally B would be shown first since 9/10 it will get to place it's event on the UI thread before your thread could detect there was a problem.
I'd suggest using AsyncTask to perform whatever mechanisms are needed to startup, then in the onPostExecute() allow your program to resume starting up so it can showDialog(B) for whatever it needs. That way if dialog A is showing you can stop the startup process there and not show b.
public class MyAsyncStartup extends AsyncTask<Integer,Integer,MyResult> {
MyActivity activity;
public MyResult handleBackground() {
if( somethingWentWrong ) return null;
}
public onPostExecute( MyResult result ) {
if( result == null ) {
showDialog(B);
} else {
activity.resumeStartupAndShowA();
}
}
}
I don't think it is possible that A is shown before B... this is because runOnUIThread adds the event TO THE END of the event queue. The code in that event (showing dialog A) is not going to get executed until after the onCreate() finishes (which means that dialog B gets shown first).
What cannot be guaranteed is the order between showing dialog B and calling runOnUIThread, but that doesn't matter. Here is a fragment from the official docs:
[runOnUIThread] 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.
N/A
You can't show B until you know whether or not A will be shown. So you have to wait for the worker thread no matter what. Would it be possible to put showDialog(B) in your other thread like this?
onCreate(Bundle savedInstanceState){
// show dialog A if something is not correct
new Thread(){
public void run(){
runOnUiThread(new Runnable(){
public void run(){
if(something is wrong) {
showDialog(A);
}
showDialog(B);
}
});
}
}
}.start();
}