web-dev-qa-db-ja.com

スレッドからUIを更新

Progressbarを更新するスレッドからUIを更新したい。残念ながら、プログレスバーのドロウアブルを「実行可能」から更新すると、プログレスバーが消えます!反対側のonCreate()でプログレスバーのドロウアブルを変更することはできます!

助言がありますか?

public void onCreate(Bundle savedInstanceState) {
    res = getResources();
    super.onCreate(savedInstanceState);
    setContentView(R.layout.gameone);
    pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); //**Works**/
    handler.postDelayed(runnable, 1);       
}

private Runnable runnable = new Runnable() {
    public void run() {  
        runOnUiThread(new Runnable() { 
            public void run() 
            { 
                //* The Complete ProgressBar does not appear**/                         
                pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); 
            } 
        }); 
    }
}
52
Filly

AsyncTask (インテリジェントバックラウンドスレッド)および ProgressDialog を使用してこれを行う必要があります。

AsyncTaskを使用すると、UIスレッドを適切かつ簡単に使用できます。このクラスにより、スレッドやハンドラを操作することなく、バックグラウンド操作を実行し、UIスレッドで結果を公開できます。

非同期タスクは、バックグラウンドスレッドで実行され、その結果がUIスレッドで公開される計算によって定義されます。非同期タスクは、Params、ProgressおよびResultと呼ばれる3つの汎用タイプと、begin、doInBackground、processProgressおよびendと呼ばれる4つのステップで定義されます。

4つのステップ

非同期タスクが実行されると、タスクは4つのステップを経ます。

onPreExecute()。タスクが実行された直後にUIスレッドで呼び出されます。この手順は通常、たとえばユーザーインターフェイスに進行状況バーを表示することにより、タスクをセットアップするために使用されます。

doInBackground(Params...)。onPreExecute()の実行が終了した直後にバックグラウンドスレッドで呼び出されます。このステップは、時間がかかるバックグラウンド計算を実行するために使用されます。非同期タスクのパラメーターはこのステップに渡されます。計算の結果はこのステップによって返されなければならず、最後のステップに戻されます。このステップでは、publishProgress(Progress ...)を使用して、1つ以上の進行単位を公開することもできます。これらの値は、onProgressUpdate(Progress ...)ステップでUIスレッドに公開されます。

onProgressUpdate(Progress...)、publishProgress(Progress ...)の呼び出し後にUIスレッドで呼び出されます。実行のタイミングは未定義です。このメソッドは、バックグラウンド計算の実行中にユーザーインターフェイスに進行状況を表示するために使用されます。たとえば、プログレスバーをアニメーション表示したり、テキストフィールドにログを表示したりするために使用できます。

onPostExecute(Result)、バックグラウンド計算の終了後にUIスレッドで呼び出されます。バックグラウンド計算の結果は、パラメーターとしてこのステップに渡されます。スレッド化ルール

このクラスが適切に機能するために従うべきいくつかのスレッド化ルールがあります:

タスクインスタンスはUIスレッドで作成する必要があります。 execute(Params ...)は、UIスレッドで呼び出す必要があります。 onPreExecute()、onPostExecute(Result)、doInBackground(Params ...)、onProgressUpdate(Progress ...)を手動で呼び出さないでください。タスクは1回しか実行できません(2回目の実行が試行されると、例外がスローされます)。

サンプルコード
この例でアダプターが行うことは重要ではありません。AsyncTaskを使用して進行状況のダイアログを表示する必要があることを理解するためにより重要です。

private class PrepareAdapter1 extends AsyncTask<Void,Void,ContactsListCursorAdapter > {
    ProgressDialog dialog;
    @Override
    protected void onPreExecute() {
        dialog = new ProgressDialog(viewContacts.this);
        dialog.setMessage(getString(R.string.please_wait_while_loading));
        dialog.setIndeterminate(true);
        dialog.setCancelable(false);
        dialog.show();
    }
    /* (non-Javadoc)
     * @see Android.os.AsyncTask#doInBackground(Params[])
     */
    @Override
    protected ContactsListCursorAdapter doInBackground(Void... params) {
        cur1 = objItem.getContacts();
        startManagingCursor(cur1);

        adapter1 = new ContactsListCursorAdapter (viewContacts.this,
                R.layout.contact_for_listitem, cur1, new String[] {}, new int[] {});

        return adapter1;
    }

