I am trying to make a progress dialog that pop up while things are loading. I have figured out how to make dialog boxes appear and disappear and can change whats in them but I have multiple async tasks and want the dialog to appear when the first async task starts and then disappear when the last async tasks finishes.
Is there a way for the dialogs to know when all async tasks are complete for a given activity? I am having problems on how to approach this issue. Thanks for the help!
Here is a exact sample code which i used to acheive the same functionality.
public class LoginActivity extends Activity
{
public static String TAG = "Login_Activity: ";
private EditText usernameEditText;
private EditText passwordEditText;
private ProgressDialog progress_dialog;
private int taskCount = 0;
private void updateTaskCount(int value)
{
taskCount += value;
if(progress_dialog != null && taskCount == 0)
{
progress_dialog.dismiss();
}
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
usernameEditText = (EditText) findViewById(R.id.login_username);
passwordEditText = (EditText) findViewById(R.id.login_password);
progress_dialog = new ProgressDialog(this);
}
public void LoginClick(View view)
{
String URL = "http://SOME.com/api/Members?Username=" +
usernameEditText.getText().toString()+ "&Password=" +
passwordEditText.getText().toString();
progress_dialog.setMessage("Authenticating. Please wait...");
progress_dialog.setCancelable(false);
progress_dialog.show();
new AuthenticateUserFromServer().execute(URL);
updateTaskCount(1);
new NotifyWebService ().execute("some other url");
updateTaskCount(1);
}
protected void onDestroy()
{
progress_dialog.dismiss();
super.onDestroy();
}
#Override
protected void onPause()
{
progress_dialog.dismiss();
super.onPause();
}
private class AuthenticateUserFromServer extends AsyncTask <String, Void, String>
{
protected String doInBackground(String... urls)
{
return Utility.readJSONFromWebService(urls[0]);
}
protected void onPostExecute(String result)
{
// do other stuff
updateTaskCount(-1);
}
}
private class NotifyWebService extends AsyncTask <String, Void, String>
{
protected String doInBackground(String... urls)
{
return Utility.readJSONFromWebService(urls[0]);
}
protected void onPostExecute(String result)
{
// do other stuff
updateTaskCount(-1);
}
}
}
If you have multiple/separate classes for async tasks you can create a static utility class to keep track of and update count.
Related
I've read a lot of questions on AsyncTask problems of different kinds, but I seem not to find the problem I'm facing.
Android Studio insists on making my custom AsyncTask static with the following note:
This AsyncTask class should be static or leaks might occur
For that reason I've been trying on using WeakReference to the Activity the task runs in. Problem is that I want to use findViewById() in onPre and onPostExecute and I cannot to access the method.
I've found that:
weakReference.get().findViewById(R.id.dictionaryLoading).setVisibility(View.VISIBLE);
does not produce an error in Android Studio, but it crashes the app.
How to solve the problem of not accessing findViewById() in the custom static AsyncTask?
Code generally works if I get rid of weakReference and make AsyncTask it non-static
Here's my AsyncTask: (the empty while loop is there on purpose so it waits until the global variable has some data.
public static class LoadingDictionaryAsync extends AsyncTask<Void, Void, Void> {
private final WeakReference<MainScreenActivity> weakReference;
private LoadingDictionaryAsync(MainScreenActivity mainScreenActivity){
this.weakReference = new WeakReference<>(mainScreenActivity);
}
#Override
protected void onPreExecute() {
weakReference.get().findViewById(R.id.dictionaryLoading).setVisibility(View.VISIBLE);
weakReference.get().findViewById(R.id.dictionaryListView).setVisibility(View.GONE);
}
#Override
protected Void doInBackground(Void... voids) {
if (vocabulariesGlobal == null || vocabulariesGlobal.size() == 0) {
weakReference.get().loadDatabaseVocabularyToDictionary();
}
while (vocabulariesGlobal == null || vocabulariesGlobal.size() == 0) {
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
weakReference.get().loadDictionaryOnTheList(vocabulariesGlobal);
weakReference.get().findViewById(R.id.dictionaryLoading).setVisibility(View.GONE);
weakReference.get().findViewById(R.id.dictionaryListView).setVisibility(View.VISIBLE);
}
}
And that's how I am calling it:
LoadingDictionaryAsync loadingDictionaryAsync = new LoadingDictionaryAsync((MainScreenActivity)getParent());
loadingDictionaryAsync.execute();
EDIT:
I've tried with creating a separate file with the LoadingDictionaryAsync where static is not a problem anymore, but I still have problem with passing MainScreenActivity it, so findViewById() cannot be used.
What is the proper way of passing Activity? I want to pass it in onNavigationItemSelected() and onQueryTextChange() in SearchView?
Context mContext;
//IN onPostExecute(String s)
TextView tv =((Activity)mContext).findViewById(R.id.tvData);
Demo: Details in my class:
public class ParseUrl extends AsyncTask<String, Void, String> {
Context mContext;
public ParseUrl(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
//showProgessDialog();
}
#Override
protected String doInBackground(String... params) {
String s = "";
return s;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
TextView tv = ((Activity) mContext).findViewById(R.id.tvData);
tv.setText(s);
}
}
And Call AsyncTask in MainActivity with context is 'this' keyword:
String URL="url";
new ParseUrl(this).execute(URL);
I've fixed the problem in the following way:
Moved Async classes I've created to separate files.
Switched the use of WeakReference to Context
Preceded findViewById() with ((MainScreenActivity)context).
Called the AsyncTasks with MainScreenActivity.this
So the call is:
LoadingDictionaryAsync loadingDictionaryAsync = new LoadingDictionaryAsync(MainScreenActivity.this);
loadingDictionaryAsync.execute();
And now the AsyncTask class looks like the following:
public class LoadingDictionaryAsync extends AsyncTask<Void, Void, Void> {
private Context context;
public LoadingDictionaryAsync(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
((MainScreenActivity)context).findViewById(R.id.dictionaryLoading).setVisibility(View.VISIBLE);
((MainScreenActivity)context).findViewById(R.id.dictionaryListView).setVisibility(View.GONE);
}
#Override
protected Void doInBackground(Void... voids) {
if (((MainScreenActivity)context).vocabulariesGlobal == null || ((MainScreenActivity)context).vocabulariesGlobal.size() == 0) {
((MainScreenActivity)context).loadDatabaseVocabularyToDictionary();
}
while (((MainScreenActivity)context).vocabulariesGlobal == null || ((MainScreenActivity)context).vocabulariesGlobal.size() == 0) {
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
((MainScreenActivity)context).loadDictionaryOnTheList(((MainScreenActivity)context).vocabulariesGlobal);
((MainScreenActivity)context).findViewById(R.id.dictionaryLoading).setVisibility(View.GONE);
((MainScreenActivity)context).findViewById(R.id.dictionaryListView).setVisibility(View.VISIBLE);
}
}
I made a AsyncTask class with the following code
public class removeDialog extends AsyncTask<Void, Void, Void> {
Context c;
ProgressDialog asyncDialog;
String page;
public removeDialog(Context c, String page) {
this.c = c;
this.page = page;
asyncDialog = new ProgressDialog(c);
}
#Override
protected void onPreExecute() {
//set message of the dialog
asyncDialog.setTitle("Please wait");
asyncDialog.setMessage("Loading...");
asyncDialog.setCancelable(false);
//show dialog
asyncDialog.show();
if (page == "algemeneVoorwaarden") {
Intent intent = new Intent(c, algemeneVoorwaarden.class);
c.startActivity(intent);
}
if (page == "contact") {
Intent intent = new Intent(c, contactTest.class);
c.startActivity(intent);
}
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
//don't touch dialog here it'll break the application
//do some lengthy stuff like calling login webservice
return null;
}
#Override
protected void onPostExecute(Void result) {
//hide the dialog
asyncDialog.dismiss();
super.onPostExecute(result);
}
}
First time I tried:
on the first time I see an ProgressDialog, but the second time I want to open the activity I get nothing.
Second time I tried:
I get no ProgressDialog even the first time I try.
I execute my code in an AsyncTask class, code:
voorwaarden.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new removeDialog(c, "algemeneVoorwaarden").execute();
}
});
Does someone know why it isn't working? Please help me.
Your dialog will be dismissed as soon as it's shown, because your doInBackground is empty. Try adding a Thread.sleep() with a few seconds, just to simulate a delay.
Also, I suspect that the new activities you're starting will leave your dialog behind. So I would suggest you to test the code without these new activities for now.
public class RemoveDialog extends AsyncTask<Void, Void, Void> {
ProgressDialog asyncDialog;
public RemoveDialog(Context c) {
asyncDialog = new ProgressDialog(c);
}
#Override
protected void onPreExecute() {
//set message of the dialog
asyncDialog.setTitle("Please wait");
asyncDialog.setMessage("Loading...");
asyncDialog.setCancelable(false);
//show dialog
asyncDialog.show();
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
try {
Thread.sleep(3000);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
//hide the dialog
asyncDialog.dismiss();
super.onPostExecute(result);
}
}
I'm doing background things using AsyncTask. I have been knowing that operations are just executed parallelly in AsyncTask however don't know about when it starts.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lec_refer_room);
String subCode = null;
try{
System.out.println(subCode);
}catch(Exception e){
finish();
}
new GetRefer(subCode, page).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
// this is AsyncTask
}
I tried to finish activity when string subCode is null. However above code occurs exception in GetRefer().executeOnExecutor()
Does AsyncTask starts along with main thread?
Then how can I use try-catch with AsycTask?
I've created a sample to show to you how AsyncTask works hope it what you was asking for
public class TaskTest extends AsyncTask<String, Integer, Boolean> {
protected Boolean doInBackground(String... params) {
Boolean StringNull = false;
String subCode = params[0];
if (subCode == null){
StringNull = true;
}
return StringNull;
}
protected void onPostExecute(Boolean result) {
if (!result) {
System.out.println(subCode);
} else {
finish();
}
}
}
To execute it you have to do as follows :
TastkTest tasktest = new TaskTest();
tasktest.execute(subCode);
Edit (Final Code)
Inside of your onCreate()
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lec_refer_room);
String subCode = null;
TastkTest tasktest = new TaskTest();
tasktest.execute(subCode);
}
The InnerClass still the same.
Edit2
If you want to put it on onCreate() do as follows...
String subCode = null;
if(subCode==null){
finish();
}
You could call finish () in your onCreate() but it's not something you probably want to do as the user would have no idea why the Activity didn't start.
This article will help explain the way AsyncTask works: http://hiqes.com/androids-asynctask-explained/
I am new to android programming. I am developing a web crawler for which i am using a Async Task and it is working well.In order to keep user informed,i am using progress dialog. My problem is,if i use a Progress Dialog my program takes more time to execute and when i won`t use the progress dialog,it executes faster.
Done Work
OnCreate Method
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_results);
Intent intent = getIntent();
s1 = intent.getStringExtra("Number1");
s2 = intent.getStringExtra("Number2");
s3=intent.getIntExtra("selectedItem",0);
HttpAsyncTask asyncTask = new HttpAsyncTask();
asyncTask.execute();
}catch (Exception e)
{
messageBox("Exception",e.getMessage());
}
}
Async Task Class
private class HttpAsyncTask extends AsyncTask<List<String>, Integer, List<String>> {
private ProgressDialog dialog;
#Override
protected void onPreExecute()
{
dialog = new ProgressDialog(Results.this);
dialog.setIndeterminate(true);
dialog.setMessage("Please Wait");
dialog.setCancelable(true);
dialog.show();
super.onPreExecute();
}
#Override
protected List<String> doInBackground(List<String>... urls) {
//android.os.Debug.waitForDebugger();
// spinner.setVisibility(View.VISIBLE);
List<String>resultList=new ArrayList<String>();
try
{
if(isCancelled())
return resultList;
resultList=WebCrawlerClass.GetPost(s1,s2,s3);
}catch (Exception e)
{
messageBoxs("Error", e.getMessage());
}
return resultList;
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(List<String> result)
{
if(dialog.isShowing())
{
dialog.dismiss();
}
if(s3 == 2)
{
docListAdapter=new ListViewData(Results.this,result);
}
else {
docListAdapter = new NameNumListData(Results.this, result);
}
docList=(ListView)findViewById(R.id.listView2);
docList.setAdapter(docListAdapter);
super.onPostExecute(result);
}
#Override
protected void onCancelled() {
super.onCancelled();
this.cancel(true);
}
}
Am I missing something? Need help..
Thanks and Regards,
Abhinav
In you activity
// Start the progress dialog
..
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// dismiss the progress dialog
}
};
HttpAsyncTask asyncTask = new HttpAsyncTask(handler);
asyncTask.execute();
In your asynctask class
private class HttpAsyncTask extends AsyncTask<List<String>, Integer, List<String>> {
private Handler handler = null;
public HttpAsyncTask (Handler handler) {
this.handler = handler;
}
protected Void doInBackground(Void... params) {
//Perform your task
// When you know that task is finished , fire following code
if (null != handler) {
Message message = handler.obtainMessage();
message.obj = Any data you want to sent to the activity
message.what = 1 ; ( Optional )
handler.sendMessage(message);
}
}
Thus when sendMessage function is called from doInbackground.. your handleMessage in your activity will get triggered and then you should dismiss the progress dialog
Hope this will improve the performance issue what you are facing
Remove super.onPreExecute(); in onPreExecute() method and check .It might Help
Solution:
Okay,I've found the solution from your answers since your answers are not completely working
First we need to use Handler to post a Runnable to main/UI thread to run UpdateDisplay() and but define ProgressDialog under UIThread not other threads which was also crucial.
Here is the final code :
public final String RSSFEEDOFCHOICE = "http://www.deals2buy.com/rssgen/tech.xml";
public final String tag = "RSSReader";
private RSSFeed feed = null;
private Handler handler = new Handler();
private ProgressDialog dialog;
/** Called when the activity is first created. */
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
dialog = ProgressDialog.show(RSSReader.this, "Loading",
"Loading, please wait..");
Thread t = new Thread() {
public void run() {
feed = getFeed(RSSFEEDOFCHOICE);
handler.post(new Runnable() {
public void run() {
dialog.dismiss();
UpdateDisplay();
};
});
}
};
t.start();
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Problem :
When Android application first load, this is what happens :
Retrieving RSS content from Url and parse it into RSSFeed feed instance variable via getFeed(String url).
Showing these feeds to users in ListView via UpdateDisplay() method.
When these are happening, I wanted to show a ProgressDialog to users to notify them about system are retriving content like "Loading, please wait..." Once getFeed(String Url):RSSFeed is done, ProgressDialog will be dismissed and UpdateDisplay():void will be invoked.
So this is my first attempt :
public final String RSSFEEDOFCHOICE = "somewhere.xml"; //coming from http
public final String tag = "RSSReader";
private RSSFeed feed = null;
/** Called when the activity is first created. */
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
ProgressDialog dialog = ProgressDialog.show(RSSReader.this, "Loading...", "Loading, please wait");
feed = getFeed(RSSFEEDOFCHOICE);
dialog.dismiss();
UpdateDisplay();
}
And it doesn't show the ProgressDialog so it didn't work the way I want. Since I belived it is because ProgressDialog is continues progress, it should be handled by another Thread.
Here is my second attempt :
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
Thread t = new Thread()
{
public void run()
{
ProgressDialog dialog = ProgressDialog.show(RSSReader.this, "Loading...", "Loading, please wait");
feed = getFeed(RSSFEEDOFCHOICE);
dialog.dismiss();
}
};
UpdateDisplay();
}
It was okay till UpdateDisplay() since this method was handled by main thread and it wasn't waiting anything so I thought maybe I should have put it under t Thread after dialog.dismiss().
So I did this :
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
Thread t = new Thread()
{
public void run()
{
ProgressDialog dialog = ProgressDialog.show(RSSReader.this, "Loading...", "Loading, please wait");
feed = getFeed(RSSFEEDOFCHOICE);
dialog.dismiss();
UpdateDisplay();
}
};
}
But then debugger said at run-time : only the main thread which handles onCreate():void can reach and use View objects because it creates them.
Now, I am so messed up and feel like quitting programming.
Some one can help me :/
Thanks in advance.
You could use AsyncTask, thats exactly what its for. Since onPostExecute(Long result) is done on the UI thread, it wont crash when looking for View objects.
Here is a example taken from the asyncTask reference
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
What you want to do is obtain the RSS feed in doInBackground(), and then update the UI in onPostExecute.
In your onCreate() method, invoke the asyncTask.
new DownloadFilesTask().execute(url1, url2, url3);
Okay,I've found the solution from your answers since your answers are not completely working
First we need to use Handler to post a Runnable to main/UI thread to run UpdateDisplay() and but define ProgressDialog under UIThread not other threads which was also crucial.
Here is the final code :
public final String RSSFEEDOFCHOICE = "http://www.deals2buy.com/rssgen/tech.xml";
public final String tag = "RSSReader";
private RSSFeed feed = null;
private Handler handler = new Handler();
private ProgressDialog dialog;
/** Called when the activity is first created. */
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
dialog = ProgressDialog.show(RSSReader.this, "Loading",
"Loading, please wait..");
Thread t = new Thread() {
public void run() {
feed = getFeed(RSSFEEDOFCHOICE);
handler.post(new Runnable() {
public void run() {
dialog.dismiss();
UpdateDisplay();
};
});
}
};
t.start();
}
You have to run your request in another thread than the progressdialog. So try with
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
ProgressDialog dialog = ProgressDialog.show(RSSReader.this, "Loading...", "Loading, please wait");
Thread t = new Thread()
{
public void run()
{
feed = getFeed(RSSFEEDOFCHOICE);
dialog.dismiss();
UpdateDisplay();
}
};
}
And depending on what you do in update display you should run it in the UI thread.
Actually the best way would be to use AsyncTask.
However as a quick workaround you could do smth like this:
private Handler handler = new Handler();
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
Thread t = new Thread()
{
public void run()
{
ProgressDialog dialog = ProgressDialog.show(RSSReader.this, "Loading...", "Loading, please wait");
feed = getFeed(RSSFEEDOFCHOICE);
dialog.dismiss();
handler.post(new Runnable() {
public void run() {
UpdateDisplay();
}
});
}
};
}