I have a function that dynamically creates all my user interface.
What can I do to show a dialog progress while my function is executing, and then dismiss the dialog when my function has finished the user interface?
This is an example of my code:
Sorry, I'm new to android, it is hard for me to understand some code... I will write my code here...
I have this function:
public void principal() {
//CODE TO CREATE ALL THE USER INTERFACE DYNAMICALLY
}
and I have the asyncTask like this:
public class EjecutarTarea extends AsyncTask<Void, Void, Void>
{
protected void onPreExecute() {
dialog = new ProgressDialog(StadioNenaActivity.this);
dialog.setMessage("Cargando..");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
protected Void doInBackground(Void... unused) {
Principal();
return null;
}
#Override
protected void onProgressUpdate(Void... unused) {
}
#Override
protected void onPostExecute(Void unused) {
dialog.dismiss();
}
}
When I execute the asynctask in the onCreate, it crashes:
new EjecutarTarea().execute();
Use an AsyncTask. It gives a fantastic and easy way to load stuff in the background and them paste views in the main thread.
Here is an example of my AsyncTask:
private class LoadingTask extends AsyncTask<Void, Integer, Void> {
private ProgressBar mProg;
private TextView mLoadingText;
#Override protected void onPreExecute() {
mProg = (ProgressBar)findViewById(R.id.launcherbar_loadprogress);
mProg.setTouchDelegate(null);
mProg.setClickable(false);
mProg.setLongClickable(false);
mProg.setOnTouchListener(null);
mProg.setMax(100);
mLoadingText = (TextView) findViewById(R.id.launcheractivity_loadingwhat);
}
#Override protected Void doInBackground(Void... voids) {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
setProgressAndSleep(R.string.loading_log, 29, 250);
LOG.setContext(LauncherActivity.this);
LOG.setDebug(true);
setProgressAndSleep(R.string.loading_database, 43, 250);
AppionDatabase.setContext(LauncherActivity.this);
setProgressAndSleep(R.string.loading_sensors, 57, 250);
Sensor.init(LauncherActivity.this);
setProgressAndSleep(R.string.loading_jobs, 71, 250);
Job.init(LauncherActivity.this);
setProgressAndSleep(R.string.loading_workbenches, 86, 250);
WorkbenchState.init(LauncherActivity.this);
setProgressAndSleep(R.string.loading_application_state, 100, 250);
ApplicationState.setContext(LauncherActivity.this);
startService(new Intent(LauncherActivity.this, BluetoothConnectionService.class));
return null;
}
#Override public void onProgressUpdate(Integer... prog) {
mLoadingText.setText(prog[0]);
mProg.setProgress(prog[1]);
}
#Override public void onPostExecute(Void voids) {
startActivity(new Intent(LauncherActivity.this, HomescreenActivity.class));
}
private void setProgressAndSleep(int text, int progress, int duration) {
try {
publishProgress(new Integer[] {text, progress});
Thread.sleep(duration);
} catch (InterruptedException e) {
LOG.e(TAG, "Failed to sleep thread while loading Application Contexts!", e);
}
}
}
Edit NOTE I recommend not keeping the setProgressAndSleep(int, int int) method. I only use it cause it loads too fast and I really wanted the loading bar. :-P
All changes in Android UI will makes in UI Thread. To run your function in UI thread you need to use mathos runOnUIThread() from activity http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)
Hope it help you!
Your best shot is, probably, to use ViewSwitcher to have temporary view with progress bar while you construct other view. Do operations that take time in doInBackground() of AsyncTask but actual operations on UI such as flipping the view must be done in postExecute() or via runOnUIThread(). Progress updates may be done in onProgressUpdate()
Related
I have 2 AsyncTasks in two different classes but the problem is when the first is do in backgroung state the second is not executed. The first asyncTask if preformed in loop because it needs to update every 5 seconds the new data. If i stop the task (condition = flase) the second one works perfectly.
First class:
public class MapScreen extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_screen);
UpdateUserCords updateUC = new UpdateUserCords();
updateUC.execute();
}
class UpdateUserCords extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... params) {
while(condition)
{
//some code in loop...
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
}
}
Second class:
public class Groups extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_groups);
getGroups getGr = new getGroups();
getGr.execute(); //not executing, no error or crash
}
class getGroups extends AsyncTask<String, Void, String>
{
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
#Override
protected String doInBackground(String... params) {
//some code...
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
}
}
After Android API 11, AsyncTasks started to run on serial executor by default, that means that only one task is running at a time. To get the behavior of prior to API 11, which is running on ThreadPoolExecutor, you'll need to specify it in the code like this:
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) {
myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else {
myTask.execute();
}
Please take a look here for more information:
http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html
Good luck!
P.S. It's not recommended to use AsyncTask for an infinite thread, AsyncTask purpose is to do a Task on the background, not to run forever, so if you want an infinite thread, I think you should create it as a Thread and not as an AsyncTask.
You asynctasks are in two different activities.
Only one activity is active at any time.
Both classes extend Activity and only one of them is running at the same time.
If you want a task to be execute longer than the lifetime of an activity, you have to wrap it into an Service
I have a huge database (40MB) on an SDCard. I need fetch data, with LIKE in query, which is very slow.
DB request takes about 5 seconds. Therefore, I need to do it asynchronously and with ProgressDialog.
I tried it with AsyncTask, but problem is with ProgressDialog. It was implemented this way:
private class GetDataFromLangDB extends AsyncTask<String, String, String> {
private final ProgressDialog dialog = new ProgressDialog(TranslAndActivity.this);
#Override
protected void onPreExecute() {
super.onPreExecute();
urDBCursor.close();
curDBCursor = null;
scaAdapter = null;
this.dialog.setMessage("Loading data...");
this.dialog.show();
}
#Override
protected String doInBackground(String... whatSearch) {
String result = "";
if (myDatabaseAdapter != null) {
curDBCursor = myDatabaseAdapter.fetchAll(whatSearch[0]);
}
return result;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
prepareListView();
}
}
The problem is that ProgressDialog is not shown during the DB request.
After finished database query, it flash on screen for a short time. When user tries
to tap on screen during database request, UI is freezed, and after DB request
message about 'not responding' is shown.
I tried it with a thread this way:
public void startProgress(View view, final String aWhatSearch) {
final ProgressDialog dialog = new ProgressDialog(MyActivity.this);
if (curDBCursor != null){
curDBCursor.close();
curDBCursor = null;
}
dialog.setMessage("Loading data...");
dialog.show();
Runnable runnable = new Runnable() {
public void run() {
curDBCursor = myDatabaseAdapter.fetchAll(aWhatSearch);
// dirty trick
try {
Thread.sleep(250); // it must be here to show progress
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
public void run() {
if (dialog.isShowing()) {
dialog.dismiss();
}
prepareListView();
}
});
}
};
new Thread(runnable).start();
}
The result was the same, but when I used the trick with Thread.sleep(250);
ProgressDialog was shown during the database request. But it is not spinning,
it looks freezed during the DB request.
DB stuff is called this way (after tap on search button):
btnSearchAll.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// AsyncTask
new GetDataFromLangDB().execute(edtTextToSearch.getText().toString());
// or Thread
//startProgress(null, edtTextToSearch.getText().toString());
}
});
I found a lot of problems like this in SO, but nothing was useful for me.
Could it be that DB is on SD Card?
I put the definition of the dialog into the AsyncTask Class and it works fine for me.
Take a look at this exampel (You have to change NAMEOFCLASS in the name of your CLASS:
private class doInBackground extends AsyncTask<Integer, Integer, Void> {
final ProgressDialog dialog = new ProgressDialog(NAMEOFCLASS.this) {
#Override
protected void onPreExecute() {
dialog.setCancelable(false);
dialog.setTitle(getString(R.string.daten_wait_titel));
dialog.setIcon(R.drawable.icon);
dialog.setMessage(getString(R.string.dse_dialog_speichern));
dialog.show();
}
#Override
protected void onCancelled() {
dialog.cancel();
}
....
#Override
protected void onProgressUpdate(Integer... values) {
// DO YOUR UPDATE HERE
}
#Override
protected void onPostExecute(Void result) {
dialog.dismiss();
}
}
Maybe this SO answer could help you. It looks like similar problem. Try to use AsyncQueryHandler for querying your database
declare you Dialog box on Class (Activity) level like this
private ProgressDialog dialog = null;
show the progress dialog and call the AsyncTask class when you want to start you Busy work..like onButton click or any
dialog = ProgressDialog.show(this,"Sending Email to your account please! wait...", true);
SendingEmailTask task = new SendingEmailTask();
String s = "";
task.execute(s);
create your inner class like
private class SendingEmailTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
//do your work here..
// like fetching the Data from DB or any
return null;
}
#Override
protected void onPostExecute(String str) {
//hide progress dialog here
dialog.dismiss();
}
}
let me know if this help!!
I am having a problem with ProgressDialog UI being frozen when I start the action in the AsyncTask.
My problem is somewhat different than the bunch of other similar question because the my background task consists of two parts:
- first part (loadDB()) is related to the database access
- second part (buildTree()) is related to building the ListView contents and is started with runOnUiThread call
The progress dialog is correctly updated during the 1st part of the task, but not during the 2dn part.
I tried moving the buildTree part in the AsyncTask's onPostExecute but it doesn't help, this part of the code still causes the progress to freeze temporarily until this (sometimes quite lengthy) part of the work is done. I can not recode the buildTree part from scratch because it is based on external code I use.
Any tips on how to resolve this? Is there a method to force updating some dialog on screen?
The code goes here:
public class TreePane extends Activity {
private ProgressDialog progDialog = null;
public void onCreate(Bundle savedInstanceState) {
// first setup UI here
...
//now do the lengthy operation
new LoaderTask().execute();
}
protected class LoaderTask extends AsyncTask<Void, Integer, Void>
{
protected void onPreExecute() {
progDialog = new ProgressDialog(TreePane.this);
progDialog.setMessage("Loading data...");
progDialog.show();
}
protected void onPostExecute(final Void unused) {
if (progDialog.isShowing()) {
progDialog.dismiss();
}
}
protected void onProgressUpdate(Integer... progress) {
//progDialog.setProgress(progress[0]);
}
protected Void doInBackground(final Void... unused)
{
//this part does not block progress, that's OK
loadDB();
publishProgress(0);
//long UI thread operation here, blocks progress!!!!
runOnUiThread(new Runnable() {
public void run() {
buildTree();
}
});
return null;
}
}
public void buildTree()
{
//build list view within for loop
int nCnt = getCountHere();
for(int =0; i<nCnt; i++)
{
progDialog.setProgress(0);
//add tree item here
}
}
}
Don't run your whole buildTree() method inside the UI thread.
Instead, run only the changes you want to make to the UI in the UI thread:
protected Void doInBackground(final Void... unused)
{
//this part does not block progress, that's OK
loadDB();
publishProgress(0);
buildTree();
return null;
}
And then:
public void buildTree()
{
//build list view within for loop
int nCnt = getCountHere();
for(int =0; i<nCnt; i++)
{
progDialog.setProgress(0);
runOnUiThread(new Runnable() {
public void run() {
// update your UI here and return
}
});
// now you can update progress
publishProgress(i);
}
}
You should call AsyncTask's publishProgress method and not the progDialog.setProgress(0); as you call.
Also the buildTree shouln't run on the UI thread since it will block it.
run the logic from the doInBackground method.
note that you don't actually build the ListView, rather you should build it's data model.
look here
something like this:
protected Void doInBackground(final Void... unused)
{
//this part does not block progress, that's OK
loadDB();
publishProgress(0);
buildTree();
}
public void buildTree()
{
//build list view within for loop
int nCnt = getCountHere();
for(int =0; i<nCnt; i++)
{
publishProgress(i); //for exmple...
//add tree item here
}
}
I am facing the issue with displaying progressbar onItem selected in option menu.
My code is here:
case R.id.mnuLogout:
showDialog(Constants.PROGRESS_DIALOG);
closeOptionsMenu();
if(MyApp.IsLoggedOut())
handler.sendEmptyMessage(Constants.LOGOUT);
else
handler.sendEmptyMessage(Constants.ERROR_MSG);
Progressbar is displayed after completion of IsLogged method.
You're calling get() right after the AsyncTask as executed and lose asynchronous behavior because this method waits until task is finished. You should add all the code in try/catch block to AsyncTask.onPostExecute() method and also dismiss the dialog from this method.
void doLogout() {
new LogoutTask().execute();
}
void dispatchLogoutFinished() {
dismissDialog(Constants.PROGRESS_DIALOG);
if (MyApp.IsLoggedOut()) {
// do something
} else {
// do something else
}
}
private class LogoutTask extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
TheActivity.this.showDialog(Constants.PROGRESS_DIALOG);
}
protected Void doInBackground(Void... params) {
return null;
}
protected void onPostExecute(Long result) {
TheActivity.this.dispatchLogoutFinished();
}
}
And I don't think you need to send messages to the handler. The dispatchLogoutFinished() is executed on the UI thread, so there's no need for synchronization.
I have two activities. The first one executes the second one.
Intent i = new Intent(MyOne.this, MyTwo.class);
startActivity(i);
The problem: My second activity does some heavy work on launching so it launches couple of second and before it is launched i see a black screen.
Is it any way to set a progressbar or some image instead of this black screen? Because i don't think user will wait for something, that he doesn't know. I tried setting progressbar after setcontentview in my second activity, but progressbar shows up only when activity fully started.
I suggest you to do this asynchronously using AsyncTask.
Short example:
ProgressDialog dialog;
class YourTask extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
dialog = ProgressDialog.show(...);
}
protected Void doInBackground(Void... unused) {
try {
// doSomethingHeavy();
// publishProgress(...);
} catch(Exception e) {
//...
}
return null;
}
protected void onProgressUpdate(Void... unused) {
}
protected void onPostExecute(Void unused) {
dialog.dismiss();
}
}
You sure can. Check out the AsyncTask and this tutorial for inspiration.