I have this code in my activity (LoadTask is an inner class):
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
ProgressDialog loading = new ProgressDiaolg(this);
...
}
public class LoadTask extends AsyncTask<Context, Void, Integer> {
ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
#Override
protected void onPreExecute() {
loading.show();
}
#Override
protected Integer doInBackground(Context... params) {
EventLoader el = new EventLoader(params[0]);
list = el.getMylist();
return el.getError();
}
protected void onPostExecute(Integer result) {
if (result == EventLoader.NO_HTTP_CONN) {
getErrorDialog(R.string.errore_caricamento, true).show();
} else if (result == EventLoader.ERR_JSON) {
getErrorDialog(R.string.errore_json, true).show();
} else if (result == EventLoader.ERR_NULL) {
getErrorDialog(R.string.errore_evento_null, true).show();
} else {
mainList=list;
Intent intent = new Intent(MainActivity.this, EventActivity.class);
intent.putExtra(Const.Tags.FULL_LIST, mainList);
loading.dismiss();
startActivity(intent);
}
}
}
the dialog works fine during the loading of the list, but here's my problem:
dismissing the dialog before startActivity(intent) will result in 2-3 seconds of no progress indicator while the new activity is created (there's a listview to be populated with a custom adapter) and before it is actually resumed, which is not very user friendly.
dismissing the dialog after startActivity(intent) will result in a rough disposal of the dialog (first goes the dimmed background, then it freezes... and so on). actually it's like not calling loading.dismiss() at all and letting it be destroyed with the activity.
Is there a smooth way for the ProgressDialog to be persistent through both the loading of the data and the creation of the new activity and eventually be dismissed when the new activity UI is ready to be shown?
If you want a smoother transition I would recommend you use fragments instead. Or you can make it slightly smoother by not populating the list view until onStart and making sure it's done on the background thread.
Related
I have an Activity with a tabbed UI in which I load 3 fragments through a ViewPagerAdapter.
1 fragment (called C) is a simple PreferenceFragment, 1 (B) is only a TextView the last one (A) extends Fragment and I use it to show a ListView containing all the installed packages on the devices.
When the user open the app, an AsyncTask in Fragment A loads the packages and it prepares the adapter to pass to the ListView. Moreover, I use a ProgressDialog in the AsyncTask to inform the users that the list is almost ready.
I leave you with some code:
Inner AsyncTask in fragment C:
private class AppListTask extends AsyncTask<Void, Integer, List<Map<String, Object>>> {
Context context;
public AppListTask(Activity context) {
this.context = context;
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(context);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setCancelable(true);
progressDialog.show();
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialogInterface) {
AppListTask.this.cancel(true);
}
});
}
#Override
protected List<Map<String, Object>> doInBackground(Void... voids) {
// get list of apps
progressDialog.setMax(list.size());
int nApps = 1;
for(ResolveInfo info : list) {
//work on info
nApps++;
publishProgress(nApps);
}
//return
}
#Override
protected void onProgressUpdate(Integer... progress) {
progressDialog.setProgress(progress[0]);
}
#Override
protected void onPostExecute(List<Map<String, Object>> items) {
if (progressDialog != null && progressDialog.isShowing()) {
if (!((Activity) context).isFinishing() && !((Activity) context).isDestroyed()) {
progressDialog.dismiss();
progressDialog = null;
}
}
//set adapter on list view
}
}
and I execute it from onActivityReady in Fragment C
private ProgressDialog progressDialog;
...
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (listAdapter == null || listAdapter.isEmpty()) {
new AppListTask(getActivity()).execute();
}
}
#Override
public void onPause() {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
super.onPause();
}
...
The problem is that on Note4 it works perfectly while on galaxy S5 happens something strange.
If I open the app the first time, as soon as the ProgressDialog is dismissed (in onPostExecute), the app is automatically closed without exceptions. At the second or third launch instead it works good.
If I do not use the ProgressDialog at all, it works good on first launch.
I also tried to use the ProgressDialog as setCancelable(false) but nothing changes.
I have an Activity that extends a ListActivity , in onCreate method i set the contentView and call an AsyncTask to load data and the list get filled as I want, the problem is when I check for example the detail activity and want go back the the listView: I get the onCreate method executed, data are loaded again and the listView is scrolled to the top loosing my previous position.
What I want to achieve is something like google gmail app for example: the list view get loaded once and the scroll position is saved.
I've looked so much over here and I tried many solutions but none is working.
What is the best way to achieve this scenario?
my activity :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
new LoadEvents().execute();
}
my asyncTask :
class LoadEvents extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(Home.this);
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
protected String doInBackground(String... args) {
List<NameValuePair> params = new ArrayList<NameValuePair>();
JSONObject json = jParser.makeHttpRequest(AgendaIConstantes.URL_EVENTS, "GET", params);
......Processing
eventList.add(map);
}
} else {
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String file_url) {
pDialog.dismiss();
runOnUiThread(new Runnable() {
public void run() {
ListAdapter adapterRes = getListAdapter();
if(adapterRes == null){
ListAdapter adapter = new SimpleAdapter(Home.this, eventList,R.layout.list_item,
new String[] { .....},
new int[] { .....});
setListAdapter(adapter);
}
}
});
}
Just do not execute your loading task every call of onCreate method. You can use either boolean flag in your activity or save state using onSaveInstanceState.
By the way, calling getListAdapter in onPostExecute is not very ok method and your null checking shows it.
I have two activities. While switching to second activity by intent, it takes 3-4 seconds because it has lots of components with adapters fetching data from SQLite etc. Thus, I want to show a progress dialog while switching.
I have been digging topics for this purpose and tried many of them:
1-) Using AsyncTask on the second activity. It doesn't show the progress dialog as soon as I click on a component to switch to the second activity. It waits for 3-4 seconds and then progress dialog shows up for less then a second which is not user-friendly way.
2-) Using AsyncTask on the first activity. It shows as soon as I click on that component but the progress wheel doesn't spin. The progress dialog freezes.
3-) Using AsyncTask onStart() method on the second activity. This results as the first way.
The code below implements the second way above, using AsyncTask on the first activity.
public void toVisitRegister(Event event) { //Switching to the second activity
new startingThread().execute();
Intent toVisitRegister = new Intent(MainCalendar.this, VisitRegister.class);
startActivity(toVisitRegister);
finish();
}
And here is the AsyncTask
public class startingThread extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
startingProgress = new ProgressDialog(MainCalendar.this);
startingProgress.setTitle("Visit Register");
startingProgress.setMessage("Initializing...");
startingProgress.show();
}
#Override
protected String doInBackground(String... params) {
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(MainCalendar.this.startingProgress != null) {
MainCalendar.this.startingProgress.dismiss();
}
}
}
I also tried to call startActivity in onPostExecute, but it didn't work. Therefore, I am waiting for your opinions and suggessions about this issue. Any help will be appreciated.
Thanks.
I also tried to call startActivity in onPostExecute,
Pass the Activity context to startingThread AsyncTask and put your start activity code in onPostExecute() of AsyncTask.
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(MainCalendar.this.startingProgress != null) {
MainCalendar.this.startingProgress.dismiss();
Intent toVisitRegister = new Intent(MainCalendar.this, VisitRegister.class);
mContext.startActivity(toVisitRegister);
mContext.finish();
}
}
Here mContext is the Context of your current MainCalendar Activity.
Looking at your implementation, the AsyncTask wont have time to work because you will be jumping to the next Activity right away. Try calling the next activity in PostExecute().
I also tried to call startActivity in onPostExecute, but it didn't work.
Did you did it like this:
public void toVisitRegister(Event event) { //Switching to the second activity
new startingThread().execute();
}
public class startingThread extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
startingProgress = new ProgressDialog(MainCalendar.this);
startingProgress.setTitle("Visit Register");
startingProgress.setMessage("Initializing...");
startingProgress.show();
}
#Override
protected String doInBackground(String... params) {
return null;
}
#Override
protected void onPostExecute(String result) {
if(MainCalendar.this.startingProgress != null) {
MainCalendar.this.startingProgress.dismiss();
}
Intent toVisitRegister = new Intent(MainCalendar.this, VisitRegister.class);
startActivity(toVisitRegister);
finish();
}
}
In my code I load a spinner adapter by using Async Task
In My case The ProgressDialog is Not dismissing
This is My code.
I want to show the item after adapter load and the progressDialog is to dismiss
Please Help me, Thanks
private class LoadMoreVehicals extends AsyncTask<Object, Integer, Object> {
#Override
protected void onPreExecute() {
progressBar = ProgressDialog.show(RegistrationScreen.this, "",
"Loading...");
progressBar.setIndeterminate(true);
progressBar.setIndeterminateDrawable(getResources().getDrawable(
R.anim.progressbar_handler));
super.onPreExecute();
}
#Override
protected Object doInBackground(Object... params) {
String countryUrl = ConstantURL.COUNTRY_URL;
getCounty(countryUrl);
countrySpinner
.setAdapter(new MyCustomSpinnerAdapter(
RegistrationScreen.this,
R.layout.spinner_dropdown,
countyList));
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
progressBar.getProgress();
}
#Override
protected void onPostExecute(Object result) {
progressBar.dismiss();
Log.e("Im in onPostExecute", "");
super.onPostExecute(result);
}
}
While programming in Android you should remember one thing that any task which draws something on the screen should be executed on the main thread. When you set the adapter then android calls the getView() method of the adapter and draws views on the screen. So you should set the adapter in the postExecute() method instead in doInBackground() method.
Here is a small sample to clear my point:
class MyTask extends AsyncTask<Void, Void, Void> {
ProgressDialog pd = new ProgressDialog(MainActivity.this);
#Override
protected void onPreExecute ( )
{
//starting the progress dialogue
pd.show();
}
#Override
protected Void doInBackground (Void... params)
{
//fetch data here
...
...
return null;
}
#Override
protected void onPostExecute (Void result)
{
//set adapter here
...
...
//dismissing the progress dialogue
pd.dismiss();
}
}
In my experience i have so many problems with async runs and UI so now always separate the stuff trying to place the "responsibilities" in each place. So i do something like this:
Create my Async class with the process i want to do and nothing that transform the UI in it
Create a function in UI thread that modify the UI when async task finish, something like OnAsyncTaskComplete(Object response)
Keep communicated the threads
public class MyActivity extends Activity {
private static MyAsyncClass backgroundTask;
private static ProgressDialog pleaseWaitDialog;
//......activity stuff.......
#Override
public void onPause()
{
super.onPause();
//Get rid of progress dialog in the event of a screen rotation or other state change. Prevents a crash.
if (pleaseWaitDialog != null)
pleaseWaitDialog.dismiss();
}
//Function to avoid lose the async thread if the app interrupts (phone rotation, incoming call, etc) RECOMENDED TO HANDLE THIS!!
//Sets the current state after app resume
#Override
public void onResume()
{
super.onResume();
//If there is a background task set it to the new activity
if ((backgroundTask != null) && (backgroundTask.getStatus() == Status.RUNNING))
{
if (pleaseWaitDialog != null)
pleaseWaitDialog.show();
backgroundTask.setActivity(this);
}
}
}
//Logic business after the web service complete here
//Do the thing that modify the UI in a function like this
private void onTaskCompleted(Object _response)
{
//For example _response can be a new adapter
MyList.setAdapter((BaseAdapter)_response);
//or can be a list to create the new adapter
MyList.setAdapter(new MyAdapter(this, (ArrayList<String>)_response));
//or can be anything you want, just try to make here the things that you need to change the UI
}
/**
* Class that handle the async task
*/
public class MyAsyncClass extends AsyncTask<Void, Void, Object>
{
//Maintain attached activity for states change propose
private MyActivity activity;
//Keep the response of the async task
private Object _response;
//Flag that keep async task completed status
private boolean completed;
//Constructor
private MyAsyncClass(MyActivity activity) {
this.activity = activity;
}
//Pre execution actions
#Override
protected void onPreExecute() {
//Start the splash screen dialog
if (pleaseWaitDialog == null)
pleaseWaitDialog= ProgressDialog.show(activity.this,
"PLEASE WAIT",
"Getting results...",
false);
}
//Execution of the async task
protected Object doInBackground(Object...params)
{
//return the thing you want or do want you want
return new ArrayList();
}
//Post execution actions
#Override
protected void onPostExecute(Object response)
{
//Set task completed and notify the activity
completed = true;
_response = response;
notifyActivityTaskCompleted();
//Close the splash screen
if (pleaseWaitDialog != null)
{
pleaseWaitDialog.dismiss();
pleaseWaitDialog = null;
}
}
//Notify activity of async task completion
private void notifyActivityTaskCompleted()
{
if ( null != activity ) {
activity.onTaskCompleted(_response);
}
}
//for maintain attached the async task to the activity in phone states changes
//Sets the current activity to the async task
public void setActivity(MyActivity activity)
{
this.activity = activity;
if ( completed ) {
notifyActivityTaskCompleted();
}
}
}
}
Hope its help you
First of all you cannot set the adapter in the doInBackground
follow this design:
private class LoadMoreVehicals extends AsyncTask<Object, Integer, Object>
{
private ArrayList<Country> countries;
#Override
protected void onPreExecute() {
progressBar = ProgressDialog.show(RegistrationScreen.this, "","Loading...");
progressBar.setIndeterminate(true);
progressBar.setIndeterminateDrawable(getResources().getDrawable(R.anim.progressbar_handler));
super.onPreExecute();
}
#Override
protected Object doInBackground(Object... params) {
String countryUrl = ConstantURL.COUNTRY_URL;
countries = getCounty(countryUrl);
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
progressBar.getProgress();
}
#Override
protected void onPostExecute(Object result) {
countrySpinner.setAdapter(new MyCustomSpinnerAdapter(RegistrationScreen.this,R.layout.spinner_dropdown,countries));
progressBar.dismiss();
Log.e("Im in onPostExecute", "");
super.onPostExecute(result);
}
}
I have a tabgroup having multiple activities. In one of the tabs i have two activities between whom i want to place a progress dialog.For this i am using Asynk Task. Following is my AsynkTask class which i have made an inner class for AboutUs activity:
private class TheTask extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
progDialog = ProgressDialog.show(AboutUs.this.getParent(), "Loading... ",
"please wait....", true);
}
#Override
protected Void doInBackground(Void... params) {
final Intent aboutusIntent = new Intent(getParent(), Departments.class);
final TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.startChildActivity("Departments", aboutusIntent);
return null;
}
#Override
protected void onPostExecute(Void result) {
if(progDialog.isShowing())
{
progDialog.dismiss();
}
}
}
I am calling this class in my AboutUs activity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aboutus);
.
.
.
.
/* Button for going to Departments */
Button ourdepbtn = (Button) findViewById(R.id.departmentsbutton);
ourdepbtn.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
//ourDepartments();
new TheTask().execute();
return false;
}
});
}
However this does'nt start a new activity i.e. Departments. The progress dialog appears and then disappears but activity never loads.
Any suggestions..??
First, you cannot start an activity from a non GUI thread (which Async doInBackground() is). Just start directly inside your Button.onClick() (why you use onTouch?) listener.
If you want to show up a ProgressDialog for the new Activity as soon as possible, you need to create it in the new (child) Activity onCreate(), as your ProgressDialog is connected to the new (child) activity (is it?). Take care about the order of creating layouts (create the ProgressDialog after calling setContentView()).
I am not very sure why you want to show that ProgressDialog. Is there something which delays the display of the childActivity? You loading some data? Then, the Dialog should be related to that loading task (Async I guess).
private class TheTask extends AsyncTask{
Context con;
Intent aboutusIntent;
TabGroupActivity parentActivity;
private TheTask(Context context)
{
this.con=context;
}
#Override
protected void onPreExecute() {
progDialog = ProgressDialog.show(con, "Loading... ",
"please wait....", true);
}
#Override
protected Void doInBackground(Void... params) {
aboutusIntent = new Intent(con, Departments.class);
parentActivity = (TabGroupActivity)getParent();
return null;
}
#Override
protected void onPostExecute(Void result) {
if(progDialog.isShowing())
{
progDialog.dismiss();
}
parentActivity.startChildActivity("Departments", aboutusIntent);
}
}
Thanks for your suggestions Oliver :)