I have a asynctask and I want to make it to be canceled after some time, 60 sec for example.
I think I have to it inside a while statemant, but I dont know how to count the time.
Here is my idea:
public class ThreadWithAutoCancel extends AsyncTask<Void, Void, Void> {
public ThreadWithAutoCancel(int timeOut) {
WatchDog watchDog = new WatchDog(this);
watchDog.execute(timeOut);
}
#Override
protected Void doInBackground(Void... params) {
// Do the job
return null;
}
class WatchDog extends AsyncTask<Integer,Void,Void>{
private long startTime;
private AsyncTask task;
public WatchDog(AsyncTask taskToStop){
task = taskToStop;
}
#Override
protected void onPreExecute(){
startTime = System.currentTimeMillis()/1000;
}
#Override
protected Void doInBackground(Integer... params) {
while(System.currentTimeMillis()/1000 < startTime+params[0]){
}
task.cancel(true);
return null;
}
}
}
After starting the AsyncTask, hold a reference to it and call cancel on it 60 seconds later, perhaps on a UI Thread Handler. Inside your doInBackground method you will have to make sure you return if isCancelled returns true. I hope the following snippet will help:
public class MyActivity extends Activity {
private Handler mHandler;
private AsyncTask<?, ?, ?> mTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
}
#Override
protected void onPostResume() {
super.onPostResume();
mTask = new MyCustomTask();
mTask.execute(1, 2, 3);
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mTask.cancel();
}, 60L);
}
}
And inside your custom task:
public class MyCustomTask extends AsyncTask<Integer, Float, String> {
#Override
protected String doInBackground(Integer... params) {
String output = "";
for (Integer i : params) {
// Check status for each param
if (isCancelled()) {
return output;
}
...
}
}
#Override
protected void onCancelled(String result) {
// This bit runs on the UI thread
...
}
You can do this using handler. For example this code will show "Completed" on TextView with R.id.mytext after asynctask will execute for 60 seconds:
final int FINISH = 1;
Thread waitingThread;
MyAsyncTask myAsyncTask;
Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == FINISH)
{
myAsyncTask.cancel(true);
((TextView) findViewById(R.id.mytext)).setText("Completed");
}
};
};
// ...
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
waitingThread = new Thread(new Runnable() {
#Override
public void run() {
try {
TimeUnit.SECONDS.sleep(60);
mHandler.sendEmptyMessage(FINISH);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
myAsyncTask = new MyAsyncTask();
myAsyncTask.execute();
waitingThread.start();
}
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
while (true) {
// do something
}
}
}
Related
I have sample code which very simply does some heavy work and sends a message to a handler to update the UIThread. My concern is with the handler reference i am passing to the constructor. If my activity gets destroyed while the asncTask is still running will the handler reference not be null ?
public class SomeActivity extends Activity
{
private static final int UPDATE_BUTTON_TEXT = 1;
private static final SomeActivity me = null;
private static Handler handler = new Handler() {
public void handleMessage(Message msg) {
if (me == null) return;
switch (msg.what) {
case UPDATE_BUTTON_TEXT:
Button btn = (Button) me.findViewById(R.id.someButton);
btn.setText((String) msg.obj);
}
}
};
private View.OnClickListener onClickListener = new View.OnClickListener() {
public void onClick(View view) {
new SomeLongRunningTask().execute();
}
};
private static class SomeLongRunningTask extends AsyncTask<Void, Void, Boolean> {
private Handler handler;
public SomeLongRunningTask(Handler handler) {
this.handler = handler;
}
#Override
protected Boolean doInBackground(Void... voids) {
try {
Thread.sleep(30000); // replace with some background logic
} catch (InterruptedException e) {}
return true;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
//can the handler be null here if activity is destroyed ????
Message msg = handler.obtainMessage(UPDATE_BUTTON_TEXT);
msg.obj = "success"
handler.sendMessage(msg);
}
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button someButton = (Button) findViewById(R.id.someButton);
someButton.setOnClickListener(onClickListener);
}
#Override
protected void onStart() {
super.onStart();
me = this;
}
#Override
protected void onStop() {
me = null;
super.onStop();
}
}
Yes, the reference of the handler is going to be retained in memory until it has a reference count > 0.
I think you should use AsyncTask().onProgressUpdate for updating progress on UI, which does what you're trying to do.
EDIT
If you're updating ui in onPostExecute then you don't need to use onProgressUpdate(my apologies).
Just use an interface as a callback function like below:
private interface Callback {
void updateUI(String value);
}
private static class SomeLongRunningTask extends AsyncTask<Void, String, Boolean> {
private Callback mCallback;
public SomeLongRunningTask(Callback callback) {
mCallback = callback;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
mCallback.updateUI("success");
}
}
// somewhere else...
Callback callback = new Callback() {
#Override
public void updateUI(String value) {
Button btn = (Button) me.findViewById(R.id.someButton);
btn.setText((String) msg.obj);
}
};
new SomeLongRunningTask(callback).execute();
Also it doesn't seem right to have a handler instance as a static variable. It will last until the class is unloaded.
As a rule, whenever I write an AsyncTask subclass, I use a pattern like this:
private WeakReference<Callback> mCallbackRef;
public MyAsyncTask(Callback callback) {
mCallbackRef = new WeakReference<>(callback);
}
#Override
protected void onPostExecute(Boolean aBoolean) {
if (mCallbackRef != null) {
Callback callback = mCallbackRef.get();
if (callback != null) {
callback.updateUI("success");
}
}
}
I have designed an app that gets the network information and updates the UI every 5 seconds.
It is advised to do the background processes on a separate thread than the UI thread, and I did so...but I still get an error that:
"I/Choreographer﹕ Skipped 3730 frames! The application may be doing
too much work on its main thread."
Why is that?
Here's my code
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wifiTextView = (TextView)findViewById(R.id.wifi_textView);
ipTextView = (TextView)findViewById(R.id.ip_val_textView);
// and so on
//Updating the UI every mInterval seconds, using a separate thread than UI thread
Thread backgroundThread = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(mInterval);
runOnUiThread(new Runnable() {
#Override
public void run() {
//Log.d(DEBUG_TAG, "run(): Background thread");
MyNetwork network = new MyNetwork(getApplicationContext()); // passing the context
updateUI(network);
}
});
}
} catch (InterruptedException e) {
wifiTextView.setText("Exception: Please Close and Restart the App");
}
}
};
backgroundThread.start();
}
In the same MainActivity class, I have this private function:
private void updateUI(MyNetwork network){
// Handles updating the textviews in the UI
//Log.d(DEBUG_TAG, "updateUI(DeepstreamNetwork)");
if (network.isConnected()){
wifiTextView.setText(R.string.wifi_is_on);
wifiTextView.setTextColor(Color.GREEN);
ipTextView.setText(network.getIpAddress());
else {
wifiTextView.setText(R.string.wifi_is_off);
wifiTextView.setTextColor(Color.RED);
ipTextView.setText("N/A");
}
}
UPDATE
So, I have updated my MainActivity class to have this MyAsyncTask method to handle background work...here's my code:
private class MyAsyncTask extends AsyncTask<Void, Void, MyNetwork> {
#Override
protected void onPostExecute(MyNetwork network) {
updateUI(network);
}
#Override
protected MyNetwork doInBackground(Void... params) {
MyNetwork network = new MyNetwork(getApplicationContext()); // passing the context
return network;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
Two issues:
1) how do I force it to do this background task every 5 seconds. Since the network status changes every few secs (disconnection etc...), so I want it to update the UI respectively.
2) should I call it like this in MainActivity: new MyAsyncTask().execute();
Thanks all
I dont know why you called it Thread backgroundThread = new Thread() because runOnUiThread() is really the main Thread.
You should try this in an asynctask where you only update the UI in onPostExecute()
EDIT:
private class MyAsyncTask extends AsyncTask<Void, Void, String> {
private MyNetwork network;
#Override
protected void onPreExecute() {
this.network = new MyNetwork(getApplicationContext());
}
#Override
protected String doInBackground(Void... params) {
return network.getIpAddress();
}
#Override
protected void onPostExecute(String ipAddress) {
if (this.network.isConnected()){
wifiTextView.setText(R.string.wifi_is_on);
wifiTextView.setTextColor(Color.GREEN);
ipTextView.setText(ipAddress);
else {
wifiTextView.setText(R.string.wifi_is_off);
wifiTextView.setTextColor(Color.RED);
ipTextView.setText("N/A");
}
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
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.
What can I do, if I'm in any Activity and I want download a file (using thread) and at same time I want the main thread waits until download is finished?
Use AsyncTask.. from activity
new DownloadTask(this).execute();
The task for example:
public class DownloadTask extends AsyncTask<Void, Void, String> {
private ProgressDialog progressDialog;
private Context context;
/**
*
* #param context
* #param pdfDoc the document of the PDF
*/
public DownloadTask(Context context) {
this.context = context;
progressDialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
progressDialog.setMessage("Downloading...");
progressDialog.setIndeterminate(true);
progressDialog.show();
}
#Override
protected String doInBackground(Void... arg0) {
//download here
}
#Override
protected void onPostExecute(final String result) {
progressDialog.dismiss();
}
}
Use AsyncTask and callbacks.
public interface DownloadCallback<T>{
public void onFinishDownload(T downloadedResult);
}
public static void downloadString(String url, DownloadCallback<String> callback){
new AsyncTask<Void,Void,Void>(){
String result;
#Override
protected void onPreExecute() {
// Do things before downloading on UI Thread
}
#Override
protected String doInBackground(Void... arg0) {
//download here
result = download(url);
}
#Override
protected void onPostExecute(final Void result) {
// Do things on UI thread after downloading, then execute your callback
if (callback != null) callback.onFinishDownloading(result);
}
}.execute();
}
And to use this, you just do this:
downloadString("http://www.route.to.your.string.com", new DownloadCallback<String>(){
public void onFinishDownloading(String downloadedResult){
Toast.makeText(YourActivityName.this, downloadedResult, Toast.LENGTH_SHORT).show();
}
});
If you want the thread to communicate with he main thread, telling that download is finished, use a handler
This code will help you understand it
MyHnadler handler;
onCreate(Bundle savedInstance)
{
setContent..
...
handler=new MyHandler();
new MyThread().start();
}
public class MyHandler extends Handler
{
#Override
public void handleMessage(Message message) {
switch (message.what) {
case 1: //....threading over
//write your code here
break;
case2 : //if you want to be notiifed of something else
..
}
public class MyThread extends Thread
{
#Override
public void run()
{
//run the threa
//and when over
Message msg=handler.getMessage();
msg.what=1;
handler.sendMessage(msg); //send the message to handler
}
}
}
As you can see the thread communicates with the UI thread via the Handler. In the above example, I have only sent any object from the thread to the UI thread. To do that just do msg.obj=your_obj in the thread. It can be any object. Hope this helps you:)
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.