TextView is not updating on time - android

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

Related

asyncTask onProgressUpdate does not work at 2nd invoking

im using asyncTask to showing a download progress , my download will be done by a library named "file-downloader" in my main activity.
it's github page is "https://github.com/wlfcolin/file-downloader"
my custom dialog shows when i click to my specified button , and download task and progressBar starts when i press download button in this custom dialog
all thing is ok and progressBar works fine.
but when i dismiss this dialog and another time i invoke this dialog the progressBar does not work !
i save download status in database using the fileDownloader library listeners and anothe time i invoke custom dialog it read from database
and detect downloadProgress is currently running but we see no changing in custom dialog's progressBar , what is the problem ?
activity code
public class MainActivity extends AppCompatActivity {
/*
/
/ some variables
/
*/
public static int downloadedFile2SizePercent = 0 ; // downloaded file percent
public static int downloadingFileStatus = 0; // downloading status
Button myBtn ;
DownloadDialog dd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
myBtn = (Button)findViewById(R.id.button22);
myBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dd = new DownloadDialog(mContext,1);
dd.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dd.show();
}
});
/*
/ downloadingFileStatus value manages here by file downloader listeners correctly and saves as static variable and also in database
/ downloadedFile2SizePercent value manages here by file downloader listeners correctly and saves as static variable
/
*/
}
}
DownloadDialog Class
public class DownloadDialog extends Dialog implements View.OnClickListener{
public Context c;
public Button download, delete;
private ProgressBar pb;
ProgressTask progressTask;
private int downloadStatus;
private String downloadLink;
private int downloadID
public DownloadDialog(Context a, int downloadId) {
super(a);
this.c = a;
this.downloadId = downloadId
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.download_dialog);
download = (Button) findViewById(R.id.downloaddialot_downloadbtn);
delete = (Button) findViewById(R.id.downloaddialot_deletebtn);
download.setOnClickListener(this);
delete.setOnClickListener(this);
pb = (ProgressBar)findViewById(R.id.progressBar);
pb.setMax(100);
pb.setProgress(0);
//database is opend at mainActivity it's static
downloadStatus=Integer.parseInt(MainActivity.prDb.intSearch(downloadId));// detects download status --> 0 is "notDownloadedYet" and
// 1 is "downloading" and 2 is "downloaded"
downloadLink= MainActivity.puDb.intSearch(downloadId);//detects download link
progressTask = new ProgressTask();
if(downloadStatus==1){
pb.setProgress(MainActivity.downloadedFile2SizePercent);//this code line works every 2nd and after dialog invoking
progressTask.execute(true);
Toast.makeText(c,"test task progress for 2nd started", Toast.LENGTH_SHORT).show();//this code line works every 2nd and afterdialog invoking
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.downloaddialot_downloadbtn:
FileDownloader.start(downloadLink); // download task starts here
progressTask.execute(true);
Toast.makeText(c,"download task progress for 1nd started", Toast.LENGTH_SHORT).show();
break;
case R.id.downloaddialot_deletebtn:
if(downloadStatus==2){
// delete codes
}
break;
}
}
public class ProgressTask extends AsyncTask<Boolean, Integer, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Boolean... params) {
while (MainActivity.downloadedFile2SizePercent!=100){
publishProgress(MainActivity.downloadedFile2SizePercent);
}
if(MainActivity.downloadedFile2SizePercent==100){
publishProgress(MainActivity.downloadedFile2SizePercent);
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
pb.setProgress(values[0]);
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
downloadStatus=2; //also saves in database by download listeners in mainActivity
}
}
}
The progress bar just like any other UI element can only be managed or updated from the main UI thread.
It is the time consuming task the part that should be run in a AsyncTask, then this task can save the progress status in a volatile variable and then the UI thread can periodically update the progress bar reading the volatile variable, for example using a timer.
You can read all about AsyncTask here: https://developer.android.com/reference/android/os/AsyncTask.html
But here's my quick example/tutorial:
private class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// prepare your UI for the background task beginning
}
#Override
protected Void doInBackground(Void... params) {
// do some long-running task...
// you can do partial updates like:
publishProgress(25);
/* more hard work */
publishProgress(50);
/* even more hard work */
publishProgress(75);
// and when you're done...
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// update your UI with the current progress (values[0])
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// update your UI now that it's done
}
}
The key concept to understand regarding AsyncTask is that every method except doInBackground() is executed on the UI thread (the main thread). That means you are free to update your UI from these calls.
doInBackground(), however, is executed on a different thread. That means you can do expensive work here without slowing down your app's user interface.
Of course, all the hard work you're doing on that background thread needs to make its way to the UI thread somehow (so that you can use it). That's what publishProgress() and the return statement of doInBackground() are for. When you call publishProgress(someValue), the system will invoke onProgressUpdate(someValue) for you. When you return someValue, the system will invoke onPostExecute(someValue) for you.

