My app crashes with AsyncTask - android

I'm new to android and have a problem with my simple application.
I using a very simple counter using AsyncTask.
When I run the app and start the counter, it counts to 10, and then instead of printing "DONE!" the app just crushes, I have no idea why. Here's my code.
(The activity has 3 buttons to create, start and cancel the task).
public class AsyncTaskActivity extends AppCompatActivity {
AsyncTask myAsyncTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
}
public static void startActivity(Context context){
Intent intent = new Intent(context, AsyncTaskActivity.class);
context.startActivity(intent);
}
public void createNewTask(View view) {
TextView textView = findViewById(R.id.text_view_id);
myAsyncTask = new MyAsyncTask(textView);
}
public void startTask(View view) {
myAsyncTask.execute();
}
public void cancelTask(View view) {
myAsyncTask.cancel(true);
}
private static class MyAsyncTask extends AsyncTask{
private TextView textView;
public MyAsyncTask(TextView textView){
this.textView = textView;
}
#Override
protected Object doInBackground(Object[] objects) {
for(int counter = 0; counter <= 10; counter ++){
if(!isCancelled()) {
textView.setText(String.valueOf(counter));
SystemClock.sleep(500);
}
else
break;
}
textView.setText("DONE!");
return null;
}
}

You cannot update UI from background thread mean the code inside doInBackGround runs on background thread
#Override
protected Object doInBackground(Object[] objects) {
for(int counter = 0; counter <= 10; counter ++){
if(!isCancelled()) {
textView.setText(String.valueOf(counter));
SystemClock.sleep(500);
}
else
break;
}
textView.setText("DONE!");
// ^^^^^ crash , cannot update UI from background thread
return null;
}
so instead use onPostExecuted
protected void onPostExecute(Long result) {
textView.setText("DONE!");
}
Note: if you cancel the task then you will find the same crash with textView.setText(String.valueOf(counter));.
Always use generic types and pass the resultant counter value and update UI accordingly.
private static class MyAsyncTask extends AsyncTask<Void,Void,Integer>{
private TextView textView;
public MyAsyncTask(TextView textView){
this.textView = textView;
}
protected Long doInBackground(Void... obj) {
for(int counter = 0; counter <= 10; counter ++){
if(!isCancelled()) {
SystemClock.sleep(500);
return counter;
}
else
break;
}
return null;
}
protected void onPostExecute(Integer result) {
if(result != null)
textView.setText(String.valueOf(result));
else
textView.setText(String.valueOf("Done"));
// your current code will set done no matter the task is cancelled or not
}
}

You can't edit View from AsyncTask doInBackground (only main thread). So move setText to onPostExecute
#Override
protected void onPostExecute(Void result)
textView.setText("DONE!");
}

Related

AsyncTask is not run from start when the Activity is created

