3

私は現在、キャンバスにいくつかのタイルを描画するカスタムビューに取り組んでいます。これらのタイルはいくつかのファイルからロードされ、必要に応じてロードされます。

それらはAsyncTaskによってロードされます。すでにロードされている場合は、キャンバスにペイントされます。これは正常に機能しています!

これらの画像が読み込まれると、AsyncTaskはview.postInvalidate()を起動 します。問題は、view.postInvalidate()を起動するたびにカスタムビューonDraw(Canvasキャンバス)を起動しないことです。

view.postInvalidateは、画像がロードされたときに初めてonDraw()メソッドを起動し、次にCustomView内のonTouchEventでthis.invalidate()を起動したときにのみ起動します。

ビューがキャンバスを再度描画するかどうかを決定することは可能ですか?ビューを強制的に再描画する方法はありますか?invalidateメソッドは、ビューが再描画を検討する場合はクールであることをビューに伝えると思います-.-

それらの無効化メソッドに制限がある可能性はありますか?

皆さんがこの問題についてもっと知っていることを願っています。

編集:

画像はすべてメインスレッドから実行されるAsyncTaskによってロードされるため、すべてのpostInvalidate()invalidate( )に変更しましたが、実行されたinvalidate()がonDraw()メソッドを実行しないという問題があります。view.invalidate()は、元のメソッドをオーバーライドすることで起動されることがわかりました。

@Override
public void invalidate() {
    super.invalidate();
    Log.d(TAG, "invalidate executed");
}

今どうしたらいいのかわからない。view.invalidate()とview.postInvalidate()を起動していますが、まったく組み合わせて動作するものはありません。

4

5 に答える 5

1

ここには少し誤解があります。invalidateメソッドとpostInvalidateメソッドは、最も早い描画サイクルで更新および再描画する必要があることをビューに通知するために使用されます。違いは、invalidateメソッドはUIスレッド内から呼び出す必要があり、postInvalidateはUIスレッドの外部から呼び出す必要があることです。

これらの方法について、ここで簡単に説明します。

一方、 AsyncTaskは、特に直面している問題のために考案されたクラスです。バックグラウンドで大きなタスクを実行する必要がある場合、非同期でそのためのAsyncTaskが必要ですが、!AsyncTaskのコールバックメソッドはUIThreadで実行されます!

ここでAsyncTaskメソッドの説明を見てください:

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

  1. onPreExecute()は、タスクが実行された直後にUIスレッドで呼び出されます。この手順は通常、ユーザーインターフェイスに進行状況バーを表示するなどしてタスクを設定するために使用されます。

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

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

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

つまり、onPostExecuteメソッドでは、UIThreadから呼び出されるpostInvalidateメソッドの代わりにinvalidateメソッドを使用してみてください。

于 2012-09-03T21:33:01.217 に答える
1

setWillNotDraw(boolean)というメソッド呼び出しについて聞いたことがありますか?

こちらをチェックしてください

falseに設定すると、表示されます

于 2014-12-04T16:04:09.027 に答える
0

将来と可能なグーグルサーチャーのためにこれを保存するだけです;)

ビューのデータを提供する新しいクラスを作成しました。このクラスは、バックグラウンドでThreadとrunnsを拡張します。ビューに表示する必要のあるタイルをチェックします。

簡単に言うと、新しいタイルを表示する必要があるたびに、プロバイダークラスはいくつかの更新要求を収集します。3つ以上の更新要求が「収集」された場合、または最初の更新要求から1秒以上経過した場合、ビューはview.postInvalidate()を取得します。

問題は、一度に複数のリクエストを実行すると、ビューがいくつかの無効化リクエストを無視することでした。これらの無効化リクエストを収集し、1つのinvalidate()でそれらのいくつかを実行すると、わずかな時間の遅れで最新の情報を見ることができますが、それを見ることができます;)

于 2012-09-06T13:13:38.040 に答える
0

すべての子ビューを個別に無効にする(これらの子ビューにはそれぞれ独自のAsyncTaskが組み込まれている)が、共通の親ViewGroupを無効にすることを要求view.invalidate()するかどうかの問題を解決しました。view.postInvalidate()

今詳細に。私は持っていた

public class mViewGroup extends RelativeLayout {...}

その中のいくつかのビュー、各ビューは次のとおりです。

public class mView extends View {

private mViewGroup mContext = null;

//with a little bit modified standard constructors:
public mView (Context context, mViewGroup ParentViewGroup) {
        super(context);
        mContext = ParentViewGroup;
}

//and also with an AsyncTask:
private class mViewAsyncTask extends AsyncTask<Integer, Void, Void> {
public mAsyncTask() {
   @Override
   protected Void doInBackground(Integer... a) {
       //which does its work and sometimes publishes progress:
       publishProgress();
       return null;
   }

   protected void onProgressUpdate(Void... progress) {
       invalidate();
   }

}

の呼び出しは、機能するinvalidate();場合と機能しない場合があります(異なるAsyncTaskに属する異なるから呼び出しが行われた場合でもmView、非常に近い時間に行われた場合があります)。

変化

invalidate(); //i.e. invalidating individual View

mContext.invalidate(); //i.e. invalidating the whole ViewGroup

問題を解決しました。

于 2013-11-02T11:56:37.960 に答える
0

私の場合、ターゲットのカスタムビューにはその時点でheight = 0属性があります。(私の間違い)そしてpostInvalidate()とinvalidateはonDraw()とLogも起動しませんでした。

高さを正しく変更すると、すべての問題が解決しました。

于 2017-01-10T04:44:37.877 に答える