25

既存の Android プロジェクトで、次のコードに遭遇しました (デバッグごみを挿入した場所)。

ImageView img = null;

public void onCreate(...) {

    img = (ImageView)findViewById(R.id.image);

    new Thread() {
        public void run() {
            final Bitmap bmp = BitmapFactory.decodeFile("/sdcard/someImage.jpg");
            System.out.println("bitmap: "+bmp.toString()+" img: "+img.toString());
            if ( !img.post(new Runnable() {
                public void run() {
                    System.out.println("setting bitmap...");
                    img.setImageBitmap(bmp);
                    System.out.println("bitmap set.");
                }
            }) ) System.out.println("Runnable won't run!");
            System.out.println("runnable posted");
        }
    }.start();

Android 開発は初めてで、ググってみましたが、これがメイン (UI) スレッドをブロックせずに、デコード後に UI スレッドに画像を設定する方法であることを理解しています。(少なくともandroid-developersによると)Thread.currentThread().getName() (さまざまな場所でログを記録して確認しました)

現在、画像が表示されないことがあり、標準出力には次のように表示されるだけです

I/System.out( 8066): bitmap: android.graphics.Bitmap@432f3ee8 img: android.widget.ImageView@4339d698
I/System.out( 8066): runnable posted

Runnable からのメッセージの痕跡はありません。どうやらランナブルはそうではありませんrun()が、img.post()戻りますtrue。ImageView をプルしonCreate()て宣言しfinalても役に立ちません。

私は無知です。UIスレッドをブロックしながらビットマップを直接設定するだけで問題は解決しますが、私は物事を正しくしたいと考えています。誰かがここで何が起こっているのか理解していますか?

(ps。これはすべてAndroid 1.6電話とandroid-3 SDKで観察されました)

4

6 に答える 6

58

ドキュメントを見ると、View.post関連する情報がいくつかあります。

このメソッドは、このビューがウィンドウにアタッチされている場合にのみ、UI スレッドの外部から呼び出すことができます。

でこれを行っているため、まだウィンドウに接続されていないonCreate可能性があります。Viewこれを確認するには、オーバーライドonAttachedToWindowしてログに何かを入れ、投稿時にログを記録します。post が失敗すると、post 呼び出しが の前に発生することがわかりますonAttachedToWindow

他の人が述べたように、Activity.runOnUiThread独自のハンドラーを使用または提供できます。Viewただし、それ自体から直接実行したい場合は、単純にViewのハンドラーを取得できます。

view.getHandler().post(...);

これは、ある種のバックグラウンド ロードを含むカスタム ビューがある場合に特に便利です。新しい別のハンドラーを作成する必要がないという追加のボーナスもあります。

于 2012-05-04T22:45:47.580 に答える
10

問題は、UI スレッドではない別のスレッドで UI (ImageView) を更新していることだと思います。UI は、UI スレッドによってのみ更新できます。

Handlerを使用してこれを解決できます。

Handler uiHandler;

public void onCreate(){
    ...
    uiHandler = new Handler(); // This makes the handler attached to UI Thread
    ...
}

次に、次を置き換えます:

if ( !img.post(new Runnable() {

uiHandler.post(new Runnable() {

UIスレッドでimageviewが更新されていることを確認します。

Handler は非常に紛らわしい概念です。私もこれについて本当に理解するために何時間もの調査を行いました ;)

于 2010-11-03T02:36:19.197 に答える
6

あなたがそこに持っているものに明らかな問題はありません。View.post() を呼び出すと、UI スレッドで実行されるはずです。アクティビティがなくなった場合 (おそらく画面の回転によって)、ImageView は更新されませんが、たとえ見えなくても、ログ エントリには「ビットマップを設定しています ...」と表示されるはずです。

次のことを試して、違いがあるかどうかを確認することをお勧めします。

1) System.out ではなく Log.d (標準の Android ロガー) を使用する

2) Runnable を View.post() ではなく Activity.runOnUiThread() に渡します

于 2010-11-03T04:54:20.517 に答える
3

次のコードを使用すると、コードをいつでもどこでも MainThread に投稿できますが、ContextまたはActivity. view.getHandler()そうすることで、失敗や面倒なことonAttachedToWindow()などを防ぐことができます。

    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //TODO
        }
    });
于 2014-07-17T09:19:38.583 に答える
1

同じ問題があり、ハンドラが存在しないため、view.getHandler() の使用も失敗しました。runOnUiThread() が問題を解決しました。おそらくこれは、UI の準備が整うまで実際に何らかのキューイングを行います。

私にとっての原因は、基本クラスでアイコンロードタスクを呼び出し、結果が非​​常に迅速に返されたため、メインクラスがビューを確立していなかったことです(フラグメント内の getView() )。

いつか誤って失敗するのではないかと少し疑っています。しかし、私は今それの準備ができています!みんなありがとう。

于 2013-06-12T14:42:36.840 に答える