2010-04-07 3 views
1

나는이 문제에 관해서는 알았지 만, 문제가있는 순서대로 작은 문제가 있습니다. 특히, 내 스레드()에서 Spinner에서 사용하는 배열을 설정하고 있습니다. 문제는 Spinner가 기본적으로 내 스레드()가 완료되기 전에 모든 설정되고 완료되었으므로 null 배열로 설정됩니다.Android ProgressDialog 진행 바를 올바른 순서대로 수행

스피너 ArrayAdapter를 다른 스레드에 의해로드되는 배열과 어떻게 연관시킬 수 있습니까?

문제를 이해하는 데 필 요하다고 생각되는 코드를 잘라 냈지만 더 필요한 경우 알려주세요. refreshData() 호출 여부에 관계없이 문제가 발생합니다.

동일한 줄에 따라 때로는 메뉴에서 loadData()를 호출하려고합니다. loadData()를 직접 따라하면 다음 줄에서 축배를 발생 시키므로 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 ---- -----> I는 짐의 제안에서 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()); 
} 

와우,이 해결책을 찾기 위해 나를 위해 영원히 걸렸지 만 기뻐 임 마침내 일이 입수 한 것으로 :이 권리를했다 확실하지 경우, 여전히 작동하지 않습니다.

배경 스레드로 Spinner를 업데이트하는 것은 처리기를 사용하여 수행 할 수 있습니다. 핸들러는 스레드의 주요 작업이 완료된 후에 호출됩니다.

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과에서 onCreate에서 loadData()가() loadData 트리거 스레드에서 실행에서 작업() 이후에 수행해야 할 모든 작업 후 this thread

답변

0

에 그의 대답은()가 완료되었습니다. loadData()를 인라인하고 pd.dismiss() 다음에이 설치 후 작업을 runOnUiThread()에 추가하십시오. 혹시이 문제를 해결 한 경우

+0

감사 짐, 임 전문가는 프로그래머, 그래서 내가 정확히 "인라인"에 대해, 특히 부분이 무슨 뜻인지 모르는 두려워 내가 loadData()를 수정하려고 않았다 (에 포함 질문에 EDIT)하지만 아무 소용이 없습니다. 같은 문제. 아마도 당신이 제안한 것을 구현하지 않았을 것입니다. 더 많은 도움을 주시면 감사하겠습니다.감사합니다 – FauxReal

+0

전문 용어에 대한 사과, '인라인'은 메서드 코드를 호출 한 곳으로 복사하고 메서드를 제거하는 것을 의미합니다. Refactor 메뉴를 사용하여 Eclipse에서 직접 또는 자동으로 수행 할 수 있습니다. 어쨌든 내 오리지널 제안의 요지는 오랜 시간이 걸리는 작업이 포함 된 컨트롤을 설정하는 올바른 방법은 1. 초기 설정, 2를위한 새로운 스레드를 설정하는 것입니다. 데이터를 얻는 것은 완료되었을 때 runOnUiThread() 3. 컨트롤에 데이터를 채 웁니다. –

+0

다시 한 번 감사드립니다. Jim, 제안 된대로 onCreate 메서드가 변경되었습니다 (생각합니다). 위의 코드는 두 번째 코드 창에서 볼 수 있습니다. runOnUiThread가 Thread() 안에 들어가야 했습니까? 여전히 작동하지 않습니다. 디버깅 할 때 스레드 실행을 시작하기 전에 전체 UI를 설정하는 것처럼 보입니다. – FauxReal

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

가 나는 또한 당신이 당신이 사용할 수있는 아주 좋은 AsyncTaskEx의 IMPL을 가지고 https://github.com/commonsguy/cwac-task 를 사용하는 것이 좋습니다 것입니다 ui를 잠그지 않고 무거운 작업을하십시오.

예시 클래스;

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