I am trying to create an AsyncTask for following function:
private void updateStreamImageRequest() {
countDownTimer = new CountDownTimer(10000, 2000) {
#Override
public void onTick(long millisUntilFinished) {
imageRequest();
}
#Override
public void onFinish() {
countDownTimer.start();
}
};
}
I do not have much knowledge in AsyncTaskand I am struggling to make it work. The AsyncTask shall continueally run a get request.
So far I have done this so far but it does not work:
public void getImgAsync() {
new requestAsyncTask();
}
public class requestAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
countDownTimer = new CountDownTimer(10000, 2000) {
#Override
public void onTick(long millisUntilFinished) {
API_StreamImage_Request();
}
#Override
public void onFinish() {
countDownTimer.start();
}
};
return null;
}
}
So do it this way -
Create your Countdown timer that runs for 10 seconds. So it will finish after 10 seconds. Then in finish method call your Asynctask to fetch in background.
countDownTimer = new CountDownTimer(10000, 5000) {
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
new requestAsyncTask().execute();
}
};
countDownTimer.start();
class requestAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
countDownTimer.cancel();
countDownTimer.start();
}
#Override
protected Void doInBackground(Void... params) {
API_StreamImage_Request();
return null;
}
}
You might have to create a global variable of your countdown timer so that you can access it inside your asynctask class. Or you can even pass it as well if you want.
You can also use a Handler for this.
private int mInterval = 10000;
private Handler mHandler = new Handler();
Runnable requestCaller = new Runnable() {
#Override
public void run() {
try {
new requestAsyncTask().execute();
} finally {
mHandler.postDelayed(requestCaller, mInterval);
}
}
};
Or a Timer
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
new requestAsyncTask().execute();
}
},0, 10000);
Related
I'm trying to understand a right way to work with viewmodel & livedata.
I created a simple app which started timer when activity start.
When activity destroyed - timer continues running and on restart activity created a second timer and now we have two running timers - it's a potential memory leak ?
How a right way to stop our "task" on stop\destroy activity ?
My code:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding mActivityMainBinding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mActivityMainBinding.getRoot());
MainActivityViewModel mainActivityViewModel =
new ViewModelProvider(this).get(MainActivityViewModel.class);
Observer<Integer> liveDataObserver = integer ->
mActivityMainBinding.tvCounter.setText("Elapsed : "+integer+ " s");
mainActivityViewModel.getLiveData().observe(this, liveDataObserver);
getLifecycle().addObserver((LifecycleEventObserver) (source, event) ->
Log.d("mylog", event.name()));
} }
MainActivityViewModel .java
public class MainActivityViewModel extends ViewModel {
private MutableLiveData<Integer> mutableLiveData = new MainActivityLiveData<>();
private static int BEGIN_AFTER = 1000, INTERVAL = 5000;
private static int counter = 0;
public MainActivityViewModel() {
startTimer();
}
private void startTimer() {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Log.d("mylog", timer.toString() + " " + ++counter);
mutableLiveData.postValue(counter);
}
}, BEGIN_AFTER, INTERVAL);
}
public MutableLiveData<Integer> getLiveData() {
return mutableLiveData;
} }
MainActivityLiveData.java
public class MainActivityLiveData<T> extends MutableLiveData<T> {
#Override
protected void onActive() {
Log.d("mylog", "onActive");
}
#Override
protected void onInactive() {
Log.d("mylog", "onInactive");
}}
You need to stop the timer inside onClear() of viewModel. for that you have to make it a global variable .
public class MainActivityViewModel extends ViewModel {
private MutableLiveData<Integer> mutableLiveData = new MainActivityLiveData<>();
private Timer timer = new Timer();
private static int BEGIN_AFTER = 1000, INTERVAL = 5000;
private static int counter = 0;
public MainActivityViewModel() {
startTimer();
}
private void startTimer() {
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Log.d("mylog", timer.toString() + " " + ++counter);
mutableLiveData.postValue(counter);
}
}, BEGIN_AFTER, INTERVAL);
}
public MutableLiveData<Integer> getLiveData() {
return mutableLiveData;
}
#Override
protected void onCleared() {
super.onCleared();
stopTimer();
}
private void stopTimer(){
if(timer != null) {
timer.cancel();
timer.purge();
timer = null;
}
}
}
This question already has answers here:
Running code in main thread from another thread
(17 answers)
Closed 5 years ago.
I'm trying to dynamically update an android LinearLayout in the main thread.
Unfortunately I'm having a lot of trouble ascertaining anything from the tutorials online. None of them seem to provide a complete picture of how to communicate between threads.
My idea is something like this:
public class MainActivity extends AppCompatActivity {
private LinearLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new LinearLayout(this);
setContentView(layout);
Updater updater = new Updater();
Thread workerThread = new Thread(updater);
//somehow update layout
The updater class would look something like this:
public class Updater implements Runnable {
private int count = 0;
public Updater() {}
#Override
public void run()
{
for (int i = 0; i < 10; i ++){
try {
count++;
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I know I need a Handler in order to communicate messages between the threads, but I don't know how to set that up.
I would like to avoid anonymous classes, and dynamically create new TextViews whenever Updater has a new message.
create WorkerThreadListener interface:
public interface WorkerThreadListener {
void onUpdate(int counter);
}
Change your Updater class:
public class Updater implements Runnable {
private final WorkerThreadListener mWorkerThreadListener;
private final Handler mHandler;
private int count = 0;
public Updater(final WorkerThreadListener workerThreadListener) {
this.mWorkerThreadListener = workerThreadListener;
this.mHandler = new Handler();
}
#Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
count++;
mHandler.post(new Runnable() {
#Override
public void run() {
mWorkerThreadListener.onUpdate(count);
}
});
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Change MainActivity class:
public class MainActivity extends AppCompatActivity {
private LinearLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new LinearLayout(this);
setContentView(layout);
Updater updater = new Updater(new WorkerThreadListener() {
#Override
public void onUpdate(int counter) {
//update layout here
}
});
Thread workerThread = new Thread(updater);
workerThread.start();
}
}
Hi please check my below answer hope it helps you.
public class ProgressTestActivity extends Activity {
private ProgressBar progress;
private TextView text;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
progress = (ProgressBar) findViewById(R.id.progressBar1);
text = (TextView) findViewById(R.id.textView1);
}
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;
doFakeWork();
progress.post(new Runnable() {
#Override
public void run() {
// here you can add any view or anyof your logic which is related to UI put it into here.
text.setText("Updating");
progress.setProgress(value);
}
});
}
}
};
new Thread(runnable).start();
}
// Simulating something timeconsuming
private void doFakeWork() {
SystemClock.sleep(5000);e.printStackTrace();
}
}
Other ways are also possible.if you have any doubt please comment below post i will explain you in details.
If you just want to use a tick timer and set progress to ui thread . You can use CountDownTimer.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView textView;
private CountDownTimer countDownTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new);
textView = (TextView) findViewById(R.id.textView);
findViewById(R.id.b2).setOnClickListener(this);
}
public void processData() {
countDownTimer = new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
textView.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
textView.setText("done!");
}
}.start();
}
#Override
protected void onStop() {
super.onStop();
if (countDownTimer != null) {
countDownTimer.cancel();
}
}
#Override
public void onClick(View v) {
processData();
}
}
Apart from that to post a callback on UI thread you can use Handler .
Handler mainThreadHandler = new Handler(Looper.getMainLooper());
mainThreadHandler.post(new Runnable() {
#Override
public void run() {
}
});
This is the code i am working on. Here I cant update the UI until myOnResponse is finished.Because we are doing a doInBackgrnd, so my textresponse is empty. And Since onPostExecute is happening right after.
For his I think PublicProgres should help.
How to Call PublishProgress at AsyncTask ?
private class ConversationTask extends AsyncTask<String, Void, String> {
String textResponse = new String();
#Override
protected String doInBackground(String... params) {
System.out.println("in doInBackground");
MessageRequest newMessage = new MessageRequest.Builder().inputText(params[0]).context(context).build();
// async
GLS_service.message("xxxxxxxxx", newMessage).enqueue(new ServiceCallback<MessageResponse>() {
#Override
public void onResponse(MessageResponse response) {
context = response.getContext();
textResponse = response.getText().get(0);
action5(textResponse);
System.out.println(textResponse);
}
#Override
public void onFailure(Exception e) {
}
});
return textResponse;
}#Override protected void onPostExecute(String result) {
reply.setText(textResponse);
}
}
Please help.
I don't think that you have to use AsyncTask.
You can do something like this :
YourTask.java
public class YourTask implements Runnable {
private Handler handler;
private TextView textView;
public YourTask(TextView textView){
this.textView = textView;
handler = new Handler();
}
#Override
public void run() {
MessageRequest newMessage = new MessageRequest.Builder().inputText(params[0]).context(context).build();
GLS_service.message("xxxxxxxxx", newMessage).enqueue(new ServiceCallback<MessageResponse>() {
#Override
public void onResponse(MessageResponse response) {
final String textResponse = response.getText().get(0);
handler.post(new Runnable() {
#Override
public void run() {
if(textView != null){
textView.setText(textResponse);
}
}
});
}
#Override
public void onFailure(Exception e) {
}
});
}
}
And now how to use it :
SomeActivity.java
...
textView = (TextView) findViewById(R.id.textView);
...
Thread thread = new Thread(new YourTask(textView));
thread.start();
...
Nevertheless if you want to do this action in Asynktask just try this
private class ConversationTask extends AsyncTask<String, Void, Void> {
private Handler handler;
public ConversationTask(){
handler = new Handler();
}
#Override
protected Void doInBackground(String... params) {
MessageRequest newMessage = new MessageRequest.Builder().inputText(params[0]).context(context).build();
GLS_service.message("xxxxxxxxx", newMessage).enqueue(new ServiceCallback<MessageResponse>() {
#Override
public void onResponse(MessageResponse response) {
final String textResponse = response.getText().get(0);
handler.post(new Runnable() {
#Override
public void run() {
if(reply != null){
reply.setText(textResponse);
}
}
});
}
#Override
public void onFailure(Exception e) {
}
});
return null;
}
}
Hope it helps
I'm trying to update my digital clock using timertask. I have created a function called updateClock() which sets the hours and minutes to the current time but I haven't been able to get it to run periodically. From what I've read in other answers one of the best options is to use timertask however I haven't been able to make any example I found online work inside an Android activity.
This is what I've written so far:
public class MainActivity extends Activity {
TextView hours;
TextView minutes;
Calendar c;
int cur_hours;
int cur_minutes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.clock_home);
hours = (TextView) findViewById(R.id.hours);
minutes = (TextView) findViewById(R.id.minutes);
updateClock();
}
public void updateClock() {
c = Calendar.getInstance();
hours.setText("" + c.get(Calendar.HOUR));
minutes.setText("" + c.get(Calendar.MINUTE));
}
public static void init() throws Exception {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
updateClock(); // ERROR
}
}, 0, 1 * 5000);
}
}
How can I make it work?
Use runOnUiThread for updating Ui from Timer Thread
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
MainActivity.this.runOnUiThread (new Runnable() {
public void run() {
updateClock(); // call UI update method here
}
}));
}
}, 0, 1 * 5000);
}
if you just need updates every minute, you can also listen to the ACTION_TIME_TICK broadcast event.
private boolean timeReceiverAttached;
private final BroadcastReceiver timeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateClock();
}
};
private Handler handler = new Handler();
#Override
protected void onResume() {
super.onResume();
updateClock();
if (!timeReceiverAttached) {
timeReceiverAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
registerReceiver(timeReceiver, filter, null, handler);
}
}
#Override
protected void onPause() {
super.onPause();
if (timeReceiverAttached) {
unregisterReceiver(timeReceiver);
timeReceiverAttached = false;
}
}
OR, periodically post the Runnable to the Handler of UI thread. Also, pause and resume tasks to save battery.
public class MyActivity extends Activity {
private final Handler mHandler = new Handler();
private final Timer mTimer = new Timer();
#Override
protected void onResume() {
super.onResume();
mTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
//---update UI---
}
});
}
},0,5000);
}
#Override
protected void onPause() {
super.onPause();
mTimer.cancel();
}
}
I want to show a circle progressdialog when some functions run in backstage. so I write such a series of code:
pd = ProgressDialog.show(GridLayoutActivity.this, "","...");
new Thread(new Runnable() {
public void run() {
someFunc();
handler.sendEmptyMessage(0);// 执行耗时的方法之后发送消给handler
}
}).start();
But the progressDialog doesn't roll? why?
Try with Asynchronous task, here i post the example code, you may change as per you own
public class BackGround_Task extends AsyncTask<Void, Void, Void> {
private final ProgressDialog dialog = new ProgressDialog(
YourClassName.this);
// can use UI thread here
protected void onPreExecute() {
this.dialog.setMessage("Loading...");
this.dialog.setCancelable(false);
this.dialog.show();
}
#Override
protected Void doInBackground(Void... params) {
//Your Background Task
return null;
}
protected void onPostExecute(Void result) {
//What will you do after the completion of Background process
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
}
}
Just use something like this:
ProgressDialog progressDialog = new ProgressDialog(GridLayoutActivity.this);
progressDialog.setMax(100);
progressDialog.setProgress(0);
progressDialog.setMessage("...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show();
new Thread(new Runnable() {
public void run() {
someFunc();
handler.sendEmptyMessage(0);// 执行耗时的方法之后发送消给handler
}
}).start();
Send handler message after try block. Use like this:
pd = ProgressDialog.show(SetFrames.this,"Loading", "Please Wait...",true);
new Thread() {
public void run() {
try {
//your function
}catch(Exception e)
{
}
handler.sendEmptyMessage(0);
pd.dismiss();
}
}.start();
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
}
};