    protected void onPostExecute(ContactsListCursorAdapter result) {
        list.setAdapter(result);
        dialog.dismiss();
    }
}
62
Pentium10

UIスレッドに短い実行を提供するために見た最も簡単なソリューションは、ビューのpost()メソッドを使用することです。 UIメソッドはリエントラントではないため、これが必要です。この方法は次のとおりです。

package Android.view;

public class View;

public boolean post(Runnable action);

Post()メソッドはSwingUtilities.invokeLater()に対応しています。残念ながら、SwingUtilities.invokeAndWait()に対応する単純なものは見つかりませんでしたが、モニターとフラグを使用して前者に基づいて後者を作成できます。

したがって、これで保存するのはハンドラーを作成することです。ビューを見つけて投稿するだけです。 id-edリソースを使用する傾向がある場合は、findViewById()を使用してビューを見つけることができます。結果のコードは非常に簡単です:

/* inside your non-UI thread */

view.post(new Runnable() {
        public void run() {
            /* the desired UI update */
        }
    });
}

注:SwingUtilities.invokeLater()と比較して、View.post()メソッドはブール値を返し、ビューにイベントキューが関連付けられているかどうかを示します。 invokeLater()を使用したので、それぞれ。とにかく火だけのためにpost()を忘れて、私は結果の値を確認しませんでした。基本的に、ビューでonAttachedToWindow()が呼び出された後にのみpost()を呼び出す必要があります。

宜しくお願いします

25

Handlerを使用する場合(UIスレッドでそのインスタンスを作成したことを願っています)、runnable内でrunOnUiThread()を使用しないでください。 runOnUiThread()は、非UIスレッドからsmthを実行するときに使用されますが、HandlerはUIスレッドでrunnableを既に実行しています。

次のようにやってみてください:

private Handler mHandler = new Handler();
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.gameone);
    res = getResources();
    // pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); **//Works**
    mHandler.postDelayed(runnable, 1);
}

private Runnable runnable = new Runnable() {
    public void run() {
        pB.setProgressDrawable(getResources().getDrawable(R.drawable.green));
        pB.invalidate(); // maybe this will even not needed - try to comment out
    }
};
11
Vit Khudenko

(Runnableの代わりに) AsyncTask クラスを使用します。 UIに影響を与える可能性のあるonProgressUpdateというメソッドがあります(UIスレッドで呼び出されます)。

11
pablochan

UIスレッドでHandlerを作成し、それを使用して他のスレッドからメッセージを投稿または送信し、UIを更新する必要があります。

9
schwiz

AsyncTaskが気に入らない場合は、 observer pattern を使用できます。その例では、アクティビティの内部クラスとしてResponseHandlerを使用してから、進行状況バーの割合を設定する文字列メッセージを使用します... UI、次にワーカースレッド(この例ではEventSource)が必要なタスクを実行できます。

私はAsyncTask thoを使用しますが、オブザーバーパターンは、カスタマイズの理由に加えて、わかりやすくすることができます。また、この方法が広く受け入れられているかどうか、100%うまくいくかどうかもわかりません。今すぐダウンロードして、Androidプラグインをテストしてください

1
tmho

公式の documentation で推奨されているように、 AsyncTaskを使用して、5ミリ秒より短い作業項目を処理できます。タスクにさらに時間がかかる場合は、他の選択肢を探してください。

HandlerThread は、ThreadまたはAsyncTaskの代替の1つです。 HandlerThreadからUIを更新する必要がある場合は、UIスレッドLooperにメッセージを投稿し、UIスレッド Handler はUIの更新を処理できます。

サンプルコード:

Android:スレッドでトースト

0
Ravindra babu