美文网首页Android知识Android开发Android技术知识
Android协调员:解决你还不知道你存在的问题

Android协调员:解决你还不知道你存在的问题

作者: 小菜鸟程序媛 | 来源:发表于2017-03-04 15:34 被阅读466次

    原文地址:https://hackernoon.com/coordinators-solving-a-problem-you-didnt-even-know-you-had-e86623f15ebf#.nm0brlclo

    Square公司有一个大多人还不知道的库-Coordinators,不是一个很具有描述性的名字,甚至在Github上也没有太多的信息。

    简单的生命周期,无论是安卓还是其他

    简单的示例代码:

    Class ExampleCoordinator extends Coordinator{
      @Override public void attach(View view){
        //附加监听器,加载状态,其他操作
      }
      
      @Override public void detach(View view){
        //解绑监听器,保存状态等
      }
    }
    

    你可以在任何View中绑定一个Coordinator

    Coordinators.bind(view,coordinatorProvider);
    

    Activity

    每个人都知道Activity,他在App中代表单个界面,而且是你定义的特定意图的入口点。

    如果要开启一个新的Activity,可以使用Intent,就像activity.startActivity(activity,OtherActivity.class)

    他们也不能嵌套,虽然之前可以使用LocalActivityManager和ActivityGroup实现嵌套,但是在Api11之后已经过时了。

    Activities通过使用setContentView()来显示View,通常假定他只能显示一种特定的布局,如果需要一个不同的界面,你就需要使用一个新的Activity代替。

    Fragments

    完整的Fragment和Activity的生命周期完整的Fragment和Activity的生命周期

    Fragment是屏幕上的一个片段,技术上显示一个自定义的视图组,被Activity中的FragmentManager所管理,Fragment与FragmentController所关联,而FragmentController与宿主Activity相关联。

    他们的设计主要是为了创建‘子屏幕功能’,继承所有重要的生命周期回调,比如onCreate()onActivityResult()onPermissionResult()、甚至是更重要的onSaveInstanceState(Bundle bundle).

    他也有自己的生命周期回调方法,比如onAttach()onCreateView()onActivityCreated()onDestroyView()onDetach().

    你可以通过getSupportFragmentManager().beginTransaction().add(R.id.container,new MyFragment()).commit();来创建一个Fragment。

    大多数时候,你只需要访问你绑定的Activity,和onCreateView()onDestroyView().

    如果有复杂的情况,你可以在一个Fragment中嵌套一个Fragment,就可以通过Fragment的getChildFragmentManager(),这有时会导致混乱,无论你使用getFragmentManager或者是getChildFragmentManager().

    有人可能会问,我们在我们Activity的子视图中真的需要这些生命周期函数吗。

    自定义Viewgroups

    你知道Activity和Fragment中有什么共同点吗,他们显示Viewgroups,都是以xml格式声明的,并且他们还有一些不错的回调。

    public class MyCustomViewGroup extends RelativeLayout {
        public MyCustomViewGroup(Context context) {
            super(context);
            init(context);
        }
    
        public MyCustomViewGroup(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        public MyCustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
        @TargetApi(21)
        public MyCustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            init(context);
        }
    
        private void init(Context context) {
            if(!isInEditMode()) {
               // ...
            }
        }  
    
        @OnClick(R.id.button)
        public void doSomething() {
            // ...
        }
      
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            ButterKnife.bind(this);
        }
      
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            // pretty much `onStart()`
        }
    
        @Override
        protected void onDetachedFromWindow() {
            // pretty much `onStop()`
            super.onDetachedFromWindow();
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <fully.qualified.MyCustomViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="Go to next"/> <!-- centerInParent works because -->
                                        <!-- custom viewgroup is also RelativeLayout -->
    </fully.qualified.MyCustomViewGroup>
    

    我们可以扩展我们的视图组(DrawableLayout、RelativeLayout、FrameLayout,LinearLayout等等),并选择我们自己定义的视图组作为需要继承的来源。

    代替getSupportFragmentManager().beginTransaction().blah().commit()我们可以轻松的实现inflateaddViewremoveView

    自定义View创建通过inflation,他有四个构造方法,需要通过继承Android特定的类来工作。

    Coordinators

    为了脱离自定义视图组的限制,我们可以将所有的试图控制器逻辑移出Viewgroup本身,并将其作为标记附加进去。

    下面是他的工作原理:

    public final class Coordinators{
      private Coordinators(){
      }
      public static void bind(View view,CoordinatorProvider provider){
        View.OnAttachStateListener binding = new Binding(coordinator,view);
        view.addOnAttachStateChangeListener(binding);
      }
    }
    ```
    
    ```
    final class Binding implements View.OnAttachStateChangeListener{
      Binding(Coordinator coordinator,View view){
        this.coordinator = coordinator;
        this.view = view;
      }
    
      @Override public void onViewAttachedToWindow(@NonNull View v){
        coordinator.attach(view);
        view.setTag(R.id.coordinator,null);
      }
      
      @Override public void onViewDetachedFromWindow(@NonNull View view){
        coordinator.detach(view);
        view.setTag(R.id.coordinator,null);
      }
    }
    ```
    你可以创建一个协调器,他可以是任何一个POJO类,并可以附加到任何自定义视图组,而无需扩展他。
    使用协调器,你会收到一个```attach(View)```和```detach(View)```回调,代替原来Viewgroup的```onAttachToWindow()```和```onDetachedFromWindow()```回调。
    
    然后将协调器实例作为标记存储,然后,协调器可以获得```Coordinator coordinator = (Coordinator)getTag(R.id.coordinator)```,这当然是由Coordinators类提供的。
    
    这有什么好处?现在我们的类是一个POJO,我们可以直接使用Dagger注入这个类,而不必指定一个void inject(MyCustomViewGroup group)方法。
    
    ```
    public class TasksCoordinator
            extends Coordinator {
        @Inject // <-- !
        public TasksCoordinator() {
        }
    
        @Inject
        TasksPresenter tasksPresenter;
    
        @OnClick(R.id.noTasksAdd)
        void openAddNewTask() {
            tasksPresenter.openAddNewTask();
        }
    
        @BindView(R.id.noTasks)
        View noTasksView;
    
        @BindView(R.id.noTasksIcon)
        ImageView noTaskIcon;
    
        // ...
      
        @Override
        protected final void attach(View view) {
            this.unbinder = ButterKnife.bind(this, view);
            presenter.takeCoordinator(this);
        }
    
        @Override
        protected final void detach(View view) {
            presenter.dropCoordinator(this);
            unbinder.unbind();
        }
    }
    ```
    有了这些,我们获得了以下好处:
    我们不需要继承一个视图组和定义4个构造函数,以便定义我们自己的“视图控制器”逻辑。
    我们可以直接从Dagger直接注入我们新创建的协调器,而不需要void inject(MyCoordinator协调器)
    我们不再需要一个Context来创建一个“视图”的实例,我们可以只创建一个Coordinator来代替。
    
    ### 结论
    
    
    就个人而言,我喜欢协调员所采取的方向。我不完全确定onAttachedToWindow()和onDetachedFromWindow()回调本身是否真的足够,但在我们自己的类中定义一个attach(View)和detach(View)方法,然后将它与一个标签相关联并不难。
    
    作为回报,我们收到一个POJO视图控制器,可以直接通过Dagger创建和注入,而无需创建4个构造函数,并在自己的XML文件中固定自定义视图组。
    
    如果导航逻辑与活动/片段分离,并且移动到Presenter层,则新的协调器方法尤其适用。它使得更清洁的代码 - 应用程序状态转换不是视图应该管理的,毕竟。
    
    这个是我的测试代码地址: [https://github.com/Zhuinden/simple-stack/tree/master/simple-stack-example-mvp](https://github.com/Zhuinden/simple-stack/tree/master/simple-stack-example-mvp).

    相关文章

      网友评论

        本文标题:Android协调员:解决你还不知道你存在的问题

        本文链接:https://www.haomeiwen.com/subject/jeadgttx.html