Android 实用技巧:用好泛型,少写代码
SFWMonica
8年前
<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>