Android 實用技巧:用好泛型,少寫代碼
Android實用技巧之:用好泛型,少寫代碼
Android開發中,總會遇到大量的繁雜模版代碼,重復無味的樣板方法,冗長雜余的套路寫法,占據了大量的開發時間,并且容易手誤出錯,極大地降低了編程效率和代碼的優雅。
現在,我們通過幾個小例子,講解在TMVP中,如何通過泛型解耦和精簡代碼,達到高度封裝簡潔優雅的效果。
1、基類使用泛型限定ViewDataBinding,子類直接指定泛型,一勞永逸:
基類:
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>
2、基類使用泛型限定Presenter泛型,并通過apt工廠初始化Presenter,綁定view,子類直接使用Presenter,不用再new Presenter,一勞永逸:
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();
}
}
3、BaseViewHolder使用ViewDataBinding泛型限定,CoreAdapter使用BaseBean泛型限定,從此告別Adapter,ViewHolder,一勞永逸:
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();
}
4、TRecyclerView使用BaseBean泛型限定,從告別OnRefresh,OnLoadMore,一勞永逸:
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);
}
5、TypeSelector使用泛型類型,viewType對應layoutId,輕松實現復雜列表多viewType的選擇器,一勞永逸:
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();
}
5、Repository使用泛型結果和HashMap包裝多個參數,使用apt自動生成的ApiFactory返回不帶泛型的Observable,從此列表類型的網絡請求交給AdapterPresenter,一勞永逸:
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" />
更新日志:
2017/1/8: 使用Apt封裝Retrofit生成ApiFactory替換掉所有的Repository,狂刪代碼
2017/1/7: 使用DataBinding替換掉所有的ButterKnife,狂刪代碼
2017/1/6: 使用DataBinding替換掉所有的ViewHolder,狂刪代碼,從此邁向新時代
2016/12/30:使用Apt生成全局路由TRouter,更優雅的頁面跳轉,支持傳遞參數和共享view轉場動畫
2016/12/29:去掉BaseMultiVH新增VHClassSelector支持更完美的多ViewHolder
2016/12/28:使用Apt生成全局的ApiFactory替代所有的Model
2016/12/27:增加了BaseMultiVH擴展支持多類型的ViewHolder
2016/12/26:抽離CoreAdapterPresenter優化TRecyclerView