2010-04-07 29 views
1

我剛剛得到了這個,但我遇到了一些小問題。 具體來說,在我的線程()中,我設置了一個由Spinner使用的數組。問題是在我的thread()完成之前,Spinner基本上都被設置和完成了,因此它使用一個空數組來設置它自己。Android ProgressDialog進度條以正確的順序處理事情

如何關聯的紡紗ArrayAdapter與正在被另一個線程加載一個數組?

我剪的代碼下降到什麼,我認爲是有必要了解的問題,只是讓我知道,如果需要更多。無論是否調用refreshData()都會出現問題。

按照同樣的思路,有時我想從菜單中調用loadData()。直接跟在loadData()之後,如果我嘗試在下一行觸發一個toast,這會導致forceclose,這也是因爲我如何實現ProgressDialog。

謝謝你看

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 -----> 我試圖改變的onCreate()來吉姆的建議之後以下。不知道是否我沒這個權利,仍然不能正常工作:

@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()); 
} 

哇,這花了永遠爲我找到一個解決方案,但是我喜出望外地終於得到了這個工作。

更新微調用後臺線程可通過利用一個處理程序來完成。處理程序在線程的主要工作完成後調用。

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; 
    } 
} 
}; 

感謝bhatt4982和他的this thread

回答

0

答案loadData()中的onCreate()需要的run()在線程引發loadData工作之後進行後,所有的工作()有已完成。嘗試內聯loadData(),並在pd.dismiss()之後將此後設置工作添加到runOnUiThread()。

+0

感謝吉姆, 林沒有專家,程序員,所以我怕我不正是你的意思,尤其是部分關於「內聯」知道 我也嘗試修改loadData()(包括在編輯的問題),但無濟於事。同樣的問題。我可能沒有實現你的建議。 任何進一步的幫助非常感謝。謝謝 – FauxReal 2010-04-08 17:58:12

+0

我對這個術語表示歉意,'內聯'意味着將一個方法的代碼複製到它被調用的地方並刪除該方法。您可以自己完成,也可以使用重構菜單在Eclipse中自動完成。無論如何,我最初的建議的要點是,設置控件涉及一些冗長操作的正確方法是1.初始設置,它爲2創建一個新線程,獲取數據,當數據完成時,runOnUiThread() 3.用數據填充控件。 – 2010-04-08 19:04:53

+0

再次感謝Jim, 我改變了像你所建議的(我認爲)onCreate方法。你可以在第二個代碼窗口中看到它。 runOnUiThread是否應該進入Thread()?這仍然不起作用。 當我調試時,它甚至在它開始運行線程之前就設置了整個UI。 – FauxReal 2010-04-08 19:40:31

3

不知道如果你曾經解決了這個,但是這個工作對我來說:

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); 
    } 

} 
0

我也建議你使用https://github.com/commonsguy/cwac-task 它有非常好的AsyncTaskEx IMPL,你可以用它來不用鎖定用戶界面就可以做大量的工作。

示例類;

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()"); 
     } 
    } 

從您的主要活動,你可以這樣調用;

(new DoHeavyWorkAsync()).execute();