Android ProgressDialog Progress Bar faire les choses dans le bon ordre

? FauxReal @ | Original: StackOverFlow

Je ai juste obtenu ce sujet, mais je ai un petit problème dans l'ordre des choses de se éteindre. Plus précisément, dans mon fil ( ) Je vais mettre en place un tableau qui est utilisé par un Spinner . Le problème est l' Spinner est tout placé et fait essentiellement avant mon fil ( ) est terminée, il se met en place avec un tableau NULL .

Comment associer les filateurs ArrayAdapter avec un tableau qui est chargé par un autre thread ?

Je ai coupé le code jusqu'à ce que je pense est nécessaire de comprendre le problème, mais laissez-moi savoir si il faut faire plus . Le problème se produit si oui ou non RefreshData ( ) est appelée .

Dans le même sens, parfois, je veux appeler loadData ( ) dans le menu . Immédiatement après loadData ( ) si je essaie de tirer un toast sur ​​la ligne suivante cela provoque un FORCECLOSE, qui est aussi à cause de la façon dont je la mise en œuvre ProgressDialog .

MERCI POUR LE REGARD

public class CMSHome extends Activity { 

private static List<String> pmList = new ArrayList<String>();

// Instantiate helpers
PMListHelper plh = new PMListHelper();
ProjectObjectHelper poc = new ProjectObjectHelper();

// These objects hold lists and methods for dealing with them
private Employees employees;
private Projects projects;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // Loads data from filesystem, or webservice if necessary
    loadData();

    // Capture spinner and associate pmList with it through ArrayAdapter
    spinner = (Spinner) findViewById(R.id.spinner);
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                    this, android.R.layout.simple_spinner_item,
                    pmList);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

    //---the button is wired to an event handler---
    Button btn1 = (Button)findViewById(R.id.btnGetProjects);
    btn1.setOnClickListener(btnListAllProjectsListener);
    spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
}


private void loadData()
{
    final ProgressDialog pd = ProgressDialog.show(this,
            "Please wait", "Loading Data...", true, false);

    new Thread(new Runnable(){
        public void run(){
            employees = plh.deserializeEmployeeData();
            projects = poc.deserializeProjectData();

            // Check to see if data actually loaded, if not then refresh
            if ((employees == null) || (projects == null)) {
                refreshData();
            }

            // Load up pmList for spinner control
            pmList = employees.getPMList();

            pd.dismiss();
        }
    }).start();
}

private void refreshData()
{
    // Refresh data for Projects
    projects = poc.refreshData();
    poc.saveProjectData(mCtx, projects);

    // Refresh data for PMList          
    employees = plh.refreshData();
    plh.savePMData(mCtx, employees);
}
}

< ---- ----- EDIT > Je ai essayé de changer onCreate ( ) à la suivante après suggestion Jims . Ne sais pas si je ai fait ce droit, ne fonctionne toujours pas :

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    mCtx = this;

    // Loads data from filesystem, or webservice if necessary
    // Would like to extend this to update if files are over x days old
    final ProgressDialog pd = ProgressDialog.show(this,
            "Please wait", "Loading Data...", true, false);

    new Thread(new Runnable(){
        public void run(){
            employees = plh.deserializeEmployeeData();
            projects = poc.deserializeProjectData();

            // Check to see if data actually loaded, if not then refresh
            if ((employees == null) || (projects == null)) {
                refreshData();
            }

            pd.dismiss();

            runOnUiThread(new Runnable() {
                public void run(){
                    // Load up pmList for spinner control
                    pmList = employees.getPMList();
                }
            });

        }
    }).start();

    spinner = (Spinner) findViewById(R.id.spinner);
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(
            this, android.R.layout.simple_spinner_item, pmList);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

    //---the button is wired to an event handler---
    Button btn1 = (Button)findViewById(R.id.btnGetProjects);
    btn1.setOnClickListener(btnListAllProjectsListener);
    spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
}

Wow, ce a fallu une éternité pour moi de trouver une solution, mais je suis ravi d' avoir finalement obtenu que cela fonctionne .

Mise à jour du Spinner avec un fil de fond peut être réalisé en utilisant un gestionnaire. Le gestionnaire est appelé après le travail principal du fil est terminée .

  mProgressDlg = ProgressDialog.show(this, "App_Name", "Loading data...", 
                                    true, false);
  new Thread(new Runnable(){
            public void run() {
                    /*Load Data, set pmList in my case*/
                    mProgressDlg.dismiss();
                    hRefresh.sendEmptyMessage(REFRESH);
            }
    }).start();



Handler hRefresh = new Handler(){

@Override
public void handleMessage(Message msg) {
   switch(msg.what){
     case REFRESH:
                 spinner = (Spinner) findViewById(R.id.spinner);
                 final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                         mCtx, android.R.layout.simple_spinner_item, pmList);
                 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                 spinner.setAdapter(adapter);
                 spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
            break;
   }
}
};

