I have an activity class as below.
public class LoginActivity extends Activity implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button1 = (ImageView) findViewById(R.id.button1);
button1.setOnClickListener(this);
}
#Override
public void onClick(View v) {
loader = (ProgressBar) findViewById(R.id.loader);
Thread processThread = new Thread(loaderThread);
loader.setVisibility(View.VISIBLE);
processThread.start();
try {
Thread.currentThread().join();
Log.i("Activity","gone past join()");
loader.setVisibility(View.INVISIBLE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private Runnable loaderThread = new Runnable() {
public void run() {
ServiceCaller serviceCaller = new ServiceCaller();
boolean status = serviceCaller.checkProcess(url);
}
};
}
Further Question [EDITED]
Here is the scenario. The main activity class creates a thread on a click. The then created thread fetches some data from the server. It is a time consuming task. So a progress bar is displayed on the UI. Currently I am using AsyncTask (not shown here) to accomplish server data retrieval. But the real challenge is wait for the background task to complete and get the value from it. What I am looking for is:
wait until server calls are made and get the results. Meanwhile show the progress bar.
Any thoughts? Apologies in case I confuse you.
Thanks in advance!
You must have a look at AsyncTask
http://developer.android.com/reference/android/os/AsyncTask.html
http://www.vogella.com/articles/AndroidPerformance/article.html
and you can show the ProgressBar in onPreExecute()
do the task in doInBackground()
and hide the ProgressBar in onPostExecute()
Join method blocks the current thread. In your case Onclick method is called in UI thread, so all UI operations are blocked. It is never a good idea to block Ui thread.
So you probably should use either a Handler or Asynctask to keep updating Progressbar
Related
I have a layout with a TextView say mainTextView.
My activity file looks something like :
public class SecondActivity extends AppCompatActivity {
private static Integer i = 0;
private TextView tv = null;
#override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
tv = (TextView) findViewById(R.id.mainTextView);
new MyThread().execute();
}
private void notifyAChange () {
tv.setText(i.toString());
}
private class MyThread extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground (String... params) {
while (true) {
try {
i++;
Thread.sleep(1000);
notifyAChange();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
This returns a FATAL EXCEPTION on runtime. I know I can't touch a view from another Thread except the original one but in that case I am touching the view from the main thread so what is wrong ?
Nope you are in the doInBackground part of the AsyncTask (worker thread).
You are calling notifyAChange() form worker thread, not main UI thread.
You should update the UI from onPostExecute. Or you can also use runOnUiThread for the part updating the view.
Main use of asyncktask to perform long running task so there are three methods preExecute to set progress bar befor starting executing task, doinbackground to perform task like download data (main thread),post execute to perform task after completion of task
you can only change UI component from Post execute while using asynctask.
For more info related to asynktask refer https://developer.android.com/reference/android/os/AsyncTask.html
and for Implementation and explanation refer AsynkTask ImplementationUpdate UI from Thread
you can also use RunonUI therad method and Handler
Edit: It was suggested that it would be helpful to add my code so, my AsyncTask code is now pasted below...
I'm just learning Android and I have a UI with a few buttons. I want to animate the UI, changing the color of the buttons, in a sequence.
I shouldn't do that from the main thread of course, and it doesn't work anyway. The code manipulating the UI runs but the UI doesn't update until the end of the sequence.
So I created a thread and tried to run through the sequence from a background thread however, I would get an error trying to manipulate the UI components from the background thread. Only the main thread can touch the UI components.
Then I discovered AsyncTask. What I figured was, I could run through the sequence in doInBackground(). Every time I needed to update the UI I'd call publishProgress() which would cause onProgressUpdate() to be called from the main thread so I could access UI components without error.
Every time I call publishProgress() I would follow it with a SystemClock.sleep(500) to let time pass until the next animated UI update.
What I found though was that doInBackground() would run through the 4 UI state changes in about 2 seconds (500 ms each) but the UI would not update with each call to publishProgress(). Instead doInBackground() completes and then onProgressUpdate() is called 4 times in a row.
From the description, publishProgress & onProgressUpdate are designed to update a progress bar as doInBackground cranks through some longish running task so, obviously, onProgressUpdate must execute multiple times before doInBackground completes, right?
Am I missing something?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startGame(View view) {
MyTask task = new MyTask();
task.doInBackground();
}
class MyTask extends AsyncTask<Void,Void,Void> {
private int current_int;
#Override
protected Void doInBackground(Void... voids) {
this.current_int = 1;
Log.e("doInBackground","light up button "+this.current_int);
publishProgress();
SystemClock.sleep(500);
this.current_int = 2;
Log.e("doInBackground","light up button "+this.current_int);
publishProgress();
SystemClock.sleep(500);
this.current_int = 1;
Log.e("doInBackground","light up button "+this.current_int);
publishProgress();
SystemClock.sleep(500);
this.current_int = 2;
Log.e("doInBackground","light up button "+this.current_int);
publishProgress();
SystemClock.sleep(500);
return null;
}
#Override
protected void onProgressUpdate(Void... voids) {
super.onProgressUpdate(voids);
Log.e("onProgressUpdate","Updating button "+this.current_int);
Button btn1 = (Button) findViewById(R.id.button1);
Button btn2 = (Button) findViewById(R.id.button2);
if (this.current_int==1){
btn1.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light));
btn2.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_dark));
} else {
btn2.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light));
btn1.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_dark));
}
}
}
}
Just for reference : An Asynctask presents a systematic way to transition from main thread (calling thread) to the new thread (called thread). The onPreExecute() and onPostExecute() methods execute on the calling thread and the doInBackground() is the actual method executing on the new thread. Doing UI updates on main thread will hence lead to exception if done from doInBackground() method.
Your core background logic should hence be placed in the doInBackground() method.
If you want to update UI from background thread (Asynctask or otherwise), you can do it using this :
YourActivity.this.runOnUiThread(new Runnable(){
#Override
public void run()
{
//UI update operations here
}
});
You can use Handler for this,
public class TestClass extends AsyncTask<Void,Void,Void> {
boolean isRunning = true; //set false after executing UI logic.
Handler mHandler = new Handler();
#Override
protected Void doInBackground(Void... params) {
YourFunctionToUpdateUI();
return null;
}
public void YourFunctionToUpdateUI()
{
new Thread(new Runnable() {
#Override
public void run() {
while (isRunning) {
try {
mHandler.post(new Runnable() {
#Override
public void run() {
// your code to update the UI.
}
});
} catch (Exception e) {
//handle exception
}
}
}
}).start();
}
}
I'm an idiot. The problem is, I'm creating an AsyncTask and then calling doInBackground() directly, from my main thread instead of calling execute() which creates the background thread
In an effort to learn Android I am writing a small app. The first thing I am trying to do is login via a remote API.
I would like to show a "loading" dialog when the call is being made (in case he user in using mobile internet). Researching this has shown two possible methods.
One is to use a ProgressDialog and a private class that extends Thread, the other is using a private class that extends AsyncTask.
Which is best/more appropriate for this task?
I have tried using the ProgressDialog version but am struggling. I have put the function making the http request in the extended Thread run() method, but am unsure on how to pass the response data (JSON) back into my activity.
Any and all help gratefully received.
The best way possible is to use an AsyncTask with a ProgressDialog. You should extend AsyncTask and implement all the methods you need:
onPreExecute() - here you initialize your ProgressDialog and show() it
doInBackground() - here you do your work
onPostExecute() - here you call dismiss() on ProgressDialog to hide it
(optional) onProgressUpdate() - here you can change the progress of your ProgressDialog if it's determinate
There is a get() method in AsyncTask class that lets you retrieve the result of the work. Also you can implement an interface between the AsyncTask and calling Activity to return the result. Hope this helps.
Efforts come with rewards :) Egor is right, AsyncTask is the best way to do it. But
You have to know that Activity is working on the UI thread and threads not. So the only way to share things is via handler. Here an example:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
progress = (ProgressBar) findViewById(R.id.progressBar1);
handler= new Handler();
}
public void startProgress(View view) {
// Do something long
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
progress.setProgress(value);
}
});
}
}
};
new Thread(runnable).start();
}
In my activity class i want to perform a series of long calculations that require around 5 sec to complete when i press a button. So in order to do that i have create a new class which does all the calculations in its run method(since it implements Runnable) and when finished i set a variable to true to indicate that. In the code that checks the if the button is pressed i start a new Thread passing my class in it and then cheking whether the run method has finished or not. If it finished i then print the data. The problem with this is that when i check if the calculations have finished they actually havent so it pass that line of code and never prints the data. I have tried to do the Async Class method but still i think it wont work. Is there a way to create the thread when i press the button and keep checking if had finished so i can print the data? Which piece of code in an Activity is actually get executed over and over again? Thanks for any information.
if(v.equals(this.button)) {
EditText param1 = (EditText)findViewById(R.id.param1);
EditText param2 = (EditText)findViewById(R.id.param2);
calculations = new MathCalc(param1.getText().toString(), param2.getText().toString());
new Thread(calculations).start();
while(!calculations.isReady());
Intent intent = new Intent(this,Show.class);
intent.putExtra("show1", calculations.getResult());
startActivity(intent);
}
This is want i want to achieve.
The AsyncTask is the right tool for this. The typical use case for the AsyncTask is that you want to do something small in the background and leave feedback through the UI before, during and/or after the task is done.
Be aware that running things in the background can get you in trouble if the user quits and restarts your activity a lot, since the background task will not end when the Activity is removed from screen.
An example activity is shown below. You could add the onPreExecute and onProgress methods to the AsynchTask to give the user feedback before and during the calculation.
public class CalcActivity extends Activity {
private Button button;
private TextView resultView;
public void onCreate() {
button = (Button) findViewById(R.id.my_button);
resultView = (TextView) findViewById(R.id.result);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
button.setEnabled(false);
AsyncCalculation calc = new AsyncCalculation();
calc.execute();
}
});
}
public class AsyncCalculation extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... params) {
int result = 0;
// Do some calculation
return result;
}
#Override
protected void onPostExecute(Integer result) {
// Set the result, start another activity or do something else
resultView.setText("The result was " + result);
button.setEnabled(true);
}
}
}
I don't see how this won't work with AsyncTask. You basically need to override two methods - doInBackground() and onPostExecute().
You're guaranteed that onPostExecute() will be invoked on the UI thread after the background computation finishes. You also don't have to worry how to update the UI Thread from another thread.
Here's a good example.
Use
Button someButton = (Button) findViewById(R.id.favouriteButton);
someButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while(!isDone){
doAlotOfCalculations();
}
}
});
thread.start();
}
});
private void doAlotOfCalculations(){
...
if(whenDone){
isDone = true;
}
....
}
Which piece of code in an Activity is actually get executed over and
over again?
There is no such a thing.
It is just onResume which executes every time you start(restart) this activity
I use AsyncTask to change text of TextView like this:
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
response += url;
}
return response;
}
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
}
Everything will fine if I call it in OnClick event:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = (TextView) findViewById(R.id.txt);
Button button = (Button)this.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
new LongOperation().execute(new String[]{"Hello"});
}
});
}
But the problem when I called it in my thread, the program forced close
this.closeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Thread t= new Thread(){
#Override
public void run(){
try{
//Do something
//Then call AsyncTask
new LongOperation().execute(new String[]{"Hello"});
}catch(Exception e){}
}
};
t.start();
}
});
Where am I wrong? I dont' understand how difference call AsyncTask in thread or not.
I recommend you consult the AsyncTask documentation and Processes and Threads for a better understanding of how it works. Essentially, you should create your AsyncTask subclass on the main thread.
When you call AsyncTask.execute(), your provided, AsyncTask.onPreExecute is called on the main thread, so you can do UI setup.
Next AsyncTask.doInBackground method is called, and runs in its own thread.
Finally, when your AsyncTask.doInBackground method completes, a call is made to AsyncTask.onPostExecute on the main thread, and you can do any UI cleanup.
If you need to update the UI from within your AsyncTask.doInBackground method, call AsyncTask.publishProgress, which will invoke onProgressUpdate in the main thread.
When you call it from the UI thread, the associated Context is the running Activity. When you call it from a regular thread, there is no valid Context associated with that thread. AsyncTask executes in its own thread, you shouldn't be creating its own thread. If that is actual code, then you have missunderstood the point of AsyncTask. Search for tutorials on how to use it.
Adding to what the others have said: I think you can use AsyncTask to launch off a task in another thread, even if you start the AsyncTask from a different thread than the UI already.
But in that case, the only way you'll only be able to modify the UI indirectly, for example: pass the handler of the current Activity somehow to this AsyncTask instance, and send messages to it (handler messages get processed on the UI thread). Or use broadcast intents that the Activity catches and updates the UI accordingly, etc. These solutions seem to be overkills though.