I'm facing a problem: I created two Activities.
One is the main Activity, which has a Button.
When I click this Button, the second Activity starts.
The second Activity uses an Asynctask in which a number is incremented from 1 to 10 and displays this number in a Textview
What I'm facing is that when I click the back Button while the Asynctask has not completed and then again go to the second Activity the Asynctask is not run from start immediately.
I know because in background when it completed the old task then it again starts a new task. Is there a way to fix this when destroying the Activity it also destroy the Asynctask?
Here is video sample for my problem.
Code for Main Activity:
public class MainActivity extends AppCompatActivity {
Button bt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this,SecondAcitivity.class);
startActivity(i);
}
});
}
}
Code of Second Activity:
public class SecondAcitivity extends AppCompatActivity {
TextView t1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_acitivity);
t1 = (TextView) findViewById(R.id.t1);
OurWork obj = new OurWork();
obj.execute();
}
class OurWork extends AsyncTask<Void, Integer, String> {
#Override
protected String doInBackground(Void... params) {
int i = 0;
while (i < 11) {
try {
Thread.sleep(700);
publishProgress(i);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Successfully Completed";
}
#Override
protected void onProgressUpdate(Integer... values) {
t1.setText(values[0] + "%");
}
#Override
protected void onPostExecute(String result) {
t1.setText(result);
}
}
}
you need to cancel the task on back pressed, and you need to monitor if the task is canceled while executing the doInbackground().
1- override onbackpressed:
#Override
public void onBackPressed() {
obj.cancel(true); // where obj is the asyncTask refernce object name
super.onBackPressed();
}
2- monitor isCanceled()
#Override
protected String doInBackground(Void... params) {
int i = 0;
while (i < 11 && !isCancelled()) { // added !isCancelled()
try {
Thread.sleep(700);
publishProgress(i);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Successfully Completed";
}
on next iteration of the while loop, after cancel(true); is called,the loop will quit, and doInBackground() will return.
When you press back button , onBackPressed callback is called. so you can basically try this :
#Override
public void onBackPressed() {
if (asyncFetch.getStatus() == AsyncTask.Status.RUNNING) {
asyncFetch.cancel(true);
}
finish();
}
Try to use :
private OurWork task;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_acitivity);
t1 = (TextView) findViewById(R.id.t1);
task = new OurWork();
task.execute();
}
#Override
public void onBackPressed() {
task.cancel(true);
super.onBackPressed();
}
AsyncTask runs in background of the activity where it was hosted. If OnPause or OnDestroy is called, AsyncTask is destroyed, so to solve this issue, Override OnResume and execute AsyncTask again.
To cancel the asyncTask even when it is running when back is pressed, add this to onBackPressed:
public class SecondAcitivity extends AppCompatActivity {
TextView t1;
static OurWork obj;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_acitivity);
t1 = (TextView) findViewById(R.id.t1);
obj = new OurWork();
obj.execute();
}
class OurWork extends AsyncTask<Void, Integer, String> {
#Override
protected String doInBackground(Void... params) {
int i = 0;
while (i < 11) {
try {
Thread.sleep(700);
publishProgress(i);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Successfully Completed";
}
#Override
protected void onProgressUpdate(Integer... values) {
t1.setText(values[0] + "%");
}
#Override
protected void onPostExecute(String result) {
t1.setText(result);
}
}
//override onBackPressed and do this
#Override
public void onBackPressed() {
if (obj!=null && (obj.getStatus()== AsyncTask.Status.RUNNING ||
obj.getStatus()== AsyncTask.Status.PENDING ))
obj.cancel(true);
super.onBackPressed();
}
}

count-up effect for a textView in Android

I am working on an app that counts the number of words in a paragraphs/page of text.
After the scanning is done, I would love to show the output total number of words after the number goes from 0 to TOTAL (No of Words).
Example: So, for 100 words: 0..wait..1..wait..2..wait..3..wait..4..wait..5,6,7,8,9 10.......99,100 and then STOP.
I have tried a couple of different techniques:
TextView sentScore = (TextView) findViewById(R.id.sentScore);
long freezeTime = SystemClock.uptimeMillis();
for (int i = 0; i < sent; i++) {
if ((SystemClock.uptimeMillis() - freezeTime) > 500) {
sentScore.setText(sent.toString());
}
}
Also I tried this:
for (int i = 0; i < sent; i++) {
// try {
Thread.sleep(500);
} catch (InterruptedException ie) {
sentScore.setText(i.toString());
}
}
But nothing is helped me. I am sure these are both completely amateur attempts.
Any help? Thanks
The below code will help you current gap is 100 ms but you can change as per your convenience
for (int i = 0; i < sent; i++) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
sentScore.setText(sent.toString());
}
}, 100 * i);
}
In android you are supposed to use AsyncTask for this kind of work
http://developer.android.com/reference/android/os/AsyncTask.html
private class CountUpTask extends AsyncTask<Void, Void, Void> {
private TextView textview;
private int current, total, interval;
public CountUpTask(TextView textview, int total, int interval) {
this.textview = textview;
this.current = 0;
this.total = total;
this.interval = interval;
}
#Override
protected void doInBackground() {
while(this.current < this.total){
Thread.sleep(this.interval);
this.current++;
publishProgress(this.current);
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
this.textview.setText("0");
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
this.textview.setText(progress+"");
}
#Override
protected void onPostExecute() {
}
}
As you can see, doInBackground is executed in a background thread, onPrexcute, onProgressUpdate and onPostExecute are executed in UI thread, allowing you to update the UI.
CountUpTask countUpTask = new CountUpTask ((TextView) findViewById(R.id.sentScore), sent, 500);
countUpTask.execute();

Update ProgressDialog from Thread inside Service

i want to increment a progress dialog from a thread inside a service, i have really hard time doing that, this is my code please help me.
I tried many different ways including asyncTask (I had problem with context)
and tried with static functions but its not working properly,
I pretty new with android please explain me the problem here.
the activity
public class MainActivity extends Activity {
ProgressDialog progressBar;
private void showProgrssBar() {
progressBar.show();
}
private void dismissProgressBar() {
progressBar.dismiss();
}
private void increaseProgressBar(int total) {
progressBar.incrementProgressBy(total);
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createProgressBarDialog();
Intent n = new Intent(this, myService.class);
startService(n);
}
private void createProgressBarDialog()
{
progressBar = new ProgressDialog(this);
progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressBar.setMax(200);
progressBar.setMessage("Recieving bluetooth data");
progressBar.setCanceledOnTouchOutside(false);
}
the service:
public class myService extends Service
{
private myThread myThread;
Handler handler = new Handler()
{
#Override
public void handleMessage(android.os.Message msg)
{
int total = msg.getData().getInt("total");
if (total == -1)
{
dismissProgressBar();
}
else if (total == 0)
{
showProgrssBar();
}
else
{
increaseProgressBar(total);
}
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
myThread = new myThread(handler);
myThread.start();
return START_STICKY;
}
the thread
class myThread extends Thread
{
Handler h;
int numOfLinesToRead = 220;
int line = 0;
public myThread(Handler h)
{
this.h = h;
}
private void increaseProgressBarOnActivity(int i_MsgType)
{
Message msg = h.obtainMessage();
Bundle b = new Bundle();
b.putInt("total", i_MsgType);
msg.setData(b);
h.sendMessage(msg);
}
#Override
public void run() {
super.run();
int increase;
try
{
Thread.sleep(1);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
for (; line < 220; line++)
{
increase = (line*100/numOfLinesToRead);
if (increase != 0)
{
increaseProgressBarOnActivity(increase);
try
{
Thread.sleep(90);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
Despite you having already tried AsyncTask, I still would strongly recommend to use it.
Just take a look at the onProgressUpdate() method. It is made to update the UI from AsyncTask.
Here is an example of how it could look like:
private class DownloadFilesTask extends AsyncTask<String, Integer, Long> {
private ProgressDialog progressBar;
#Override
protected void onPreExecute(){
super.onPreExecute();
progressBar= new ProgressDialog(getApplicationContext());
progressBar.setMessage("Loading...");
progressBar.show();
}
protected Long doInBackground(String... params) {
long someLong;
// do something here with params
// the Integer variable is used for progress
publishProgress(i);
// call it for example while downloading a file
return someLong;
}
// this is called whenever you call puhlishProgress(Integer)
protected void onProgressUpdate(Integer... progress) {
progressBar.incrementProgressBy(progress[0]);
}
// the onPostexecute method receives the return type of doInBackGround()
protected void onPostExecute(Long result) {
// do something with the result
progressBar.dismiss();
}
}
You said your problem was getting the Context. Well: Service is a Context
So you could simply make the AsyncTask an inner class of your Service and then use its Context.

How to show dialog box from asyntask nonUI activity in android?

i have implemented code form the below link to check the idle time of the application
How to intent to another page on android/pop up a message from idle time?
Instead using thread i used asyntask...Now my problem once it reaches the idle time..i want to show dialog to the user application is end relogin from the login activity..
How can i call dialog from the asynctask onpostExcute
public class session extends AsyncTask<Void,Void,Void> {
private static final String TAG=session.class.getName();
private long lastUsed;
private long period;
private boolean stop;
Context context;
final Dialog dialog = new Dialog(context);
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
//here i do the process.......
}
#Override
protected void onPostExecute(Void x){
//stuff to be done after task executes(done on UI thread)
// For Dialog Button**********************************
dialog.setContentView(R.layout.dialog);
dialog.setTitle("Result");
final TextView dialogtxt = (TextView) dialog
.findViewById(R.id.textView1);
final Button closeButton = (Button) dialog
.findViewById(R.id.button1);
closeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
dialogtxt.setText("session time out");
dialog.show();
// ****************************************************
}
#Override
protected void onPreExecute(){
//stuff to be done after task executes(done on UI thread)
}
}
You can do it by calling the dialog from either one of the methods except the doInBackground method.
You may call it in the onPreExecute and show the dialog there and after your background task is done you can cancel it from the onPostExecite method. If you want even more control you can also do it using onProgressUpdate. Just dispatch the progress from your background task by calling publishProgress and overwrite the onProgressUpdate method and do whatever you want there.
This is an example taken right out of the docs.
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
The Asynctask need to get the Context.
If your Asynctask is embeded into the activity, just call the java Activity.this as a context.
You can also put a context as a field in the Asynctask and then give it as an arg to Asynctask.
You can call the Dialog.show in the onPostExecute, it's on UI Thread.
This sample AsyncTask is embeded into an activity
public class AsyncDialogBuilder extends AsyncTask {
private Context context = DriverOnTripActivity.this;
private final AlertDialog.Builder dialog = new AlertDialog.Builder(context);
private Integer remoteAllWaitinOnCount;
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
}
#Override
protected Integer doInBackground(Integer... integers) {
remoteAllWaitinOnCount = User.getRemoteAllWaitinOnCount(latestClosestKojo.getRemoteId());
if (remoteAllWaitinOnCount > 0) {
try {
makeDialog();
} catch (Exception e) {
e.printStackTrace();
}
return 100;
} else {
return 99;
}
}
private void makeDialog() {
dialog.setTitle(latestClosestKojo.getName()
+ " - "
+ remoteAllWaitinOnCount
+ " Kojoalas");
dialog.setPositiveButton("S'arreter", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
isDialogPrompted = false;
dialogInterface.dismiss();
goToOnBoardingActivity();
}
});
dialog.setNegativeButton("Ignorer", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
isDialogPrompted = false;
dialogInterface.dismiss();
}
});
}
#Override
protected void onPostExecute(Integer integers) {
if (integers >= 100 && dialog != null) {
dialog.show();
isDialogPrompted = true;
}
}
}

Android: TimerTask scheduled for repetition getting fired only once

Ok this is a very weird problem I am having, and I'm pretty sure that I am messing up somewhere, but I can't quite figure out where.
What I am trying is -
Schedule a Timer to execute a TimerTask every five seconds
The TimerTask in turn executes an AsyncTask (which in this case simple sleeps for a second before returning the static count of the number of AsyncTasks).
Finally, the aforementioned count is updated in the UI.
And of course, the appropriate Handlers and Runnables have been used to post asynchronous messages from other threads to the UI.
This code executes only once. I expect it to fire every 5 seconds. Here's the code.
Note: I had no idea what to do with the Looper. I put it there after trial and error!
public class TimerAsyncMixActivity extends Activity {
public static final String TAG = "TimerAsyncMix";
static int executionCount = 0;
Handler mHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Timer().schedule(new MyTimerTask(this), 0, 5000);
}
class MyAsyncTask extends AsyncTask<String, Void, Integer>{
#Override
protected Integer doInBackground(String... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ++executionCount;
}
#Override
protected void onPostExecute(Integer result) {
mHandler.post(new UpdateUiThread(TimerAsyncMixActivity.this, result));
super.onPostExecute(result);
}
}
}
class MyTimerTask extends TimerTask{
private TimerAsyncMixActivity tma;
public MyTimerTask(TimerAsyncMixActivity tma) {
this.tma = tma;
}
#Override
public void run() {
Looper.prepare();
Log.d(TimerAsyncMixActivity.TAG, "Timer task fired");
tma.new MyAsyncTask().execute();
Looper.loop();
Looper.myLooper().quit();
}
}
class UpdateUiThread implements Runnable{
int displayCount;
TimerAsyncMixActivity tma;
public UpdateUiThread(TimerAsyncMixActivity tma, int i) {
this.displayCount = i;
this.tma = tma;
}
#Override
public void run() {
TextView tv = (TextView) tma.findViewById(R.id.tvDisplay);
tv.setText("Execution count is : "+displayCount);
}
Can anyone point me to what I'm doing wrong?
techie, this is how I implemented similar things. I'm won't claim that this is the best way, but it has worked for me and doesn't look too bad.
I have the following code in my activity. I create an async task when the activity starts and I stop it onPause. The AsyncTask does whatever it needs to do, and updates the UI on onProgressUpdate() (which is run on the UI thread, so there's no need to use a Handler).
private Task task;
#Override
protected void onPause() {
task.stop();
task = null;
}
#Override
protected void onResume() {
task = new Task();
task.execute();
}
private class Task extends AsyncTask<Void, String, Void> {
private boolean running = true;
#Override
protected Void doInBackground(Void... params) {
while( running ) {
//fetch data from server;
this.publishProgress("updated json");
Thread.sleep(5000); // removed try/catch for readability
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
if( ! running ) {
return;
}
String json = values[0];
//update views directly, as this is run on the UI thread.
//textView.setText(json);
}
public void stop() {
running = false;
}
}
Do not use a timer. If your phone goes to sleep, the timer is suspended too. Use AlarmManager.

Categories

Resources