I have a method which is list my items from a server. Therefore, this method takes time until getting all the items. So I want to use ProgressDialog for waiting this method. I read some modules but I couldnt find any useful solution.
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// setContentView(R.layout.main;
loginScreen();
}
public boolean getItems() throws MessagingException
{
items receiving here
}
public void loginScreen()
{
setContentView(R.layout.main);
Button loginBtn = (Button) findViewById(R.id.btnLogin);
loginBtn.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View arg0)
{
getItems();
}
}
}
On button Click I call the method which received all items. When I click the button I want to show a progressbar until all items getting.
create an AsyncTask which shows an ProgressBar on getItems(). You need an AsyncTask because the main Thread will be busy fetching stuff from server and ProgressBar won't show up untill that is finished.
Related
im using asyncTask to showing a download progress , my download will be done by a library named "file-downloader" in my main activity.
it's github page is "https://github.com/wlfcolin/file-downloader"
my custom dialog shows when i click to my specified button , and download task and progressBar starts when i press download button in this custom dialog
all thing is ok and progressBar works fine.
but when i dismiss this dialog and another time i invoke this dialog the progressBar does not work !
i save download status in database using the fileDownloader library listeners and anothe time i invoke custom dialog it read from database
and detect downloadProgress is currently running but we see no changing in custom dialog's progressBar , what is the problem ?
activity code
public class MainActivity extends AppCompatActivity {
/*
/
/ some variables
/
*/
public static int downloadedFile2SizePercent = 0 ; // downloaded file percent
public static int downloadingFileStatus = 0; // downloading status
Button myBtn ;
DownloadDialog dd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
myBtn = (Button)findViewById(R.id.button22);
myBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dd = new DownloadDialog(mContext,1);
dd.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dd.show();
}
});
/*
/ downloadingFileStatus value manages here by file downloader listeners correctly and saves as static variable and also in database
/ downloadedFile2SizePercent value manages here by file downloader listeners correctly and saves as static variable
/
*/
}
}
DownloadDialog Class
public class DownloadDialog extends Dialog implements View.OnClickListener{
public Context c;
public Button download, delete;
private ProgressBar pb;
ProgressTask progressTask;
private int downloadStatus;
private String downloadLink;
private int downloadID
public DownloadDialog(Context a, int downloadId) {
super(a);
this.c = a;
this.downloadId = downloadId
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.download_dialog);
download = (Button) findViewById(R.id.downloaddialot_downloadbtn);
delete = (Button) findViewById(R.id.downloaddialot_deletebtn);
download.setOnClickListener(this);
delete.setOnClickListener(this);
pb = (ProgressBar)findViewById(R.id.progressBar);
pb.setMax(100);
pb.setProgress(0);
//database is opend at mainActivity it's static
downloadStatus=Integer.parseInt(MainActivity.prDb.intSearch(downloadId));// detects download status --> 0 is "notDownloadedYet" and
// 1 is "downloading" and 2 is "downloaded"
downloadLink= MainActivity.puDb.intSearch(downloadId);//detects download link
progressTask = new ProgressTask();
if(downloadStatus==1){
pb.setProgress(MainActivity.downloadedFile2SizePercent);//this code line works every 2nd and after dialog invoking
progressTask.execute(true);
Toast.makeText(c,"test task progress for 2nd started", Toast.LENGTH_SHORT).show();//this code line works every 2nd and afterdialog invoking
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.downloaddialot_downloadbtn:
FileDownloader.start(downloadLink); // download task starts here
progressTask.execute(true);
Toast.makeText(c,"download task progress for 1nd started", Toast.LENGTH_SHORT).show();
break;
case R.id.downloaddialot_deletebtn:
if(downloadStatus==2){
// delete codes
}
break;
}
}
public class ProgressTask extends AsyncTask<Boolean, Integer, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Boolean... params) {
while (MainActivity.downloadedFile2SizePercent!=100){
publishProgress(MainActivity.downloadedFile2SizePercent);
}
if(MainActivity.downloadedFile2SizePercent==100){
publishProgress(MainActivity.downloadedFile2SizePercent);
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
pb.setProgress(values[0]);
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
downloadStatus=2; //also saves in database by download listeners in mainActivity
}
}
}
The progress bar just like any other UI element can only be managed or updated from the main UI thread.
It is the time consuming task the part that should be run in a AsyncTask, then this task can save the progress status in a volatile variable and then the UI thread can periodically update the progress bar reading the volatile variable, for example using a timer.
You can read all about AsyncTask here: https://developer.android.com/reference/android/os/AsyncTask.html
But here's my quick example/tutorial:
private class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// prepare your UI for the background task beginning
}
#Override
protected Void doInBackground(Void... params) {
// do some long-running task...
// you can do partial updates like:
publishProgress(25);
/* more hard work */
publishProgress(50);
/* even more hard work */
publishProgress(75);
// and when you're done...
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// update your UI with the current progress (values[0])
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// update your UI now that it's done
}
}
The key concept to understand regarding AsyncTask is that every method except doInBackground() is executed on the UI thread (the main thread). That means you are free to update your UI from these calls.
doInBackground(), however, is executed on a different thread. That means you can do expensive work here without slowing down your app's user interface.
Of course, all the hard work you're doing on that background thread needs to make its way to the UI thread somehow (so that you can use it). That's what publishProgress() and the return statement of doInBackground() are for. When you call publishProgress(someValue), the system will invoke onProgressUpdate(someValue) for you. When you return someValue, the system will invoke onPostExecute(someValue) for you.
I am doing an android app for a school project. I have made an AsyncTask within my main acticity that fetches data from the internet. I want this to be executed at 23:00 every day, and also when the user first installs and opens the app. I have searched online and tried ScheduledExecutorService, AlarmManager and TimerTask but I either run into trouble compiling my code or the application crashes on start. I am hoping for some help to get this working. Would really appreciate some concrete examples on how to schedule my AsyncTask.
I am currently running the AsyncTask when clicking on a button, but want to remove the button and run the task on a schedule.
Thank you in advance!
public class MainActivity extends AppCompatActivity {
private TextView ViewT;
private TextView ViewR;
private String deg;
private String rainD;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button1);
ViewT = (TextView) findViewById(R.id.ViewT);
ViewR = (TextView) findViewById(R.id.ViewR);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new getData().execute();
ViewR.setText(rainD);
ViewT.setText(deg);
}
});
}
public class getData extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
//fetching data here....
}
}
}
Edit:
I tried this today and the application does not crash but nothing shows up on my textviews either.
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final Runnable updateUI = new Runnable() {
#Override
public void run() {
new getData().execute();
ViewR.setText(rainD);
ViewT.setText(deg);
}
};
scheduler.scheduleAtFixedRate(updateUI, 5,
60*60*24, TimeUnit.SECONDS);
I'm trying to pass the callback action of a button from the main activity to an AsyncTask class. For now i just pass the Button in the constructor of the AsyncTask class and i do it directly in there:
public AsyncTaskClass(Button btnOk){
this.btnOk = btnOk;
}
#Override
protected void onPreExecute() {
btnOk.setOnClickListener(btnOkListener);
Log.i("AsyncTask", "onPreExecute");
}
private View.OnClickListener btnOkListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
//things to do
}
};
#Override
protected Boolean doInBackground(Void... params) { //etc
Is this good practice? Is there a better way of doing it, perhaps by using an external CallBack Interface? If so, how it can be made? Thank you for your time!
You never, ever pass views, fragments, activities, etc as parameters to threads. The lifecycle of Android can make you nasty surprises like, instances of views, that are not related to any UI container, since it has been replaced by other from the stack. Anyway a callback from click event will always arrive in the UI thread. So either you start the asynch task from onClick() which is simple. Or if in your case, the task is already alive you can call it from the onClick(). But the Asynch task should never know that there is a button!
MyTask myTask;
class MyTask extends AsyncTask{
private boolean shouldDoTheStuff = false;
public synchronized void doSomeStuff(){
shouldDoTheStuff = true;
}
protected synchronized Boolean doInBackground(Void... params) {
while(true){
Thread.sleep(200);
if(shouldDoTheStuff){
//react to the click
shouldDoTheStuff = false;
}
}
}
}
private View.OnClickListener btnOkListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
myTask.doSomeStuff();
}
};
Instead of synchronized you can use AtomicBoolen, which is more clean way.
I have following sample code to understand the TextView update
public class MainActivity extends Activity
{
int i=0;
private ImageButton btnMain;
private TextView txtText;
Context mycont=null;
public void myJob(final String cmd)
{
//txtText.setText(cmd);
runOnUiThread(new Runnable()
{
#Override
public void run() {
txtText.setText(cmd); //---Does not update the TextView here on Main UI
}
});
//----------- Long Work(Take around 15 seconds to complete) ----------
for(i=0;i<=1000000000;i++)
i++;
for(i=0;i<=1000000000;i++)
i++;
//--------------------------------------------------------------------
//---Update the TextView here once above Long work is executed
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mycont=this;
txtText = (TextView) findViewById(R.id.txtText);
txtText.setMovementMethod(new ScrollingMovementMethod());
btnMain = (ImageButton) findViewById(R.id.btnJob);
btnMain.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
myJob("Display this msg");
}
});
}
}
TextView is not updating on time, its waiting for other procedure to execute.
Please point me in right direction. I want to Update the TextView in the beginning of the myJob() function.
Look at this link: How will UI changes be processed in the onClickListener before starting a new activity in Android?
"Changes to UI elements are not executed immediately. They're executed the next time the UI loop runs, which is after you release control."
I would suggest you look into AsyncTasks. They allow you to perform actions before and after doing a timeconsuming job. In your case your AsyncTask would look somewhat like this:
private class LongJob extends AsyncTask<Void, Void, Void> {
TextView textViewToChange;
public LongJob(TextView text){
textViewToChange = text;
}
protected void onPreExecute(){
// Executed on main(UI) thread
textViewToChange.setText("Some random text here");
}
protected Long doInBackground(Void... params) {
// Your long job here, executed on background thread so
// it won't freeze your application.
return null;
}
protected void onPostExecute(Void result) {
// Executed on main(UI) thread
textViewToChange.setText("Text for after your job completed");
}
}
If I understand correctly, you want to update the textview, then run the Long Work. In that case do something like this:
public void myJob(final String cmd)
{
txtText.setText(cmd);
txtText.post(new Runnable() {
#Override
public void run() {
//----------- Long Work(Take around 15 seconds to complete) ----------
for(i=0;i<=1000000000;i++)
i++;
for(i=0;i<=1000000000;i++)
i++;
//--------------------------------------------------------------------
}
});
}
Note: In either case, your long work is running on the UI thread.. because you have never created a background task
Thanks to Amulya and Sander.
Both the solutions worked for me.
But as per my need, i will go for the solution by Amulya which is lightweight.
I was already aware of Android AsyncTasks.
But never thought of using in this way.
Thanks to both of you
friends,
i am using following code to fill android listview asynchronously
now problem is while running this thread i press back button or home button and comes back to activity
multiple threads are started....
can i avoid these multiple threads
actually i want if thread is running then it should not get called again and again.
it should be called when previous thread is complete.
private static String[] items={.......};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setListAdapter(
new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
new ArrayList()));
AddStringTask test= new AddStringTask();
test.execute();
}
class AddStringTask extends AsyncTask<Void, String, Void> {
#Override
protected Void doInBackground(Void... unused) {
for (String item : items) {
publishProgress(item);
SystemClock.sleep(1000);
}
return(null);
}
#Override
protected void onProgressUpdate(String... item) {
((ArrayAdapter)getListAdapter()).add(item[0]);
}
#Override
protected void onPostExecute(Void unused) {
Toast
.makeText(AsyncThread.this,
"Done - Finished updating Java Book List!",
Toast.LENGTH_SHORT)
.show();
}
}
}
any useful solution?
thanks in advance.
You can intercept the Activity Closing by overriding onStop() or onPause() or even onBackPressed() and terminate the update when it does...
If you don't wish to terminate it and instead just want NOT to initiate it again, just use static variables (or any other method) such that the test variable is created only once...
To terminate a AsyncTask, i believe there's a cancel() method...Use true as its parameter.
From API Reference
final boolean cancel(boolean mayInterruptIfRunning)
//Attempts to cancel execution of this task.