Android 实用技巧:用好泛型,少写代码

SFWMonica 7年前
   <p>Android实用技巧之:用好泛型,少写代码</p>    <p>Android开发中,总会遇到大量的繁杂模版代码,重复无味的样板方法,冗长杂余的套路写法,占据了大量的开发时间,并且容易手误出错,极大地降低了编程效率和代码的优雅。</p>    <p>现在,我们通过几个小例子,讲解在TMVP中,如何通过泛型解耦和精简代码,达到高度封装简洁优雅的效果。</p>    <h3>1、基类使用泛型限定ViewDataBinding,子类直接指定泛型,一劳永逸:</h3>    <pre>  <code class="language-java">基类:  public abstract class DataBindingActivity<B extends ViewDataBinding> extends AppCompatActivity {        public B mViewBinding;        @Override       public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);            View rootView = getLayoutInflater().inflate(this.getLayoutId(), null, false);              mViewBinding = DataBindingUtil.bind(rootView);  }    子类:  public class AboutActivity extends DataBindingActivity<ActivityAboutBinding></code></pre>    <p>2、基类使用泛型限定Presenter泛型,并通过apt工厂初始化Presenter,绑定view,子类直接使用Presenter,不用再new Presenter,一劳永逸:</p>    <pre>  <code class="language-java">public abstract class BaseActivity<P extends BasePresenter, B extends ViewDataBinding> extends DataBindingActivity<B> {      public P mPresenter;        @Override      protected void initPresenter() {          if (this instanceof BaseView &&                  this.getClass().getGenericSuperclass() instanceof ParameterizedType &&                  ((ParameterizedType) (this.getClass().getGenericSuperclass())).getActualTypeArguments().length > 0) {              Class mPresenterClass = (Class) ((ParameterizedType) (this.getClass()                      .getGenericSuperclass())).getActualTypeArguments()[0];              mPresenter = InstanceUtil.getInstance(mPresenterClass);              mPresenter.setView(this);          }      }        @Override      protected void onDestroy() {          super.onDestroy();          if (mPresenter != null) mPresenter.onDetached();      }  }</code></pre>    <p>3、BaseViewHolder使用ViewDataBinding泛型限定,CoreAdapter使用BaseBean泛型限定,从此告别Adapter,ViewHolder,一劳永逸:</p>    <pre>  <code class="language-java">public class CoreAdapter<M extends BaseBean> extends RecyclerView.Adapter<BaseViewHolder> {      private TypeSelector<M> mTypeSelector;//多个viewtype的选择器      private List<M> mItemList = new ArrayList<>();        @Override      public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {          return new BaseViewHolder(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), viewType, parent, false));      }        @Override      public void onBindViewHolder(BaseViewHolder holder, int position) {          holder.mViewDataBinding.setVariable(BR.item, getItem(position));          holder.mViewDataBinding.executePendingBindings();      }</code></pre>    <h3>4、TRecyclerView使用BaseBean泛型限定,从告别OnRefresh,OnLoadMore,一劳永逸:</h3>    <pre>  <code class="language-java">public class TRecyclerView<M extends BaseBean> extends FrameLayout implements AdapterPresenter.IAdapterView {      private SwipeRefreshLayout swipeRefresh;      private RecyclerView recyclerview;      private CoreAdapter<M> mCommAdapter;      private AdapterPresenter mCoreAdapterPresenter;        public void init(Context context, AttributeSet attrs) {          swipeRefresh.setOnRefreshListener(()->mCoreAdapterPresenter.fetch(););          recyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {              int lastVisibleItem;                @Override              public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                  super.onScrollStateChanged(recyclerView, newState);                  if (recyclerview.getAdapter() != null                          && newState == RecyclerView.SCROLL_STATE_IDLE                          && lastVisibleItem + 1 == recyclerview.getAdapter()                          .getItemCount() && mCommAdapter.isHasMore)                      mCoreAdapterPresenter.fetch();              }                @Override              public void onScrolled(RecyclerView recyclerView, int arg0, int arg1) {                  super.onScrolled(recyclerView, arg0, arg1);                  lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();              }          });      }     public TRecyclerView<M> setData(List<M> data) {          mCommAdapter.setBeans(data);      }</code></pre>    <p>5、TypeSelector使用泛型类型,viewType对应layoutId,轻松实现复杂列表多viewType的选择器,一劳永逸:</p>    <pre>  <code class="language-java">public interface TypeSelector<M> {          int getType(M m);      }        TypeSelector<MessageInfo> mTypeSelector = (item) -> TextUtils.equals(item.creater.objectId, C.ADMIN_ID)              ? R.layout.list_item_comment_admin : R.layout.list_item_comment_user;// AdminID发送的为Admin消息,其他都是普通消息        @Override      public void initView() {          mViewBinding.lvMsg.setFootData(C.getAdminMsg()).setTypeSelector(mTypeSelector);          mViewBinding.lvMsg.getPresenter()              .setRepository(ApiFactory::getMessageList)              .setParam(C.INCLUDE, C.CREATER)              .setParam(C.UID, SpUtil.getUser().objectId)              .fetch();      }</code></pre>    <p>5、Repository使用泛型结果和HashMap包装多个参数,使用apt自动生成的ApiFactory返回不带泛型的Observable,从此列表类型的网络请求交给AdapterPresenter,一劳永逸:</p>    <pre>  <code class="language-java">Repository:    public interface Repository {      Observable<DataArr> getData(HashMap<String, Object> param);          public class DataArr<T> {              public ArrayList<T> results;        }  }    ApiFactory:        /**       * @此方法由apt自动生成       */      public static Observable getCommentList(HashMap param) {          return Api.getInstance().service.getCommentList(                  ApiUtil.getInclude(param),                  ApiUtil.getWhere(param),                  ApiUtil.getSkip(param),                  C.PAGE_COUNT)                  .compose(RxSchedulers.io_main());      }    AdapterPresenter:    public class AdapterPresenter {      private Repository mRepository;//仓库      private HashMap<String, Object> param = new HashMap<>();//设置仓库钥匙      private int begin = 0;      private final IAdapterView view;        public interface IAdapterView {          void setEmpty();            void setData(DataArr response, int begin);            void reSetEmpty();      }        public AdapterPresenter(IAdapterView mIAdapterViewImpl) {          this.view = mIAdapterViewImpl;      }        public AdapterPresenter setRepository(Repository repository) {          this.mRepository = repository;          return this;      }        public AdapterPresenter setParam(String key, String value) {          this.param.put(key, value);          return this;      }        public void setBegin(int begin) {          this.begin = begin;      }        public void fetch() {          begin++;          view.reSetEmpty();          if (mRepository == null) {              Log.e("mRepository", "null");              return;          }          param.put(C.PAGE, begin);          mRepository                  .getData(param)                  .subscribe(                          res -> view.setData(res, begin),                          e -> view.setEmpty());      }  }    使用:  以下代码实现了获取用户列表的请求、分页、展示,整个复杂模块就一句话实现:    public class AboutActivity extends DataBindingActivity<ActivityAboutBinding> {        @Override      public void initView() {          mViewBinding.lvUser.getPresenter().setRepository(ApiFactory::getAllUser).fetch();      }  }    用户列表的itemType也就是其layoutId,通过attr在xml中设置:      <com.base.adapter.TRecyclerView              android:id="@+id/lv_user"              android:layout_width="match_parent"              android:layout_height="wrap_content"              app:isRefreshable="false"              app:itemType="@layout/list_item_user"              app:layout_behavior="@string/appbar_scrolling_view_behavior" /></code></pre>    <h2>更新日志:</h2>    <p>2017/1/8: 使用Apt封装Retrofit生成ApiFactory替换掉所有的Repository,狂删代码</p>    <p>2017/1/7: 使用DataBinding替换掉所有的ButterKnife,狂删代码</p>    <p>2017/1/6: 使用DataBinding替换掉所有的ViewHolder,狂删代码,从此迈向新时代</p>    <p>2016/12/30:使用Apt生成全局路由TRouter,更优雅的页面跳转,支持传递参数和共享view转场动画</p>    <p>2016/12/29:去掉BaseMultiVH新增VHClassSelector支持更完美的多ViewHolder</p>    <p>2016/12/28:使用Apt生成全局的ApiFactory替代所有的Model</p>    <p>2016/12/27:增加了BaseMultiVH扩展支持多类型的ViewHolder</p>    <p>2016/12/26:抽离CoreAdapterPresenter优化TRecyclerView</p>    <p> </p>    <p> </p>