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

 

 

 本文由用戶 SFWMonica 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!