AndroidアクセスbilityServiceによるアナログクリック機能の実現-重複機能コード多重化を実現するアーキテクチャ(5)

3913 ワード

次の予告:androidはAccessibilityServiceを利用してアナログクリック機能-コード多重アーキテクチャの注釈と詳細を実現する(6)
この記事では、アシスト機能重複論理のコード多重化について説明します.
なぜ多重化するのですか?
仮に、いいえ、実際に操作してみてください.AccessibilityServices-onAccessibilityEvent(event)メソッドでは、switch(event.getEventType()の下でcaseタイプ、クラス名を降り続け、各caseの下で、多くの機能idの判断が行われます.
通常、多くの機能の共通部分はたくさんあります.例えば、弾枠がポップアップされ、一番右のmenuボタンをクリックし、通信録のリストをスライドして友达をクリックし、ページに戻る必要があります.似たようなシーンはたくさんありますが、共通のシーンに関連するコードを抽出して多重化することを考えていますか.
of course、コードクリップalt+command+Mをstaticメソッドに抽出し、呼び出す必要がある場所で呼び出すことができます.もちろんできます.しかし、このように書くと、コードが乱れているかどうか、あるいは一歩の位置を探すのが難しいかどうか.
美しく、分析しやすい効果を達成するために、私はこのようにしました.
retrofit 2を模倣して動的エージェントを採用し、コードフラグメントを統一的に実行する
  • まず統合インタフェース
  • を作成する.
    public interface Action {
        void run(AccessibilityEvent event);
    }
    
    

    すべてのコードセグメントをActionと呼び、条件(eventType,classNameなど)を満たすとrun()に行きます.
    例えば、微信のメインインタフェースの右上隅に番号を付ける操作をクリックします.
    @EVENT_TYPE
    @EVENT_CLASS(UI_LUANCHER)
    public class ActionClickPlusAdd implements Action{
        @Override
        public void run(AccessibilityEvent event) {
           //todo find the node by this view's id ,and click it 
        }
    }
    

    ここでの注釈は,コードを簡略化するためであり,後で統一的に紹介する.
  • それから一つ一つのActionは1つのInterfaceの中に書きます(はい、retrofitの実現方式です):
  • public interface ActionService {
        /**
         *     【  】
         *
         * @param event
         */
        @TASK_IDS({TASK_MASS_SEND_GROUP, TASK_GET_ALL_GROUP_NAMES})
        @RUN(ActionClickPlusAdd.class)
        void i(AccessibilityEvent event);
    }
    
  • それからポイントです.エージェントオブジェクトを作成し、判断ロジックの統一処理を実現します.
  • 
    public class H {
    
        private ActionService service;
        private SparseArray> mTaskMethods = new SparseArray<>();
        private HashMap mActions = new HashMap<>();
    
        private static final H ourInstance = new H();
        private long  mUpdateTime ;
    
        public static H getInstance() {
            return ourInstance;
        }
    
        private H() {
    
        }
    
        public ActionService createService() {
            if (service == null) {
                service = (ActionService) Proxy.newProxyInstance(ActionService.class.getClassLoader(), new Class>[]{ActionService.class},
                        new InvocationHandler() {
    
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args)
                                    throws Throwable {
                                    //     ...
                                    
                                	ActionAssertEntity actionAssertEntity = mActions.get(method);
                                    actionAssertEntity.getAction().run(event);
                                return null;
                            }
                        });
            }
            return service;
        }
    }
    
  • それからIntentServiceでの呼び出しです:
  • public class HandleAccessibilityEventService extends IntentService {
        //          ...
        @Override
        protected void onHandleIntent(Intent intent) {
            if (intent != null) {
                AccessibilityEvent event = intent.getParcelableExtra(EXTRA_EVENT);
                if (event != null) {
                    H.getInstance().excuteServiceMethods(TaskId.get().mCurrentId, event);
                }
            }
        }
    }
    

    まとめると、特定のボタンをクリックする操作が次の2つのステップになります.
  • クラス実装Actionインタフェースを書いてrun(event)の中で論理を実現して、もちろん上は特性eventTypeとClassNameの注釈を加える必要があります;
  • このクラス名をActionServiceにくっつけて登録したのと同じです.retrofitと似ています.

  • もちろん、ある機能タスクのメソッドが初めて実行する必要がある場合、ここの処理はまず現在の機能タスクのidが持っているすべてのmethodをすべて抽出してmTaskMethodsに存在し、このmapはタスクidとmethodListのマッピングであり、イベントに対応するメソッドを実行する必要がある場合は、現在のタスクのすべてのmethodをmTaskMethodsから直接取り出し、実行します.次に,反射の過程で各action注釈に対応する属性がActionAssertEntityに格納されているため,次回は反射を繰り返して注釈属性を取得する必要がなくなる.2つのMapを多く使ったにすぎない.
    このように見ると、コードの乱れによる余分な注意力のオーバーヘッドを心配することなく、機能を実現する論理に集中することができます.
    次の記事では、使用する注釈と、エージェントオブジェクトにおける解析と判断ロジックについて具体的に説明します.