責任連鎖モードと Android イベント配信

前に書かれています:

        Android 開発者として、多くの人がインタビュー中に次の 2 つの質問に遭遇したことがあります: 1. よく知っているデザイン パターンについて話す; 2. Android のタッチ イベント分散メカニズム。この記事では、一連の責任パターンを設計パターンに組み合わせて、Android タッチ イベントの配布をシミュレートします。

  1. 責任モデルの連鎖

        責任の連鎖モデルとは、簡単に言うと、複数の責任者が連鎖的につながったもので、現在の責任者にイベントが配信され、現在の責任者が対応しなければ、次のノードに引き継がれるというものです。誰もそれを処理しないまで責任者. それは、私たちが通常「ボールを蹴る」と言うようなものです. 責任の連鎖の主な機能は、責任の連鎖の各責任者が職務を遂行できるように、送信者と受信者を切り離すことです。「連鎖」といえば、その構造は実はデータ構造の連結リストに非常に似ており、一般的に言えば、一方通行の責任連鎖であれば、現在の責任者が次の責任者の参照を保持することができます。 . 双方向の責任連鎖である場合、現在のノードは、前後の責任者への参照を保持します。

2.イベント配信

        ユーザーのタッチ イベントがディスパッチされ、現在のアクティビティから消費されます。デフォルトでは、アクティビティはイベントを消費せず、アクティビティはそれが接続されているウィンドウに渡され、ウィンドウは superDispatchTouchEvent() を介してルート ビューに渡されます。 onCreate() の始まり。一般的に言えば、ルート ビューは ViewGroup です。ViewGroup はデフォルトではイベントを消費しませんが、イベントをインターセプトする方法がもう 1 つあります。デフォルトでは、イベントをインターセプトせず、処理のために次のレベルのビューに引き渡します。ViewGroup が必要な場合現在のイベントを処理するには、onInterceptTouchEvent() メソッドを書き換えて true を返し、それを ViewGroup の onTouchEvent メソッドに渡して処理します。イベントは通常、ビューに渡されるときに処理され、クリック イベント、長押しイベントなどになります。ビューが消費しない場合、タッチ イベントは元のパスに沿って戻ります。したがって、大規模なプロセスで言えば、イベントの配信メカニズムは、Activity -> Window -> View (広義には、ViewGroup とそのサブビューを含む) であり、このイベント配信モデルの観点からは、実際には 2 つのイベント配信モデルです。 - 責任の連鎖。実際、Android のイベント配信では、一連の責任パターンが使用されています。(質問の差し引きを開始)

3. 武魂融合術 - コードを見せて

        最初に責任者の基本クラスを作成します。各責任者はこの基本クラスを継承して実装します。物事を単純化するために、Activity をシミュレートしてそのウィンドウとルート View を見つけるプロセスを省略し、Activity から ViewGroup、サブ View へのイベントの配布プロセスをシミュレートします。各責任者には、責任の連鎖で各責任者を接続するための分散メソッドがあります。

abstract class AbsTouch {
    var next:AbsTouch?=null//下一责任人
    var previous:AbsTouch?=null//上一责任人
    private var isDispatched=false//是否从上一责任人转发下来过

    //事件分发主要方法
    open fun dispatch(event: String){
        val onTouch = onTouch(event)//具体事件处理
        //事件被处理则责任链结束,不再向上或向下传递
        if (onTouch){
            println("$event 事件被处理")
            return
        }
        //事件第一次来且不是责任链最后一位责任人,向下传递
        if (!isDispatched&&next!=null){
            println("懒得处理,给下一位 $event")
            isDispatched=true
            next?.dispatch(event)
        }else{
            //事件不是第一次来或者是责任链最后一位责任人,向上回传
            println("懒得处理,给上一位 $event")
            previous?.dispatch(event)
        }
    }

    //具体决定是否消费触摸事件
    abstract fun onTouch(event: String):Boolean
}