Crédit bhatt4982 et sa réponse sur http://stackoverflow.com/questions/1458190/how-can-i-display-a-progress-at-start-up-application-in-android

Top 5 Répondre

1Jim Blackler @

Tout le travail après loadData () dans onCreate ( ) qui doit être fait après le travail en run ( ) dans le fil déclenchée dans loadData ( ) a été achevée . Essayez enlignage loadData ( ), et en ajoutant ce travail post-installation à un runOnUiThread ( ) après pd.dismiss ( ) .

2BJB @

Je ne sais pas si vous avez déjà résolu, mais cela fonctionne pour moi:

public class Start extends Activity {
private static final String TAG = "PriceList";

ArrayAdapter<ProductCategory> category_adapter;
ArrayAdapter<ProductGroup> group_adapter;

ArrayList<ProductCategory> categories;
ArrayList<ProductGroup> groups;

ArrayList<Price> prices;

Spinner group_spinner;
Spinner category_spinner;
ProgressDialog progressDialog;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    group_spinner = (Spinner) findViewById(R.id.group_spinner);
    category_spinner = (Spinner) findViewById(R.id.category_spinner);

    // product category spinner
    categories = new ArrayList<ProductCategory>();

    category_adapter = new CustomArrayAdapter<ProductCategory>(categories);
    category_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

    // load category spinner from database
    loadCategory();     // adapter MUST be setup before this is called

    category_spinner.setAdapter(category_adapter);
    category_spinner.setOnItemSelectedListener(new OnItemSelectedListener () {


    ..... other stuff ...... 


private final Handler handler = new Handler() {
    @Override
    public void handleMessage(final Message msg) {
        Log.v(TAG, "worker thread done, setup adapter");

        switch (msg.what) {
        case Constants.CATEGORIES:
            category_adapter.notifyDataSetChanged();
            break;
        case Constants.GROUPS:
            group_adapter.notifyDataSetChanged();
            break;
        case Constants.PRICES:
            startActivity(new Intent(Start.this, ShowPrices.class));
            break;
        default:
        }
        // dismiss dialog
        progressDialog.dismiss();
    }
};

    // loadCategory() essentially the same....

private void loadGroup(final String cat) {
    Log.v(TAG, "loadGroup");

    progressDialog = new ProgressDialog(this);
    progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    progressDialog.setMessage("Retrieving Product Groups...");
    progressDialog.setMax(100);
    progressDialog.setProgress(0);
    progressDialog.show();

    new Thread() {

        @Override
        public void run() {

            int count = 100;
            int i = 0;

            SQLiteDatabase db = DbUtils.getStaticDb();

            Cursor c = db.rawQuery("select count(*) from productgroup where category = '"
                            + cat + "';", null);
            c.moveToFirst();
            if (!c.isAfterLast()) {
                count = c.getInt(0);
            }
            c.close();

            progressDialog.setMax(count);

            groups.clear();
            groups.add(new ProductGroup("-1", "--- Select ---"));

            StringBuilder sb = new StringBuilder("select _id,description from productgroup");
            sb.append(" where category = '");
            sb.append(cat);
            sb.append("' order by description;");
            Log.v(TAG, sb.toString());

            c = db.rawQuery(sb.toString(), null);
            c.moveToFirst();
            while (!c.isAfterLast()) {
                Log.v(TAG, c.getString(0));
                groups.add(new ProductGroup(c.getString(0), c.getString(1)));
                i++;
                if (i % 5 == 0) {
                    progressDialog.setProgress(i);
                }
                c.moveToNext();
            }
            c.close();

            // tell UI thread OK
            handler.sendEmptyMessage(Constants.GROUPS);
        }
    }.start();
}

    // custom ArrayAdapter allows us to have our own ArrayList<T>

class CustomArrayAdapter<T> extends ArrayAdapter<T> {

    CustomArrayAdapter(ArrayList<T> list) {
        super(Start.this, android.R.layout.simple_spinner_item, list);
    }

}
3WareNinja @

Je voudrais également vous suggérons d'utiliser https://github.com/commonsguy/cwac-task il a impl AsyncTaskEx très agréable, que vous pouvez utiliser pour effectuer des travaux lourds sans verrouiller l'interface utilisateur.

Example class;

protected class DoHeavyWorkAsync extends AsyncTaskEx<Void, Integer, String> {
        private static final String TAG = "DoHeavyWorkAsync";

        @Override
        protected String doInBackground(Void... arg0) {

            // do heavy work here. e.g. loadDataFromSomewhere();
            YourActivity.this.runOnUiThread(new Runnable() {
                public void run() {
                    // you can do ui work on the main activity from here
                }
            });

            return null;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            Log.d(TAG, "onPreExecute()");
                    //e.g. display "loading..." 
        }
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            Log.d(TAG, "onPostExecute()");
        }
    }

de votre activité principale, vous pouvez appeler comme ceci ;

(new DoHeavyWorkAsync()).execute();