I am trying to get the hang of the SwingWorker class but I am getting an unexpected behaviour I can not solve.
In my background() method, I am publishing an increasing counter which should be logged as the progress into console.
Somehow the chunks.getSize()-1 always print out 0 instead of the incremented counter variable I am providing using publish(counter). What am I doing wrong here?
SwingWorker sw = new SwingWorker<Boolean, Integer>() {
#Override
protected Boolean doInBackground() throws Exception {
int counter = 0;
for (TickerStatistics ticker : tickers) {
candleData.put(ticker.getSymbol(), rc.getCandlestickBars(ticker.getSymbol(), interval));
counter++;
publish(counter);
}
return true;
}
#Override
protected void done() {
System.out.println(candleData);
}
#Override
protected void process(List<Integer> chunks) {
System.out.println(chunks.size() - 1 + " / " + tickers.size());
}
};
Related
I have a ArrayList that I fetch from internet. Now I am performing the list retrieval using Handler postdelayed. Like below in the onCreate of the activity.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
lis_dat.remove(lis_dat.size() - 1);
if (gri_not_lis) {
rv_3r_ada.notifyItemRemoved(lis_dat.size());
} else {
rv_3r_2c_ada.notifyItemRemoved(lis_dat.size());
}
List<String> lis_of_dat;
int cou = 0, pos = lis_dat.size();
String gen_sta, gen_end, gen_mon;
if (yea) {
String[] mon_sym = new DateFormatSymbols().getMonths();
lis_of_dat = Arrays.asList(mon_sym);
} else {
int how_man;
if (lis_is_new) {
how_man = 500;
} else {
how_man = 15;
}
if (day_in_bet(sta, end) <= how_man) {
gen_sta = sta;
gen_end = end;
} else {
gen_sta = sta;
Calendar cal = Calendar.getInstance();
cal.setTime(db_han.con_dat(sta));
cal.add(Calendar.DATE, how_man);
gen_end = USE_DAT.format(cal.getTime());
}
lis_of_dat = gen_dat_in_bet(gen_sta, gen_end);
}
for (String dat : lis_of_dat) {
if (yea) {
Date date = get_mon_dat(dat, YEA.format(db_han.con_dat(sta)));
gen_sta = get_mon_fir_or_las_dat(date, true);
gen_end = get_mon_fir_or_las_dat(date, false);
gen_mon = dat;
} else {
gen_sta = dat;
gen_end = null;
gen_mon = mon;
}
add_to_lis(gen_sta, gen_end, gen_mon, pos, gri_not_lis);
pos++;
}
pos_f[0] = pos;
cou_f[0] = cou;
is_loa = false;
}
}, 1000);
Now my question is this 1000 milliseconds here may vary in different devices. On whom the UI will stay frozen. So what's the alternative of this. Instead of waiting for 1 sec how can I wait till the UI loading is complete and then I do the retrieval?
I could use AsyncTask but then the task will stay running till the task is complete even if I go to another activity. but i don't need the task running after onPause is called. So how do I do it?
You can use AsyncTask which running in separate thread, your keeps UI responsive . You can cancel it in onPause of Activity by calling **asyncTaskRunner.cancel(true) **
private class AsyncTaskRunner extends AsyncTask<String, String, String> {
private String resp;
ProgressDialog progressDialog;
#Override
protected String doInBackground(String... params) {
return resp;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(String... text) {
}
}
You can save instance of handler and then remove all call backs in
onPause of the activity.
private Handler handler = new Handler();
handler.postDelayed(() -> {
// do you task here
},1000);
#Override
public void onPause() {
super.onPause();
handler.removeCallbacksAndMessages(null); // this is important
}
And if you want something which do not freeze UI without any delay,
there you go
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Executors.newSingleThreadExecutor().submit(() -> {
// Do you task here without any delay it will not freeze the UI
});
}
You can also try this,
class MyThread implements Runnable{
#Override
public void run() {
// Your Task Here, put your all calculations Here
}
}
and then in onCrate()
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new MyThread());
and then in onPause() or onDestory()
executor.shutdownNow();// this will stop the thread instantly
Boolean timer = false;
#Override
protected Boolean doInBackground(String... params) {
// TODO Auto-generated method stub
downloadmanagerstart();
System.out.println("return");
boolean downloading = true;
while (downloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(download_id);
Cursor cursor = downloadManager.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor
.getInt(cursor
.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor
.getInt(cursor
.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if (cursor.getInt(cursor
.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false;
}
cursor.close();
publishProgress(bytes_downloaded, bytes_total);
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
final int bytes_downloaded = values[0];
System.out.println(bytes_downloaded
+ " Downloaded 1");
int bytes_total = values[1];
int dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);
String totaldownload_str = android.text.format.Formatter
.formatFileSize(MainActivity.this, bytes_downloaded);
current_tvm.setText(totaldownload_str);
mProgressBar.setProgress((int) dl_progress);
if (!timer) {
Thread thread = new Thread() {
#Override
public void run() {
t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
runOnUiThread(new Runnable() {
public void run() {
System.out.println(bytes_downloaded
+ " Downloaded 2");
}
});
}
}, 0, 1000);
}
};
thread.start();
timer = true;
}
}
As you can see I have put two System.out.println(bytes_downloaded+ " Downloaded 1"); in onProgress andSystem.out.println(bytes_downloaded+ " Downloaded 2"); inside a thread on onProgress. The vale of bytes_downloaded is always 0 inside the thread why is this happening. I wanted it to be sync every second with the value bytes_downloaded in onProgress. thanks in advance.
Its 0 because its a final variable. Once its set, it can't change. So it will always be what you initially set it to. If you want to pass data like that use a member variable of the class (with synchronization if necessary), not a final or method level variable.
Additionally, this approach isn't needed. onProgressUpdate is already run on the UI thread- that's the point of the function. Why would you want to delay the UI update more, and why would you use such a convoluted way of doing so? I think you really don't understand the concepts of how threads, timers, and AsyncTasks work, because this code makes 0 sense.
I am having a problem with getting the result from an asyncTask in a separate class. I have followed from a similar questions answer on here but I cant see where I have gone wrong.
My AsyncTask is in a separate class for easy calling, I needed to be able to have the notice that the asyntask had completed and then start the next activity.
I would welcome any help as I am not sure quite where I have gone wrong.
public class StartScreen extends Activity{
ProgressDialog pd;
CountDownTimer waitTimer;
public static final String APP_PREFERENCES = "AppPrefs";
SharedPreferences settings;
SharedPreferences.Editor prefEditor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_screen);
settings = getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE);
// getPreferences();
// prefEditor = settings.edit();
waitTimer = new CountDownTimer(2000, 300) {
public void onTick(long millisUntilFinished) {
//called every 300 milliseconds, which could be used to
//send messages or some other action
}
public void onFinish() {
//After 2000 milliseconds (2 sec) finish current
//if you would like to execute something when time finishes
pd = ProgressDialog.show(StartScreen.this,"Title","Detail text",true,false,null);
getPreferences();
}
}.start();
}
private void getPreferences() {
String UserName = settings.getString("UserName", null);
if (UserName != null) {
// the key does not exist
Intent intent=new Intent(StartScreen.this,InitialPreferences.class);
startActivity(intent);
} else{
//if (UserName.equals(UserName)){
// handle the value
dataTask();
//pd.dismiss();
}
}
private void dataTask() {
// TODO Auto-generated method stub
new DATATask(this).execute(new FragmentCallback(){
#Override
public void onTaskDone() {
startMainAct();
}
});
}
private void startMainAct() {
Intent intent=new Intent(StartScreen.this,MainActivity.class);
startActivity(intent);
}
public interface FragmentCallback {
public void onTaskDone();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.start_screen, menu);
return true;
}
}
AsyncTask:
public class DATATask extends AsyncTask<Void, Void, ArrayList<String>> {
private FragmentCallback mFragmentCallback;
public void execute(FragmentCallback fragmentCallback) {
mFragmentCallback = fragmentCallback;
}
ArrayList<String> arr_data=new ArrayList<String>();
private Context context;
public DATATask(Context context)
{
this.context = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected ArrayList<String> doInBackground(Void... params) {
Document docVts, docTide;
String shippingList, tideTimes;
try {
docVts = Jsoup.connect("https://vts.mhpa.co.uk/main_movelistb.asp").timeout(600000).get();
Elements tableRows = docVts.select("table.dynlist td:eq(0),td:eq(1),td:eq(3),td:eq(4),td:eq(7),td:eq(8)");
tableRows.size();
for(int i = 1; i < 80; i++){//only allows x results from vts list, from 1 not 0. 0 produces needless results
shippingList = tableRows.get(i).text().replaceAll(" | ", "") +"\n";
arr_data.add(shippingList);// add value to ArrayList
System.out.println(shippingList);
};
docTide = Jsoup.connect("http://www.mhpa.co.uk/search-tide-times/").timeout(600000).get();
Elements tideTimeOdd = docTide.select("div.tide_row.odd div:eq(0)");
Elements tideTimeEven = docTide.select("div.tide_row.even div:eq(0)");
Elements tideHightOdd = docTide.select("div.tide_row.odd div:eq(2)");
Elements tideHightEven = docTide.select("div.tide_row.even div:eq(2)");
Element firstTideTime = tideTimeOdd.first();
Element secondTideTime = tideTimeEven.first();
Element thirdTideTime = tideTimeOdd.get(1);
Element fourthTideTime = tideTimeEven.get(1);
Element firstTideHight = tideHightOdd.first();
Element secondTideHight = tideHightEven.first();
Element thirdTideHight = tideHightOdd.get(1);
Element fourthTideHight = tideHightEven.get(1);
System.out.println("first tide time: " + firstTideTime.text() + " " + firstTideHight.text());
System.out.println("second tide time: " + secondTideTime.text() + " " + secondTideHight.text() );
System.out.println("third tide time: " + thirdTideTime.text() + " " + thirdTideHight.text());
System.out.println("fourth tide time: " + fourthTideTime.text() + " " + fourthTideHight.text());
{
/*
Work with data - all is OK
*/
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return arr_data;//<< return ArrayList from here
}
#Override
protected void onPostExecute(ArrayList<String> result) {
mFragmentCallback.onTaskDone();
}
}
Thanks for any help.
You are not calling the correct AsyncTask.execute(). The correct execute will invoke the onPreExecute() then doInBackground() then onPostExecute().
new DATATask(this).execute(new FragmentCallback(){
#Override
public void onTaskDone() {
startMainAct();
}
});
}
will call this method (the wrong one):
public void execute(FragmentCallback fragmentCallback) {
mFragmentCallback = fragmentCallback;
}
What you want to do is change this method to - setFragmentCallBack(FragmentCallback);
Then in the OnPostExecute() add this: startMainAct();
instead of doing this:
#Override
public void onTaskDone() {
startMainAct();
}
After this is done, then call the new DATATask(this).execute();
which will invoke the preExecute(), doInbackground, and PostExecute()
What you are doing is adding the FragCallback to the DataTask and not invoking the correct execute function.
I hope this helps.
Actually you did not execute your AsyncTask. You should call "super.execute(Params... params);" in you overloaded execute(FragmentCallback) method.
In your Activity:
DataTask dataTask = new DataTask();
dataTask.execute();
In your AsyncTask class:
onPostExecute(){
//put your intent to start the activity or whatever you want to do when it finishes
}
I think it is much simpler than you are making it. Hope that helps. Also, see AsyncTask Android example
You didn't execute the AsyncTask. Calling DATATask.execute(FragmentCallback) will just assign the callback to your task. You need to call either AsyncTask#execute(Runnable), AsyncTask#execute(Params...) or AsyncTask#executeOnExecutor(Executor exec, Params... params).
Also, I would pass the callback to DATATask via the constructor or a setter, instead of creating a new overloaded execute(FragmentCallback) method. It can easily confuse people.
This is one of my first apps, and I don't know what I have to do.
package com.example.stopuhr;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public int hs, sek, min;
public boolean running = false;
public String mode = "gestoppt";
public void setLabelText(){
TextView textView1 = (TextView)findViewById(R.id.textView1);
String ht = "";
String st = "";
String mt = "";
if (hs<10){
ht = "0" + hs;
}else{
ht = String.valueOf(hs);
}
if (sek<10){
st = "0" + sek;
}else{
st = String.valueOf(sek);
}
if (min<10){
mt = "0" + min;
}else{
mt = String.valueOf(min);
}
textView1.setText(mt + " : " + st + " : " + ht);
}
public void onClickStart (View view){
Thread timer = new Thread(){
Here's are the first errors
Multiple markers at this line
- Syntax error, insert "}" to complete ClassBody
- Syntax error, insert ";" to complete ConstructorDeclaration
- Syntax error, insert ";" to complete BlockStatements
- Return type for the method is missing
- Syntax error, insert ")" to complete ConstructorDeclaration
runOnUiThread(new Runnable() {
public void run(){
if (mode.equals("gestoppt")){
running = true;
mode = "läuft";
while (running){
try{Thread.sleep(9);}
catch(Exception e){}
if(hs<=99){
hs++;
}else{
hs = 0;
if(sek<=59){
sek++;
}else{
sek = 0;
}
if(min<=99){
min++;
}else{
min = 0;
}
}
}
setLabelText();
}
}
Here is the second mistake:
Syntax error on token "}", MethodHeaderName expected
I don't know what I have to do with this error.
});
};
timer.start();
}
public void onClickStop (View view){
if (mode.equals("läuft"));
running = false;
mode = "gestoppt";
}
public void onClickReset (View view){
if(mode.equals("gestoppt")){
hs = 0;
sek = 0;
min = 0;
setLabelText();
}
}
}
Thank you for your help.
In your code you have:
public void onClickStart (View view){
Thread timer = new Thread(){
runOnUiThread(new Runnable() {
public void run() {
...
}
});
};
}
The problem here is that you have the call runOnUiThread just inside a class - not in a method. In general you seem to be confused with threads, runnable and runOnUi. There's no point starting a new thread if you then want to invoke its run method on UI thread. The only thing you need to do on the UI thread is update the label text. Without going through your logic, one way of fixing the syntax errors would be:
public void onClickStart (View view) {
Thread timer = new Thread(){
public void run() {
...
runOnUiThread(new Runnable() {
public void run() {
setLabelText();
}
}
};
timer.start();
}
Finally, note that this is not the best way of performing this kind of logic. An AsyncTask with onProgressUpdate seems to me a much better solution.
I think it is better to put your functionality into a method in the MainActivity class:
private void doMyOperation() {
runOnUiThread(.....);
}
and call that method in your thread.
It looks like there is a Thread.sleep in your code that is blocking the UI. This might stop the UI from updating.
I'm trying to create an async task to handle a whole bunch of database entries and then let the user know that the entry has been made with a textView that appends to itself. I understand that I cannot touch the views inside the doInBackground, but I cannot get any other methods to work. Can anyone explain to me on how to get my code to work inside of an AsyncTask?
Code:
private class DBADDITION extends AsyncTask<Object, Void, Object> {
#Override
protected String doInBackground(Object... params) {
DBAdapter my_database = new DBAdapter(getApplicationContext());
logout.append("\n" + "Start" + " ");
my_database.open();
String temp = input.getText().toString();
int i = Integer.parseInt(temp);
for (int j = 1; j <= i; j++) {
db.createEntry("example", 10 + j);
logout.setText("\n" + j + logout.getText());
}
db.close();
return "it worked";
}
protected void onProgressUpdate(Integer... progress) {
}
}
You need to override the onPostExecute() method. This is automatically called after the doInBackground() method. Also this is on the UI thread and hence you can modify your textView here.
In case , you need to perform some UI updation before the doInBackground() then you override the onPreExecute() method.
Also, remove instances of any UI element updation from your doInBackground() like setText()
You use Activity.runOnUIThread() to setText, like these:
private class DBADDITION extends AsyncTask<Object, Void, Object> {
#Override
protected String doInBackground(Object... params) {
DBAdapter my_database = new DBAdapter(getApplicationContext());
logout.append("\n" + "Start" + " ");
my_database.open();
final String temp = input.getText().toString();
int i = Integer.parseInt(temp);
for (int j = 1; j <= i; j++) {
db.createEntry("example", 10 + j);
youractivity.this.runOnUiThread(new Runnable() {
public void run() {
logout.setText("\n" + j + logout.getText());
}
);
}
db.close();
return "it worked";
}
protected void onProgressUpdate(Integer... progress) {
}
}
logout.setText()
You can not perform operation on UI from a different Thread. All the UI Operations have to be performend on the UI thread. Since logout is a TextView object, you can not touch it directly from the doInBackground method, since it runs on a different Thread. YOu should use a Handler instance or, you have a reference to your Activity, you should call runOnUiThread. runOnUiThread allows you to post a Runnable on the looper queue of the UI Thread, without the need to instantiate an Handler.
final int finalJ = j;
runOnUiThread(new Runnable() {
public void run() {
logout.setText("\n" + finalJ + logout.getText());
}
});
runOnUiThread(new Runnable() {
public void run() {
logout.append("\n" + "Start" + " ");
}
});