Scheduling background task for certain time every day in android

I am doing an android app for a school project. I have made an AsyncTask within my main acticity that fetches data from the internet. I want this to be executed at 23:00 every day, and also when the user first installs and opens the app. I have searched online and tried ScheduledExecutorService, AlarmManager and TimerTask but I either run into trouble compiling my code or the application crashes on start. I am hoping for some help to get this working. Would really appreciate some concrete examples on how to schedule my AsyncTask.
I am currently running the AsyncTask when clicking on a button, but want to remove the button and run the task on a schedule.
Thank you in advance!
public class MainActivity extends AppCompatActivity {
private TextView ViewT;
private TextView ViewR;
private String deg;
private String rainD;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button1);
ViewT = (TextView) findViewById(R.id.ViewT);
ViewR = (TextView) findViewById(R.id.ViewR);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new getData().execute();
ViewR.setText(rainD);
ViewT.setText(deg);
}
});
}
public class getData extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
//fetching data here....
}
}
}
Edit:
I tried this today and the application does not crash but nothing shows up on my textviews either.
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final Runnable updateUI = new Runnable() {
#Override
public void run() {
new getData().execute();
ViewR.setText(rainD);
ViewT.setText(deg);
}
};
scheduler.scheduleAtFixedRate(updateUI, 5,
60*60*24, TimeUnit.SECONDS);

Asynctask inner class not updating UI textview

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);

A long text in the TextView

I have a button, and when i click to it, i make textView.setText() a very big text, 50000 symbols, and the interface stops for 3 seconds, how can i fix it?
I tried to make it with Handle and thread, but it hasn`t helped.
I tried to make textview.append(), but it also hasn`t helped.
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textText.append(rowItemHeader.getText().substring((endOfNews - 10000, endOfNews));
}
});
Edit 1 no result
private class MyTask extends AsyncTask <Void, Void, String> {
String str;
TextView txt;
MyTask(String str, TextView txt){
this.str = str;
this.txt = txt;
}
public String doInBackground(Void... args) {
return str.substring(endOfNews - 10000, endOfNews);
}
public void onPostExecute(String myString) {
// do your update here or you will get that error (the original thread one)
txt.append(myString);
}
}
How did you declare the thread ?
Yu've to use something like that :
this.runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Log.e("TAG synchronize", "synchronize");
}
});
Use AsyncTask, they are meant for exactly what you want. They are a secondary thread that is easy to setup and executes from your main thread.
Use a loop inside the thread that appends portions of the generated text to the TextView using runOnUiThread(new Runnable(...)...) and call Thread.sleep(50) which forces the Thread to sleep for that much milliseconds to prevent the lag.
Use an AyncTask with something like:
private class MyTask extends AsyncTask<Void, Void, String> {
private Context context;
public MyTask(Context context) {
this.context = context;
}
public String doInBackground(Void... args) {
// do your job here
return myString;
}
public void onPostExecute(String myString) {
// do your update here or you will get that error (the original thread one)
((TextView)context.findViewById(R.id.textview)).setText(myString);
}
}
and then in your activity
new MyTask(MyActivity.this).execute();
First, remove the view, then add the text on background thread, then add the view back. Tell me if you need some sample code.

Refresh Game Score TextView using AsyncTask

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

Categories

Resources