postメソッドは正確には何をしますか?


106

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

メインスレッドでアニメーションを実行しようとすると、開始しません。私が使用して言ったアニメーションを実行すると

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

それは始まります。

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

明らかに、どちらもメインスレッドでアニメーションを開始するはずなので、ここに何か不足しています...私の推測では、postがタスクをキューに追加すると、より「正しい時間」に開始されますが、知りたいと思いますここで何が起きるか

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


この動作はAndroidバージョンに固有ですか?Android 4.1.2では再現できませんでした!
Akdeniz

この動作をAndroid 2.3.3で再現しました。しかしAnimationDrawable!通常のAnimationインスタンスは、各セットアップで正常にアニメーション化し始めました。中AnimationDrawableケース; で起動しようとすると、onCreateその時点ではビューにアタッチされていないため、起動しません。したがって、のスレッド化の問題ではありませんAnimationDrawable。多分同じことが当てはまりAnimationますか? developer.android.com/guide/topics/graphics/...
Akdeniz

回答:


161

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/


15
では、ポストでアニメーションを開始するのは、メインスレッドで実行するのとは異なり、両方が最終的に同じスレッドで実行されるのはなぜですか?
ギャル

この単一スレッドモデルは、Androidアプリケーションのパフォーマンスを低下させる可能性があるためです。
Talha

1
パフォーマンスの低下は、アニメーションを表示しないこととどう関係していますか?
Gal

17
これが質問に答えるとは思いません。これは、uiスレッドとマルチスレッドについて何も知らない初心者のための一般的な答えのようなものです。これは、アニメーションをキューの前に投げるとアニメーションが機能する理由を説明していません。アニメーションは、post()やrunOnUiThread()のトリックを使用せずに、UIスレッドで直接実行するものであることになっています。
carrizo

3
すべてのUI作業はメインスレッド(UIスレッド)で行う必要があります。メインスレッドですぐに呼び出す代わりにpost()を使用してアニメーションを機能させるコツは、時間です。メインスレッドですぐに呼び出すと、「今すぐアニメーションを開始する」と言いましたが、現時点ではビューが準備できていない可能性がありますアニメーション用(測定、描画...)。しかし、それをpost()に入れると、アニメーションの準備ができているビューの準備のために、キューのstartAnimationが保留されることがあります。
NguyenDat

35

これはonCreateまたはonCreateViewで行われますか?その場合、アプリはウィンドウにビューがアタッチされている状態ではない可能性があります。ビューの測定値や位置などが計算されていない可能性があるため、ビューメトリックに基づく多くのアルゴリズムが機能しない可能性があります。Androidアニメーションは通常、UI演算を実行する必要があります

View.postは実際にビューのメッセージループでアニメーションをキューに入れるため、ビューがウィンドウにアタッチされると、手動で実行する代わりにアニメーションを実行します。

あなたは実際にUIスレッドで物事を実行していますが、別の時に


投稿者が「投稿によってRunnableが発生する(コードは別のスレッドで実行される)」とある場合、受け入れられた回答は誤解を招くものです。これは正解です。「実際にはUIスレッドで実行していますが、別のときに」-プラス1
smitty1

18

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


31
私が見つけた1つの大きな(そして非常に役立つ)違いは、viewが最初に表示されたときにview.post()の実行可能ファイルが呼び出されることです。IEでは、ビューのインフレーション時にアニメーションを開始し、将来のある時点で最終的にビュー階層に追加するように設定できます。その時点で、アニメーションが実行され、心配する必要はありません。
DeeV

実際、handler.post()は常にメインスレッドにメッセージ/実行可能ファイルをポストするとは限りません。ハンドラーの作成方法によって異なります(別のスレッドのルーパーに関連付けることができます)。一方、view.post()は常にメインスレッドで実行されます
Yair Kukielka

4

問題は、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-threadにあり、ビューがアニメーションを開始する準備ができているはずなので、post()呼び出しを削除できると思います。


3
onResume最初に「ビューの準備ができた」ときに、複数回(画面がスリープ状態になる、アクティビティがバックスタックにプッシュされるなど)呼び出されることがあります。から呼び出された場合onResume、アニメーションが既に開始されている天気を追跡して、複数回(再)開始されないようにするためにフラグが必要になる場合があります。
samis
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.