125

非常に奇妙な機能に遭遇しました。

メイン スレッドでアニメーションを実行しようとすると、開始されません。を使用して上記のアニメーションを実行すると

getView().post(new Runnable() {
            @Override
            public void run() {
                getView().startAnimation(a);
            }
        });

それは始まります。

CurrentThreadアニメーションを開始する前に を印刷し、両方とも を印刷しmainました。

どちらもメインスレッドでアニメーションを開始する必要があるため、明らかに、ここで何かが欠けています...ポストがタスクをキューに追加すると、より「正しい時間」に開始されると思いますが、知りたいですここで何が起こるかをより深く。

編集:物事を明確にしましょう-私の質問は、メインスレッドでアニメーションを開始しないのに、ポストでアニメーションを開始すると開始する理由です。

4

4 に答える 4

169

post :post により、Runnable がメッセージ キューに追加されます。

Runnable :実行可能なコマンドを表します。多くの場合、別のスレッドでコードを実行するために使用されます。

run () : クラスのコードのアクティブな部分の実行を開始します。このメソッドは、Runnable を実装するクラスで作成されたスレッドが開始されたときに呼び出されます。

getView().post(new Runnable() {

         @Override
         public void run() {
             getView().startAnimation(a);
         }
     });

コード:getView().startAnimation(a);

あなたのコードで、

post により、Runnable (コードは別のスレッドで実行されます) がメッセージ キューを追加します。

したがって、startAnimation は、messageQueueからフェッチされるときに新しいスレッドで起動されます。

[編集1]

UI スレッド (メイン スレッド) の代わりに新しいスレッドを使用するのはなぜですか?

UI スレッド:

  • アプリ起動時に自動でUiスレッドが作成される

  • イベントを適切なウィジェットにディスパッチする役割を担い、これには描画イベントが含まれます。

  • これは、Android ウィジェットと対話するスレッドでもあります

たとえば、画面上のボタンをタッチすると、UI スレッドがタッチ イベントをウィジェットにディスパッチし、ウィジェットが押された状態を設定して、無効化リクエストをイベント キューにポストします。UI スレッドはリクエストをデキューし、ウィジェット自体を再描画するように通知します。

ユーザーが longOperation を実行するボタンを押すとどうなりますか?

((Button)findViewById(R.id.Button1)).setOnClickListener(           
             new OnClickListener() {        
        @Override
    public void onClick(View v) {
            final Bitmap b = loadImageFromNetwork();
            mImageView.setImageBitmap(b);
}
});

UI がフリーズします。プログラムがクラッシュすることさえあります。

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
        final Bitmap b = loadImageFromNetwork();
        mImageView.setImageBitmap(b);
    }
  }).start();
}

これは、 UI をワーカー スレッドから直接更新しないという Android の規則に違反しています。

Android には、他のスレッドから UI スレッドにアクセスする方法がいくつか用意されています。

  • Activity.runOnUiThread(実行可能)
  • View.post(実行可能)
  • View.postDelayed(実行可能、長い)
  • ハンドラ

以下のように、

View.post(実行可能)

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      final Bitmap b = loadImageFromNetwork();
      mImageView.post(new Runnable() {
        public void run() {
          mImageView.setImageBitmap(b);
        }
      });
    }
  }).start();
}

ハンドラ

final Handler myHandler = new Handler(Looper.getMainLooper());

(new Thread(new Runnable() {

    @Override
    public void run() {
       final Bitmap b = loadImageFromNetwork();
      myHandler.post(new Runnable() {                           

        @Override
        public void run() {
           mImageView.setImageBitmap(b);
          }
        });
      }
    })).start();                
}

ここに画像の説明を入力

詳細については

http://android-developers.blogspot.com/2009/05/painless-threading.html

http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/

于 2012-12-12T12:56:46.843 に答える
20

良い答えについては、こちらをご覧ください。view.post() は handler.post() とほとんど同じです。メインスレッドキューに入り、他の保留中のタスクが終了した後に実行されます。activity.runOnUiThread() を呼び出すと、UI スレッドですぐに呼び出されます。

于 2012-12-12T12:47:45.543 に答える
5

問題は、post() メソッドを呼び出すライフサイクル メソッドにあると思います。onCreate()でやっていますか?もしそうなら、アクティビティの onResume() ドキュメントで見つけたものを見てください:

onResume()

API レベル 1 に追加されました void onResume () アクティビティがユーザーとの対話を開始するために、onRestoreInstanceState(Bundle)、onRestart()、または onPause() の後に呼び出されます。これは、アニメーションを開始したり、排他アクセス デバイス (カメラなど) を開いたりするのに適した場所です。

https://developer.android.com/reference/android/app/Activity.html#onResume()

したがって、Joe Plante が言ったように、post() を呼び出した時点でビューがアニメーションを開始する準備ができていない可能性があるため、onResume() に移動してみてください。

PD: 実際にコードを onResume() に移動する場合は、既に UI スレッドにいて、ビューでアニメーションを開始する準備ができているはずなので、post() 呼び出しを削除できると思います。

于 2016-11-15T06:09:00.903 に答える