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.
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
I am trying to display values inside ArrayList on single line textView one by one after some interval. How to achieve this without blocking the main thread?
I have written code which is able to do this with Thread.sleep but, after a few seconds of running, activity is getting crashed. I have used For Loop & Thread.sleep to iterate every ArrayList value after some interval.
When activity crashes, I am getting IndexOutOfBondException after a few seconds of running.
public void errorRepeater() {
Thread t = new Thread() {
#Override
public void run() {
// !isInterrupted()
while (!isInterrupted()) {
for (xz = 0; xz < errorList.size(); xz++) {
try {
Thread.sleep(2000); //1000ms = 1 sec
runOnUiThread(new Runnable() {
#Override
public void run() {
String sErrorList = errorList.get(xz);
String sErrorListOkBox = errorListOkBox.get(xz);
Log.i("MQTT sErrorList", sErrorList);
TextView tvC1HPLP = findViewById(R.id.errormsg);
tvC1HPLP.setText(sErrorList);
TextView tvok = findViewById(R.id.ok);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
t.start();
}
textView should display values inside ArrayList one by one without crashing activity.
Just for reference, you can try something like this.
// You can define those both textview globally.
TextView tvC1HPLP = findViewById(R.id.errormsg);
TextView tvok = findViewById(R.id.ok);
Handler mHandler = new Handler();
final Runnable runnable = new Runnable() {
int count = 0;
#Override
public void run() {
String sErrorList = errorList.get(count%errorList.size);
String sErrorListOkBox = errorListOkBox.get(count%errorListOkBox.size);
tvC1HPLP.setText(sErrorList);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
count++;
mHandler.postDelayed(this, 4000); // four second in ms
}
};
mHandler.postDelayed(runnable, 1000);
I am trying to simulate an sending msg progress .
The main idea is to colour the members who message sent to them, promote the status bar etc.. (gui changes ) all this with delay for each loop iteration.
The main problem is that everything is going inside the onClick listener and runing thread inside it wont help ): cause gui is changing only after delay is completed.
Any one may advice me how to do this simulation ?
send.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
for(int i=0; i<phoneNumbers.size(); i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
members.get(i).setBackgroundColor(Color.GREEN);
members.get(i).invalidate();
mProgressDialog.setProgress(i+1);
sentCount.setText(getString(R.string.msgSentCount) + (i+1));
if(i==12){
scroolView.animate().translationYBy(-50);}
}
}
});
Thanks you very much !
If I unserstood you right - fake progress + waiting time. First of all handlers a perferct to delay an output:
//Fake Progress
progress = new ProgressDialog(this);
open(this);
// Delay output
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
setData();
}
}, 6000);
in the function setData(), do the task you wanna run after
and progress bar for fake:
public void open(Activity activity) {
progress.setMessage("Fakeprogress, Data Mining...");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setIndeterminate(false);
progress.setCancelable(false);
progress.setMax(100);
progress.setProgress(10);
progress.show();
final int totalProgressTime = 100;
final Thread t = new Thread() {
#Override
public void run() {
int jumpTime = 0;
while (jumpTime < totalProgressTime) {
try {
sleep(60);
//System.out.println("********" + jumpTime);
jumpTime += 1;
progress.setProgress(0);
progress.setProgress(jumpTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
progress.dismiss();
}
};
t.start();
}
Finaly got it works with recursion !!!!
public static int counter=0;
public void runMother(final Handler handler)
{
if(counter==3)return;
handler.postDelayed(new Runnable() {
#Override
public void run() {
members.get(counter).setBackgroundColor(Color.GREEN);
counter++;
runMother(handler);
}
}, 1000*counter);
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.
I need to stop a Runnable from running when an image is clicked in my Android app. I'm running this Runnable repeatedly using ImageView.postDelayed():
r = new Runnable() {
public void run() {
imgview.setImageResource(imageArray[i]);
i++;
if (i >= imageArray.length) {
i = 0;
}
imgview.postDelayed(r, 20); // set to go off again in 3 seconds.
// imgview.setOnClickListener(this);
}
};
imgview.postDelayed(r, 20); // set first time for 3 seconds
But under certain conditions I want to stop it from running, after it's already started. Here's the full code for my activity:
public class MainActivity extends Activity {
int i = 0;
ImageView imgview, imgview2;
Handler handler = new Handler();
Runnable r;
MediaPlayer mMediaPlayer;
int[] imageArray = { R.drawable.f1, R.drawable.f2, R.drawable.f3,
R.drawable.f4, R.drawable.f5, R.drawable.f6, R.drawable.f7,
R.drawable.f8, R.drawable.f9, R.drawable.f10, R.drawable.f11,
R.drawable.f12, R.drawable.f13, R.drawable.f14, R.drawable.f15,
R.drawable.f16, R.drawable.f17, R.drawable.f18, R.drawable.f19,
R.drawable.f20, R.drawable.f21, R.drawable.f22, R.drawable.f23,
R.drawable.f24, R.drawable.f25, R.drawable.f26, R.drawable.f27,
R.drawable.f28 };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tapp_activity);
imgview = (ImageView) findViewById(R.id.imageView1);
mMediaPlayer = new MediaPlayer();
mMediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.water);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
imgview2 = (ImageView) findViewById(R.id.imageView2);
imgview2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(i==0)
{
mMediaPlayer.setLooping(true);
mMediaPlayer.start();
i=1;
r = new Runnable() {
public void run() {
imgview.setImageResource(imageArray[i]);
i++;
if (i >= imageArray.length) {
i = 0;
}
imgview.postDelayed(r, 20); // set to go off again in 3 seconds.
// imgview.setOnClickListener(this);
}
};
imgview.postDelayed(r, 20); // set first time for 3 seconds
}
else
{
i=0;
mMediaPlayer.stop();
imgview.setBackgroundResource(R.drawable.tapstill);
}
}
});
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mMediaPlayer.stop();
}
}
What can I change in my code so that my Runnable stops running in the else condition of my onClick() method?
You might try removing the callback.
imgview.removeCallbacks(r);
In order for this to work, though. you'd have to ensure that r is the same Runnable as the one you posted. You could do this by creating it once, possibly in onCreate. Since the Runnable doesn't have any dependency on the ClickListener anyway, this shouldn't be a problem.
You might also need to do some synchronization in order to prevent the case where you're removing a currently running callback, though, now that i think about it. The volatile boolean running idea is probably less complex overall.
You can control your run() method with a boolean flag:
boolean running = true;
...
r = new Runnable()
{
public void run()
{
if(running)
{
imgview.setImageResource(imageArray[i]);
i++;
if (i >= imageArray.length) {
i = 0;
}
imgview.postDelayed(r, 20);
}
};
}
If you set running = false later on, your thread will be idle and that's what you want.
You can do it by
Thread.stop();