Activity、ViewGroup、View の 3 人の責任者をシミュレートする 3 つのクラスを実装します。アクティビティには onTouchEvent メソッドしかありません

class Activity : AbsTouch(){
    val TAG=Activity::class.simpleName
    override fun onTouch(event: String): Boolean {
        println("$TAG:$event 来啦")
        //activity默认不处理,返回false
        return false
    }

}

ViewGroup には、イベントをインターセプトするための onInterceptTouchEvent メソッドがもう 1 つあります。 

open class ViewGroup : AbsTouch(){
    val TAG=ViewGroup::class.simpleName

    //ViewGroup是否消费先决条件为是否拦截,不拦截直接转发
    //拦截的话传给onTouchEvent
    override fun dispatch(event: String) {
        if (onIntercept())
            onTouch(event)
        else super.dispatch(event)
    }

    override fun onTouch(event: String): Boolean {
        println("$TAG:$event 来啦")
        return false
    }

    //相较于Activity和View ,ViewGroup多了一个onInterceptTouchEvent()方法
    //且默认不拦截
    open fun onIntercept():Boolean{
        return false
    }

}

また、View には onTouchEvent メソッドが 1 つしかありません。デフォルトでは true を返します = イベントを消費します。 

class View : AbsTouch(){
    val TAG=View::class.simpleName
    var clickAbel=true
    //view的onTouchEvent默认返回true
    //当用户自定义为false或设置clickable=false时,view不消费事件
    override fun onTouch(event: String): Boolean {
        println("$TAG:$event 来啦")
        return clickAbel
    }    

}

 3 人の責任者をインスタンス化し、それらの間の関係を責任の連鎖に確立します。イベントはアクティビティから開始され、デフォルトの ViewGroup は状況をインターセプトしません

@Test
fun onClick(){
    val activity= Activity()
    val viewGroup = ViewGroup()
    activity.next=viewGroup
    viewGroup.previous=activity
    val view = View()
    viewGroup.next=view
    view.previous=viewGroup
    activity.dispatch("点击事件")
}

イベント配信結果は以下の通り 

イベントをインターセプトする ViewGroup のメソッドを書き換え、責任の連鎖で ViewGroup を置き換えます. イベントがインターセプトされると、イベントはこの ViewGroup によって処理され、転送されません.

class NewViewGroup:ViewGroup() {
    override fun onIntercept(): Boolean {
        return true
    }
}

現時点でのイベント配信結果は以下の通りです。 

 

処理しない場合、イベント配信プロセスは次のようになります。 

 裏面に次のように書きます。

       1.責任モデルは実際には非常に単純です.主なことは、基本クラスがチェーン上の隣接ノードへの参照を保持し、ビジネスロジックに従って分散メソッドを実装することです. 利用シーンもいろいろありますが、ここでのイベント配信以外にも、一般的なokhttpインターセプターもこのデザインパターンを採用しています。

       2. イベント配信 3 つの主な役割は、Activity、Window、View です。

        3 つの主要なアプローチ

        dispatchTouchEvent: チェーン上の隣接するノードに接続して、イベントを配布します。

        onInterceptTouchEvent: ViewGroup に固有で、イベントをインターセプトし、インターセプト後にその onTouchEvent に直接移動します。

        onTouchEvent: イベントを処理するかどうか、およびそれらを処理する方法。

実装例とは異なり、クリック イベントは単一のイベントではなく一連のイベント ストリームであることが多く、担当者が最初の ACTION_DOWN メソッドを処理しないことを選択した場合、それがもたらす後続のイベント ストリームはビューによって処理されません。この記事では、一般的な観点から一般的なプロセスについて説明します. 言及されていない詳細については、このグラフィック Android イベント配信メカニズム、または他の書籍や資料を参照できます. 表現に誤りがありましたら、訂正をお願いします。

        

おすすめ

転載: blog.csdn.net/qq_37841321/article/details/120029372