2012-11-13 1 views
5

私はサードパーティライブラリを使用しているため、AsyncTaskクラスは他の多くのスレッドを開始します。私は、ライブラリがどれくらい多くのスレッドをオープンしているのかは分かりませんが、リストビューにデータを取り込む前にそれらをすべて終了するのを待っています。My AsyncTaskクラスには他のスレッドがあります。どのように私はそれを待つことができますし、すべてのスレッドは、次のメソッドを実行する前に終了する?

現時点では、私は10000ミリ秒寝ていますが、これはリストの大きさがわからないため実用的ではありません。

この問題の正しい解決方法を教えてください。あなたがスレッドは共通点も

に到達するのを待つのではなく、あるpopulatelist()を呼び出すためにスレッドを作成している場合

task = new mTask(); 
     task.execute(appsList); 
     new Thread(new Runnable() { 
      public void run() { 
       populateList(); 
      } 
     }).start(); 

    } 

    private class mTask extends AsyncTask<List<ApplicationInfo>, Void, Void> { 
     ProgressDialog progress; 

     @Override 
     protected void onPreExecute() { 
      progress = new ProgressDialog(MainActivity.this); 
      progress.setIndeterminate(true); 
      progress.show(); 
      super.onPreExecute(); 
     } 

     @SuppressWarnings("deprecation") 
     @Override 
     protected Void doInBackground(List<ApplicationInfo>... params) { 
      appDataManager = new AppDataManager(MainActivity.this, 
        mySQLiteAdapter, MainActivity.this); 
      appDataManager.work(params[0]); 
      return null; 
     } 

     @Override 
     protected void onPostExecute(Void result) { 
      mySQLiteAdapter.close(); 
      progress.dismiss(); 
      super.onPostExecute(result); 
     } 
    } 

    @SuppressWarnings("deprecation") 
    public void populateList() { 
     try { 
      Thread.sleep(10000) 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     runOnUiThread(new Runnable() { 

      public void run() { 

       Cursor cursor; 
       mySQLiteAdapter.openToRead(); 
       cursor = mySQLiteAdapter.queueAll(); 

       ArrayList<String> appsList = new ArrayList<String>(); 
       if (cursor.moveToFirst()) { 
        do { 
         appsList.add(cursor.getString(1)); 
        } while (cursor.moveToNext()); 
       } 
       cursor.moveToFirst(); 

       ArrayAdapter<String> adp = new ArrayAdapter<String>(
         MainActivity.this, android.R.layout.simple_list_item_1, 
         appsList); 
       listContent.setAdapter(adp); 
       cursor.close(); 
       mySQLiteAdapter.close(); 

       Log.i("finished", "finished"); 
     } 
     }); 

    } 

はAppDataManager

public void work(List<ApplicationInfo> appsList) { 
    List<ApplicationInfo> appList = appsList; 
    mySQLiteAdapter.openToWrite(); 
    mySQLiteAdapter.deleteAll(); 
    mySQLiteAdapter.close(); 
    for (int i = 0; i < 5; i++) { 
     String name = appList.get(i).name; 
     String pack = appList.get(i).packageName; 
     // TODO AsyncTask 
     getHtml(pack, name); 
    } 

} 

public void getHtml(final String pack, final String name) { 
    String url = MARKET_URL + pack; 
      //AndroidQuery library. fetch html 
    aq.ajax(url, String.class, 1000, new AjaxCallback<String>() { 
     @Override 
     public void callback(String url, String htm, AjaxStatus status) { 
      Log.i("status", status.getMessage()); 
      parseHtml(htm, pack, name); 

     } 
    }); 
} 
+0

appDataManagerとは何ですか? – user1049280

+0

@ user1049280インターネットからデータを取得します – code511788465541441

+2

サードパーティライブラリのAPIには、作業の完了を知らせるコールバックメカニズムがありますか? –

答えて

3

まず、populateListへの呼び出しを、の方法AsyncTaskに移動します。また、populateListを書き換えてスリープを削除し、UIスレッドで実行されていることを前提とします(runOnUiThreadコールを削除してrunメソッドの本体を直接populateListに移動します)。

AsyncTaskAppDataManagerの作業が完了するまでdoInBackgroundが完了しないようにします。終了フラグとあなたが同期できるのロックオブジェクトを定義することによって開始します。

private class mTask extends AsyncTask<List<ApplicationInfo>, Void, Void> { 
    boolean complete; 
    static Object LOCK = new Object(); 
    . . . 
} 

その後の作業が行われたときに別のオブジェクトへのコールバックを提供するために、AppDataManagerクラスを変更します。フィールドcallbackを定義し、あなたのAPIやメソッドを更新:

public void work(List<ApplicationInfo> appsList, Runnable callback) { 
    this.callback = callback; // define a field named "callback" 
    List<ApplicationInfo> appList = appsList; 
    mySQLiteAdapter.openToWrite(); 
    mySQLiteAdapter.deleteAll(); 
    mySQLiteAdapter.close(); 
    for (int i = 0; i < 5; i++) { 
     String name = appList.get(i).name; 
     String pack = appList.get(i).packageName; 
     // TODO AsyncTask 
     getHtml(pack, name); 
    } 

} 

public void getHtml(final String pack, final String name) { 
    String url = MARKET_URL + pack; 
      //AndroidQuery library. fetch html 
    aq.ajax(url, String.class, 1000, new AjaxCallback<String>() { 
     @Override 
     public void callback(String url, String htm, AjaxStatus status) { 
      Log.i("status", status.getMessage()); 
      parseHtml(htm, pack, name); 
      if (callback != null) { 
       callback.run(); 
      } 
     } 
    }); 
} 

今すぐ設定するためのフラグを待つために、あなたのdoInBackground方法を変更します。

protected Void doInBackground(List<ApplicationInfo>... params) { 
    appDataManager = new AppDataManager(MainActivity.this, 
      mySQLiteAdapter, MainActivity.this); 
    appDataManager.work(params[0], new Runnable() { 
     public void run() { 
      synchronized (LOCK) { 
       complete = true; 
       LOCK.notifyAll(); 
      } 
     } 
    }); 
    // wait for appDataManager.work() to finish... 
    synchronized (LOCK) { 
     while (!complete) { 
      LOCK.wait(); 
     } 
    } 
    return null; 
} 

これは、仕事をする必要があります。しかし、さまざまな種類のエラー(例えば、AppDataManagerのエラー通知メカニズムを提供するなど)を処理するには、これを詳しく説明する必要があります。

UPDATE最後に、AppDataManagerで5つのネットワークトランザクションを行っていることに気付きました。したがって、ajax()のコールバックメソッド内で直ちにコールバックメソッドを実行する代わりに、カウンタを減分し、カウンタが0になったらコールバックするだけです。getHtml()を呼び出すループを開始する前に、カウンタを0にリセットしてからwork()にします。カウンタは個別のスレッドによって変更されるため、スレッドへのアクセスを同期させる必要があります。 (代替として、カウンタにAtomicIntegerを使用することもできます)

+0

ありがとうございました。これはわずかな修正を加えて機能しました。 'getHtml()'がループ内で呼び出されるため、 'complete'は最初の実行時にtrueに設定されます。私はループが最後に実行されているときに真となるフラグを追加しました。それはそれを解決した。 – code511788465541441

関連する問題