ScheduledThreadPoolExecutor実行莫名停止問題&Androidいくつかのアニメーションコールバック実行スレッド

5456 ワード

この文書には、次の2つの問題が記載されています.
  • ScheduleThreadPoolExecutorはなぜか実行を停止した.
  • AnimationとAnimatorの2つのアニメーションコールバックは、どのスレッドで実行されているかをリスニングします.

  • 一:ScheduleThreadPoolExecutor問題:
    ScheduledThreadPoolExecutorにおけるscheduleWithFixedDelay(command,initialDelay,delay,unit)という方法.commandというRunnableパラメータを実装します.
    質問:
    run()メソッドを実装すると、run()メソッド内でタイムズエラーが実行されると、ScheduleThreadPoolExecutorは自動的に停止し、appはクラッシュせず、logcatもエラーログを印刷しません.
    解決方法:
    apiでも紹介されていますが、executorを継続したい場合は、try catchのエラーを報告しなければなりません.エラー・スレッド・プールが実行を停止します.
    2:AnimationとAnimatorの2つのアニメーションコールバックリスニングが実行されるスレッド:
    setAnimationListener(new ...{
    onAnimationStart()
    onAnimationRepeat()
    onAnimationEnd()
    })
    1.Animation:Viewアニメーション
    まず、このコールバック呼び出しの場所を見つけます.Animationクラスで、ソースコード:
    /**
         * Sets the handler used to invoke listeners.
         * 
         * @hide
         */
        public void setListenerHandler(Handler handler) {
            if (mListenerHandler == null) {
                mOnStart = new Runnable() {
                    public void run() {
                        if (mListener != null) {
                            mListener.onAnimationStart(Animation.this);
                        }
                    }
                };
                mOnRepeat = new Runnable() {
                    public void run() {
                        if (mListener != null) {
                            mListener.onAnimationRepeat(Animation.this);
                        }
                    }
                };
                mOnEnd = new Runnable() {
                    public void run() {
                        if (mListener != null) {
                            mListener.onAnimationEnd(Animation.this);
                        }
                    }
                };
            }
            mListenerHandler = handler;
        }

    コールバックメソッドがRunnableに組み込まれているのが見えますが、理屈を言えばhandlerで処理されます.
    では、mOnStartを探します.のこれらのパラメータはどこで呼び出されましたか.
    private void fireAnimationStart() {
            if (mListener != null) {
                if (mListenerHandler == null) mListener.onAnimationStart(this);
                else mListenerHandler.postAtFrontOfQueue(mOnStart);
            }
        }

    はい、RunnableをmListener Hanlderに渡して処理しました.ではmListenerHandlerというhandlerはどこで与えられたのでしょうか.ああ..上の方法の最後に
      mListenerHandler = handler;

    最後に、Viewクラスで次のコードが見つかりました.
    if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);

    A Handler supplied by a view's {@link android.view.ViewRootImpl}. This handler can be used to pump events in the UI events queue. 
    これはAttachInfoクラスのmHandlerのコメントです.管理UIのhandlerであることがわかります.それはメインスレッドでコールバックメソッドを実行したに違いない.
    結論:Animationコールバック方法はメインスレッドにあるに違いない.
    2.Animator:属性アニメーションValueAnimatorなど
    同様に、listenerがソースコードのどこで呼び出されたかを見てみましょう.
    private void notifyStartListeners() {
            if (mListeners != null && !mStartListenersCalled) {
                ArrayList tmpListeners =
                        (ArrayList) mListeners.clone();
                int numListeners = tmpListeners.size();
                for (int i = 0; i < numListeners; ++i) {
                    tmpListeners.get(i).onAnimationStart(this);
                }
            }
            mStartListenersCalled = true;
        }
     private void start(boolean playBackwards) {
            if (Looper.myLooper() == null) {
                throw new AndroidRuntimeException("Animators may only be run on Looper threads");
            }
            ...
            if (mStartDelay == 0) {
                ...
                notifyStartListeners();
            }
            animationHandler.start();
        }
    Animatorのstart()は、上のstart(boolean)メソッドを呼び出し、notifyStartListeners()メソッドを呼び出します.このように見ると、Animatorという意味です.start()メソッドはどのスレッドで実行され、コールバックはどのスレッドで実行されますか.後でテストしましょう.次のコードに注意してください.
    AndroidRuntimeException("Animators may only be run on Looper threads");
    Animatorはサブスレッドで実行できるように見えますが、このスレッドにはlooperが必要です!はい、コードテストをしてください.
    final ValueAnimator va = ObjectAnimator.ofFloat(0, 1);
    		va.setDuration(5000);
    		va.addUpdateListener(new AnimatorUpdateListener() {
    
    			@Override
    			public void onAnimationUpdate(ValueAnimator animation) {
    				 Log.e("TAG", "onAnimationUpdate"
    				 + Thread.currentThread().getName());
    				// start             
    			}
    		});
    		va.addListener(new AnimatorListener() {
    			@Override
    			public void onAnimationStart(Animator animation) {
    				Log.e("TAG", "onAnimationStart"
    						+ Thread.currentThread().getName());
    			}
    
    			@Override
    			public void onAnimationRepeat(Animator animation) {
    				Log.e("TAG", "onAnimationRepeat"
    						+ Thread.currentThread().getName());
    			}
    
    			@Override
    			public void onAnimationEnd(Animator animation) {
    				Log.e("TAG", "onAnimationEnd"
    						+ Thread.currentThread().getName());
    			}
    
    			@Override
    			public void onAnimationCancel(Animator animation) {
    				Log.e("TAG", "onAnimationCancel"
    						+ Thread.currentThread().getName());
    			}
    		});
    
    //va.start();
    new Thread("hah") {public void run() {Looper.prepare();va.start();Looper.loop();};}.start();
    のコードテストの 、やはりstart()がプライマリスレッドで び されると、コールバックメソッドはすべてプライマリスレッドになります.「hah」というサブスレッドで び されると、コールバックメソッドはすべて「hah」サブスレッドにあります.
    :Animatorのstart()メソッドがどのスレッドで び され、コールバックがどのスレッドにあるか. :サブスレッドにはlooperが です.