I have the following code which should update UI textview on Asynctask:
public class HelloWorldActivity extends Activity
{
private static TextView txtview;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
}
private static class SimpleTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... res) {
try {
Thread.sleep(1500);
} catch(InterruptedException exception) {
Thread.currentThread().interrupt();
}
return null;
}
#Override
protected void onPostExecute(Void params) {
txtview.setText("Hola Mundo");
}
}
}
Particularly I'm triying to change Hello World to Hola Mundo after 1,5 seconds passed. The problem is that while running the app the text still is Hello World and doesn't change. I get no error of any sort. I have even set txtview value outside onCreate method to avoid any access problems (or so I think).
If after txtview = (TextView) findViewById(R.id.mainview); I do txtview.setText("Hola Mundo"); then it works flawlessly.
What could be the problem?
Forget to execute AsyncTask by calling AsyncTask.execute() method. do it as by adding following lines in onCreate method after initializing txtview TextView object:
SimpleTask objSimpleTask=new SimpleTask();
objSimpleTask.execute();
You have not called ASyncTask, execute it like this after initializing TextView:
txtview = (TextView) findViewById(R.id.mainview);
SimpleTask objSimpleTask=new SimpleTask();
objSimpleTask.execute();
Hope is what you want.
Currently you are forget to call AsyncTask.
But i think it is a bad practice to use AsyncTask & Thread.sleep() to update UI .
ou can simply do it with Handler.
Runnable updateUI;
Handler h = new Handler();
updateUI=new Runnable() {
#Override
public void run() {
txtview.setText("Hola Mundo");
}
};
h.postDelayed(updateUI,1500);
Related
Below is a login activity which connects with the server to perform login operation, so for this to do in Background thread how to use Asynctask's methods correctly?
I am new to android and not used Asynctask before, but I have seen tutorials still couldn't do it myself
//public class LoginActivity extends AppCompatActivity extends Asynctask shows some error
Edit: error is here
//public class LoginActivity extends AsyncTask extends
AppCompatActivity{ ( { expected)
public class LoginActivity extends AppCompatActivity{
private TextView tvLFS, tvOr;
private Button btnLog;
private EditText etUn, etPw;
private static final String TAG = "LoginActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
//remove action bar
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
//change font of the heading
tvLFS = (TextView) findViewById(R.id.tvHeadingLFS);
Typeface typeface =
Typeface.createFromAsset(getAssets(),
"fonts/futuramediumitalicbt.ttf");
tvLFS.setTypeface(typeface);
init();
}
private void init() {
tvLFS = (TextView) findViewById(R.id.tvHeadingLFS);
tvOr = (TextView) findViewById(R.id.tvOR_LOGIN_USING);
btnLog = (Button) findViewById(R.id.btnLogin);
etUn = (EditText) findViewById(R.id.etUName);
etPw = (EditText) findViewById(R.id.etPass);
/* SharedPreferences pref = getSharedPreferences("ActivityPREF",
Context.MODE_PRIVATE);
SharedPreferences.Editor edt = pref.edit();
edt.putBoolean("activity_executed", true);
edt.commit();*/
btnLog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
final String usname = etUn.getText().toString();
final String uspass = etPw.getText().toString();
final LoginRequest loginRequest = new LoginRequest();
loginRequest.setClientType("mobile");
loginRequest.setMsService("login");
loginRequest.setMsServiceType("user-management");
List<LoginRequest.MsDataLogin> msDataLogList = new
ArrayList<>();
LoginRequest.MsDataLogin msData =
loginRequest.getMsDAtaLoginInstance();
msData.setUserName(usname);
msData.setUserPass(uspass);
msDataLogList.add(msData);
loginRequest.setMsData(msDataLogList);
RestClient.getApiInterface().postData(loginRequest).enqueue(new
ResponseResolver<LoginResponse>(LoginActivity.this) {
#Override
public void success(LoginResponse loginResponse) {
if (loginResponse.getErrorCode().equals("0"))
{
Toast.makeText(LoginActivity.this,
"Logged-in successfully!!", Toast.LENGTH_SHORT).show();
Intent in = new
Intent(getApplicationContext(), MainActivity.class);
startActivity(in);
finish();
} else
if(loginResponse.getErrorCode().equals("1")){
Toast.makeText(LoginActivity.this, "No
account found!! Please register", Toast.LENGTH_LONG).show();
}
}
#Override
public void failure(APIError error) {
Log.d(TAG, "failure: error--
"+error.getMessage());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Based on you edit, you're trying to extend two classes? Well, (I think) that's not possible in Java ...
Back to your question about AsyncTask. AsynTask are made to make task outside de Main Thread/UI Thread, for some scenarios (Ex.: the basic, not lock the UI while doing some work), for that reason you can't interact with the UI in a AsyncTask or even mix both things (is possible in some cases, but not recommended).
So you need to extends AsyncTask in other class than your view/activity (another Class.java or nested/internal class), example below:
public class MyAsyncTask extends AsyncTask<ParameterType, ProgressType, ReturnType> {
//Example to demonstrate UI interation
private IView view;
public MyAsyncTask(IView view) {
this.view = view;
}
#Override
protected ReturnType doInBackground(ParameterType... params) {
// do and update the work
return new ReturnType(); // work is done, return the result
}
// Override this method if you need to do something after the AsyncTask has finished (based on the return). Here you can interact with the UI too.
#Override
protected void onPostExecute(ReturnType o) {
// Example of UI interaction
view.updateUI(o);
}
}
If you don't need Parameters, Returns or update the progress of your AsyncTask, you can use the 'Void' type in place ParameterType, ProgressType or ReturnType.
Then you can create a intance of MyAsyncTask in other classes (Ex.: your activity) an call ‘execute()’ method to start the AsyncTask.
public class Foobar extends AppCompatActivity implements IView {
... code ...
MyAsyncTask fooTask = new MyAsyncTask(this); // Foobar class needs to implement IView interface
fooTask.execute(parameters); // execute AsyncTask with 'parameters'
... code ...
}
Based on your code you're trying to make a Network call. So you need need migrate your network call to inside 'doInBackground' method, and call the next activity (or show the error) in the 'onPostExecute'.
I not very familiar with your implementation (RestClient, ResponseResolver), but I think you can use Retrofit/Jackson libraries for a more solid solution. They are not very difficult to understand and makes Network calls easier.
In the references below there are other alternatives that you can use instead of a AsyncTask.
Here is some references:
https://developer.android.com/reference/android/os/AsyncTask.html
https://developer.android.com/guide/components/processes-and-threads.html
Good coding.
I have following sample code to understand the TextView update
public class MainActivity extends Activity
{
int i=0;
private ImageButton btnMain;
private TextView txtText;
Context mycont=null;
public void myJob(final String cmd)
{
//txtText.setText(cmd);
runOnUiThread(new Runnable()
{
#Override
public void run() {
txtText.setText(cmd); //---Does not update the TextView here on Main UI
}
});
//----------- Long Work(Take around 15 seconds to complete) ----------
for(i=0;i<=1000000000;i++)
i++;
for(i=0;i<=1000000000;i++)
i++;
//--------------------------------------------------------------------
//---Update the TextView here once above Long work is executed
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mycont=this;
txtText = (TextView) findViewById(R.id.txtText);
txtText.setMovementMethod(new ScrollingMovementMethod());
btnMain = (ImageButton) findViewById(R.id.btnJob);
btnMain.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
myJob("Display this msg");
}
});
}
}
TextView is not updating on time, its waiting for other procedure to execute.
Please point me in right direction. I want to Update the TextView in the beginning of the myJob() function.
Look at this link: How will UI changes be processed in the onClickListener before starting a new activity in Android?
"Changes to UI elements are not executed immediately. They're executed the next time the UI loop runs, which is after you release control."
I would suggest you look into AsyncTasks. They allow you to perform actions before and after doing a timeconsuming job. In your case your AsyncTask would look somewhat like this:
private class LongJob extends AsyncTask<Void, Void, Void> {
TextView textViewToChange;
public LongJob(TextView text){
textViewToChange = text;
}
protected void onPreExecute(){
// Executed on main(UI) thread
textViewToChange.setText("Some random text here");
}
protected Long doInBackground(Void... params) {
// Your long job here, executed on background thread so
// it won't freeze your application.
return null;
}
protected void onPostExecute(Void result) {
// Executed on main(UI) thread
textViewToChange.setText("Text for after your job completed");
}
}
If I understand correctly, you want to update the textview, then run the Long Work. In that case do something like this:
public void myJob(final String cmd)
{
txtText.setText(cmd);
txtText.post(new Runnable() {
#Override
public void run() {
//----------- Long Work(Take around 15 seconds to complete) ----------
for(i=0;i<=1000000000;i++)
i++;
for(i=0;i<=1000000000;i++)
i++;
//--------------------------------------------------------------------
}
});
}
Note: In either case, your long work is running on the UI thread.. because you have never created a background task
Thanks to Amulya and Sander.
Both the solutions worked for me.
But as per my need, i will go for the solution by Amulya which is lightweight.
I was already aware of Android AsyncTasks.
But never thought of using in this way.
Thanks to both of you
Generally I update UI in postExecute method.
e.g.
public class SampleActivity extends Activity{
TextView textSample;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aadd_addtocheck);
textSample = (TextView) findViewById(R.id.lin);
STask sampleTask = new Stask();
sampleTask.execute();
}
class GetAdd extends AsyncTask<Void, Void, JSONObject> {
#Override
protected JSONObject doInBackground(Integer... params) {
// TODO Auto-generated method stub
UserFunctions u = new UserFunctions();
return u.getNewAdd();
}
#Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
textSample.setText(result.getString("Something");
}
However, my asyncTask become large and I want to move them to different class (before they were a subclass). Therefor, I wonder how to to update UI ( like setting texviews) when asynctask will be a separete class.
You pass either the Context, Activity, or the individual Views to the AsyncTask's constructor and store them as member variables, then update them on onPostExecute().
Be sure to store Context or Activity as a WeakReference to prevent memory leaks.
If you are going to put the AsyncTask in a separate file, you might be likely to reuse that AsyncTask from other Activities, so I think that the best practise would be to make a callback to the activity so it does all the UI handling.
For doing that what you should do is create an Interface like the following:
public interface OnGetAddCompletedListener {
public void onGetAddCompleted(String text);
}
Receive the callback in the constructor of your AsyncTask and call the method in it in onPostExecute
public class GetAdd extends AsyncTask<Void, Void, JSONObject> {
private OnGetAddCompletedListener callback;
public GetAdd(OnGetAddCompletedListener callback) {
this.callback = callback;
}
#Override
protected JSONObject doInBackground(Integer... params) {
// TODO Auto-generated method stub
UserFunctions u = new UserFunctions();
return u.getNewAdd();
}
#Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
callback.onGetAddCompleted(result.getString("Something");
}
}
And then, implement the interface in the Activity you are executing it so it handles the UI modifications when you get the data in the AsycTask:
public class SampleActivity extends Activity implements OnGetAddCompletedListener {
TextView textSample;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aadd_addtocheck);
textSample = (TextView) findViewById(R.id.lin);
STask sampleTask = new Stask();
sampleTask.execute();
}
public void onGetAddCompleted(String text) {
textSample.setText(text);
}
}
With this approach, if you decide to reuse that AsyncTask from other activity you will be able to do different things when the AsyncTask has ended in case you want to do so.
You can pass arguments into the constructor of your AsyncTask when you call it. Let's say that in your main activity you have the following:
TextView tv = (TextView) findViewById(R.id.my_text_view);
Stask sampleTask = new Stask(tv);
sampleTask.execute();
When you are creating your AsyncTask, you have:
class Stask extends AsyncTask ...(){
final TextView textView;
public Stask(Textview inputFromOtherClass){
this.textView = inputFromOtherClass;
}
}
This way, the TextView created in your main activity can exist as an instance in your AsyncTask.
EDIT:As someone else posted, you can do something similar for the Context, which is useful in creating various instances.
I am writing a board game in Android where the UI consists of textViews for the scores (CPUScore and PlayerScore). The problem I have is that the UI does not update the score from its initial value when onCreate is called. I have looked at similar questions and the solution most suggested is to use AsyncTask to update the UI thread in the background. However I did not find a solution that dealt explicitly with how to use textViews in AsyncTask.
Here is my attempt:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//....
setContentView(R.layout.main_layout);
//.....
//------------ textViews declared here don't refresh -------------------
TextView playerScoreForm = (TextView) findViewById(R.id.PlayerTotalScore);
playerScoreForm.setText(Integer.toString(PlayerTotal));
playerScoreForm.invalidate();
TextView CPUScoreForm = (TextView) findViewById(R.id.CPUTotalScore);
CPUScoreForm.setText(Integer.toString(CPUTotal));
CPUScoreForm.invalidate();
//--------------------------------------------------------------------------
//AsyncTask method:
new updatePlayerScore().execute(PlayerTotal);
new updateCPUScore().execute(CPUScoreForm);
}
The AsyncTask subclasses:
private class updatePlayerScore extends AsyncTask<TextView, Void, Void> {
#Override
protected TextView doInBackground(TextView... params) {
// what to put here??
}
return playerScoreForm;
}
#Override
protected void onProgressUpdate(Integer... values) {
//??
}
protected void onPostExecute(Integer result) {
playerScoreForm.setText(Integer.toString(result));
}
}
private class UpdateCPUScore extends AsyncTask<TextView, Integer, Integer> {
// same syntax as updatePlayerScore
}
Question:
how do I transfer the textViews that I declared in the onCreate method to the AsyncTask method? I am stumped. I am fairly new to Android development.
a) I'm pretty sure you shouldn't need to invalidate the TextViews after you set them; Android should do that automagically.
b) In theory you'd set your TextView references to be member variables and then reference them in onPostExecute instead of passing them into doInBackground. doInBackground in turn will take whichever bits of data enable you to calculate the new score. What you would do on doInBackground is whatever action would cause a new score to be calculated. The return value from doInBackground gets passed into onPostExecute. You would then update the TextView (now a member variable) with this data in onPostExecute. Does that make sense? You haven't actually posted any code here that would update those score values.
See here for a quick example.
private TextView myScoreView; //initialized in onCreate as you do above.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//....
setContentView(R.layout.main_layout);
//.....
myScoreView = (TextView) findViewById(R.id.PlayerTotalScore);
myScoreView.setText(Integer.toString(PlayerTotal));
new updatePlayerScore().execute(1,2); //parameters for calculation
}
private class updatePlayerScore extends AsyncTask<Integer, Integer, Integer> {
#Override
protected TextView doInBackground(Integer... params) {
int score = params[0] + 2 * params[1];
return score;
}
#Override
protected void onProgressUpdate(Integer... values) {
//if you want to provide some indication in the UI that calculation
//is happening, like moving a progress bar, that's what you'd do here.
}
#Override
protected void onPostExecute(Integer scoreCalculationResult) {
myScoreView.setText(Integer.toString(scoreCalculationResult));
}
}
Edit: If you don't want to do the calculation logic in doInBackgroundThread, you probably just want to use:
runOnUiThread(new Runnable(){
#Override
public void run(){
myScoreView.setText(PlayerScoreValue);
}
});
Or:
myScoreView.post(new Runnable(){
#Override
public void run(){
myScoreView.setText(PlayerScoreValue);
}
});
You can pass the TextView in the constructor of the AsyncTask and update it from the onPostExecute method
private class updatePlayerScore extends AsyncTask<Void, Void, Integer> {
private TextView view;
public updatePlayerScore(TextView textView){
this.view = textView;
}
#Override
protected Integer doInBackground(Void... params) {
int score = 0;
//do you calculation the
return score;
}
protected void onPostExecute(Integer result) {
view.setText(Integer.toString(result));
}
}
note: if you Activity configuration change for any reason i.e the user rotate the device and the you AsyncTask hasn't finish it task the update of you TextView will not be updated so you should retain an instance of you AsyncTask and update the the TextView
I have a piece of code that querys my webserver xml parses the data that comes back and fills textfields on my GUi with the relevant data. Before i had this within my oncreate function and the code worked fine. However i wanted to show a loading dialogue to the user so i moved the web server and xml parsing operatons to an asynctask. The problem rises now when i go to populate my GUI text fields with my parsed data and i get an error thrown. Can anyone see what i am doing wrong
new BackgroundAsyncTask().execute(); /// called from the oncreate function
and my background task code is as follows
public class BackgroundAsyncTask extends
AsyncTask<Void, Integer, Void> {
int myProgress;
#Override
protected void onPostExecute(Void result) {
MyDialog.dismiss();
}
#Override
protected void onPreExecute() {
MyDialog = ProgressDialog.show(attraction_more_info.this, " " , " Loading. Please wait ... ", true);
}
#Override
protected Void doInBackground(Void... params) {
xml query and parse stuff on here ...
// Populate page now
TextView titlefield = (TextView) findViewById(R.id.att_title);
TextView add1field = (TextView) findViewById(R.id.att_address1);
TextView add2field = (TextView) findViewById(R.id.att_address2);
TextView townfield = (TextView) findViewById(R.id.att_town);
TextView postcodefield = (TextView) findViewById(R.id.att_postcode);
TextView phonefield = (TextView) findViewById(R.id.att_phone);
WebView webview = (WebView) findViewById(R.id.webview1);
MY ERRORS START HERE
titlefield.setText(attraction_name);
add1field.setText(attraction_address1);
add2field.setText(attraction_address2);
townfield.setText(attraction_town);
postcodefield.setText(attraction_postcode);
phonefield.setText(attraction_phone);
webview.loadData(attraction_description, "text/html", null);
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
}
}
Can anyone help me out?
You can't update UI elements from a non-UI thread. Try moving all the setText() calls and webview.loadData() to onPostExecute()
you'll have to save the query results in the class object to do that
Try this,
add1field.post(new Runnable() {
public void run() {
add1field.setText(attraction_address1);
}
});