I seem to be going round in circles.
I have some code that even on a Galaxy S3 takes a few seconds to run. Drags data from database.
I want to add a progress bar popup (spinning circle) around this to give the user that the app is doing something.
I have tried Asyntasks elsewhere in app and work fine but for this type the main UI is not waiting for the Asyntask to finish before moving on and so the new activity that is called does not have all the data it needs and crashes.
Is AsyncTask the best way round this or is there an easier way to Puase the main Activity, show a progress bar and then move on once the long deley has been completed.
Thanks for time
UPDATE
public class UpdateDetailsAsyncTask extends AsyncTask<Void, Void, Boolean> {
private Context context;
private TaskCallback callback;
private ArrayList<Object> object;
private ProgressDialog progress;
public UpdateDetailsAsyncTask (
Context pContext,
ArrayList<Object> pObject,
TaskCallback pCallback) {
context = pContext;
callback = pCallback;
object = pObject;
}
#Override
protected void onPreExecute() {
Log.i("AsyncTask", "onPreExecuted");
progress = new ProgressDialog(context);
progress.setMessage(context.getResources().getString(R.string.loading));
progress.show();
}
#Override
protected Boolean doInBackground(Void... params) {
Log.i("Archery", "AsyncTask Excuted");
Log.i("Archery Scorepad", "Building Continue Round Details");
// Save Data to Database
return true;
}
protected void onPostExecute(Boolean result) {
Log.i("AsyncTask", "onPostExuted");
progress.dismiss();
callback.startNewActivity();
}
}
Task is called from main Activity
new UpdateDetailsAsyncTask(this, ArrayListOfObjects, this).exute();
UPDATE 2
..
UPDATE 3
The Code that does some work calls an a method within a Util Class which in calls a database class. I have log messages showing for all the rows of data I am saving to the database. It starts correctly and runs through it but the onPostExecute() appears to be called before the database method has completed.
Is my issue that I have nested classes within the activity and the task appears to have completed when the class below it has not?
Thanks
You must change to the next activity in onPostExecute from Asyntask
Yes!
Here is a simple code of AsuncTask
private class LoadImageAction extends AsyncTask<String, String, String>{
private Course course;
private ProgressBar pb;
public LoadImageAction(Course course, ProgressBar pb){
this.course = course;
this.pb = pb;
}
#Override
protected void onPreExecute(){
}
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
protected void onProgressUpdate(String... string){
}
#Override
protected void onPostExecute(String result){
}
}
You can run the action by
new LoadImageAction().execute();
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 have attached on click listener to a text view, inside on click listener a function say f1 is called and inside f1 another function say f2 is called.
Inside f2 I have created a android ProgressDialog object using current activity context, and called show function on progressDialog object. ProgressDialog takes time to appear on screen around 5-6 sec.
I have analyzed my code, but not able to understand why it takes this much time ?
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ShowSyncDialog(); - f1
}
});
public void ShowSyncDialog()
{
fnSyncOfflineData(); - f2
}
public void fnSyncOfflineData()
{
ProgressDialog progressDialog = new ProgressDialog(context);
progressDialog.show();
//other code
}
You should call your functions in an AsyncTask. Also ProgressDialog must be shown at the beginning of this works. Use something like this:
public class YourTask extends AsyncTask<String, Void, String> {
private Context mContext;
private ProgressDialog progressDialog;
public YourTask(Context context) {
super();
mContext = context;
progressDialog = new ProgressDialog(context);
progressDialog.setMessage("Your Message");
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.show();
}
#Override
protected String doInBackground(String... values) {
// If you want to use 'values' string in here
String values = values[0];
String yourResult = yourFunction();
return yourResult;
}
#Override
protected void onPostExecute(String result) {
progressDialog.dismiss();
// Your task has done
...
}
}
Then call this task with:
new YourTask(YourActivity.this).execute();
You can change return type of task doInBackground method. This is just an example, you can search about AsyncTask.
Good luck.
I know how to use AsyncTask to download file, create a zip file or so.. as I call publishProgress() in my loop.
I got stuck when doInBackground() has a single slow line, no loops here, just creating an object where its constructor has slow loops.
I'm not sure about the reasonable way of updating progress in such case.
Here's a sample code:
public class Session {
private QQActivity activity;
public int createdParts;
public DailyClass daily;
private void checkDaily() {
if(!isDailyReady){
new SetAsyncQQDaily().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
class SetAsyncQQDaily extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String sdq = null;
daily = new DailyClass(Session.this); //Very very Slow!
// Do other network http
sdq = new String(Base64.encode(bos.toByteArray(),Base64.DEFAULT));
// Do some work
return sdq;
}
#Override
protected void onPostExecute(String sdq) {
//Never mind
}
#Override
protected void onPreExecute() {
Toast.makeText(activity,"Preparing the daily. Get ready!",Toast.LENGTH_LONG).show();
}
#Override
protected void onProgressUpdate(Void... values) {
//TODO: Update Value of leftBar
activity.leftBar.setProgress((100*createdParts)/Utils.DAILY_PART_COUNT);
}
}
}
In the slow constructor class, I can set-back an integer of the current progress: createdParts, but cannot call publishProgress.
public class DailyClass implements Serializable {
public DailyClass(Session session){
for(int i=1;i<=partCount;i++ ){ //Very slow loop
session.createdParts = i; //TODO: reflect value to progress bar!?
for(int j=0;j<questionsCount;j++){
objects[i-1][j] = createDefined(i);
}
Log.d("Daily","created part"+i);
}
}
//Bla .. !
}
I also though of passing the object of the AsyncTask to the slow constructor in order to call publishProgress() from there, but cannot. As publishProgress() is accessible only from doInBackground()
What's the best practice?
I want my AsyncTask class to change the visibility of a TextView from my layout and I get a fatal error. If I want to get the text value of the TextView, it works fine, but when trying to set the visibility it just crashes.
// Main Activity (MainActivity.java)
Context MainContext= getApplicationContext();
new MyAsyncTask((TextView)findViewById(R.id.my_text_view)).execute();
// My Async Task (MyAsyncTask.java)
public class MyAsyncTask extends AsyncTask <String, Void, String> {
private Context context;
private TextView my_text_view;
public MyAsyncTask (TextView my_text_view){
this.context = MainActivity.MainContext;
this.txt_loading = my_text_view;
}
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
my_text_view.setVisibility(View.VISIBLE); // crashes
Log.i("Value: ", String.valueOf(this.my_text_view.getText())); // O.K.!
return null;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
How can I make it work? Also, can I get the TextView from the Context? I don't want to send it as a parameter to the constructor.
It crashes because you are manipuling with UI in background Thread. This is not allowed and you can't do it.
my_text_view.setVisibility(View.VISIBLE);
User Interface may be updated / changed only from original / main / UI Thread. AsyncTask provides some methods that actually runs on UI Thread.
These methods are exactly designated for reach your goal: to perform any UI update.
When you want to update UI from AsyncTask, you can use:
onPreExecute()
onProgressUpdate()
onPostExecute()
I'm using "include" on my main layout. Each one of them is a RelativeLayout which needs an OnClick listener to be attached, and update some information related.
So I've tried to do it simply by:
setContentView(R.layout.allobjects);
ObjectListeners objectListeners = new ObjectListeners(objects);
for(int i=0;i<1;i++)
{
RelativeLayout objectBoxRelativeLayout = (RelativeLayout)findViewById(R.id.object1 + i);
objectBoxRelativeLayout.setOnClickListener(objectListeners.GetObjectListener(i));
SomeObject currentObject = this.objects.get(i);
Object viewObject = findViewById(R.id.object1 + i);
this.setObjectView(viewObject, currentObject);
}
The issue is that it takes too long after the "setContentView(R.layout.allobjects);" command, and the application shows black screen until it finish loading.
In addition, I use "setContentView(R.layout.allobjects);" after I perform the above commands. All of these commands have to be written after "setContentView(R.layout.allobjects);".
How can I handle that kind of situation ? Do I have to use onPreExecute and implement AsyncTask ?
Yes, AsyncTask is good solution to show loading dialog while these commands being executed.
UPDATE:
Add this class under your onCreate() function:
private class MyTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog dialog;
private Context context;
public MyTask(Activity activity) {
context = activity;
dialog = new ProgressDialog(context);
}
protected void onPreExecute() {
dialog.setTitle("Loading...");
dialog.setMessage("Loading...");
dialog.show();
}
#Override
protected Void doInBackground(Void... params) {
//do your code here in background
protected void onPostExecute(Void res) {
dialog.dismiss();
}
}
then use the task inside onCreate() like this:
MyTask mt = new MyTask(this);
mt.execute();