開場白給:醉鄉民謠
需求假定:有三個不同的數據請求源,每個數據源的佈局方式不同,利用recyclerview的方式展示在界面上
效果如下圖:
本次效果採用rxjava+retrofit請求數據,將所有數據合併入一個List中,在recyclerview adapter中根據類型,進行佈局的創建,並且使用了recylerview的一個setSpanSizeLookup方法,來生成不同的排列方式
先看一下Multiadpter
public class MultiTypeAdapter extends RecyclerView.Adapter<BaseViewHolder> {
private List<Vistable> modules;
private TypeFactory factory;
protected Context mContext;
public MultiTypeAdapter(List<Vistable> modules,Context context){
mContext = context;
this.modules = modules;
factory = new TypeFactoryList();
}
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(viewType, parent, false);
return factory.createViewHolder(viewType, view);
}
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
holder.bindViewData(modules.get(position),position,mContext,this);
}
@Override
public int getItemCount() {
return modules == null? 0:modules.size();
}
@Override
public int getItemViewType(int position) {
return modules.get(position).type(factory);
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if (manager == null || !(manager instanceof GridLayoutManager)) return;
((GridLayoutManager) manager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (getItemViewType(position)== R.layout.android_layout_item){
return 2;
}else if (getItemViewType(position) == R.layout.ios_layout_item){
return 2;
}else
return 1;
}
});
}
}
getItemViewType使用工廠方法進行獲取,避免進行類型判斷:
首先定義了一個藉口,所有的bean類都要實現該接口,從而拿到響應的佈局,不再寫在adapter中,而是從數據源下手
public interface Vistable {
int type(TypeFactory factory);
}
持有一個工廠類,用於根據bean獲取響應的佈局
//定義了所使用的類型,並且將viewholder的創建加入進來:抽取BaseViewHolder
public interface TypeFactory {
int type(AndroidBean androidData);
int type(GirlBean beautifulGirlBean);
int type(IosBean resultBean);
BaseViewHolder createViewHolder(int type, View itemView);
}
public abstract class BaseViewHolder extends ViewHolder{
private SparseArray sparseArray;
private View mItemView;
public BaseViewHolder(View itemView) {
super(itemView);
sparseArray = new SparseArray<>();
mItemView = itemView;
}
public <T extends View> T getView(int resId){
View view = sparseArray.get(resId);
if (view == null){
view = mItemView.findViewById(resId);
sparseArray.put(resId,view);
}
return (T) view;
}
public abstract void bindViewData(T data,int position,Context context,MultiTypeAdapter adapter);
}
//實現類中用於具體的實現
public class TypeFactoryList implements TypeFactory{
public static final int ANDROID_LAYOUT = R.layout.android_layout_item;
public static final int GIRL_LAYOUT = R.layout.girl_image_layout;
public static final int WECHAT_LAYOUT = R.layout.ios_layout_item;
@Override
public int type(AndroidBean androidData) {
return ANDROID_LAYOUT;
}
@Override
public int type(GirlBean beautifulGirlBean) {
return GIRL_LAYOUT;
}
@Override
public int type(IosBean iosData) {
return WECHAT_LAYOUT;
}
@Override
public BaseViewHolder createViewHolder(int type, View itemView) {
switch (type){
case ANDROID_LAYOUT:
return new AndroidViewHolder(itemView);
case GIRL_LAYOUT:
return new GirlViewHolder(itemView);
case WECHAT_LAYOUT:
return new IosViewHolder(itemView);
default:
return null;
}
}
}
這樣的好處我們再添加新類型的時候不必再去操作adapter,比較清晰,雖然代碼比較多,但閱讀起來很方便,
看一個具體的viewholer類
public class AndroidViewHolder extends BaseViewHolder<AndroidBean> {
public AndroidViewHolder(View itemView) {
super(itemView);
}
@Override
public void bindViewData(final AndroidBean module, int position, final Context context, MultiTypeAdapter adapter) {
LinearLayout ll = getView(R.id.multi_android_ll);
ll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
WebActivity.loadUrl(context,module.getUrl());
}
});
((TextView) getView(R.id.multi_android_tv)).setText(module.getDesc());
ImageView img = getView(R.id.multi_android_iv);
GlideApp.with(context).load(R.drawable.home_six_5).into(img);
在看一個bean類
public class AndroidBean implements Vistable{
/**
* _id : 5990fb20421aa96729c57239
* createdAt : 2017-08-14T09:21:36.634Z
* desc : PlayPauseView:讓播放、暫停按鈕優雅的過渡
* images : ["http://img.gank.io/8ca1bb97-8d30-4deb-9645-a2c2da1970ab"]
* publishedAt : 2017-08-14T17:04:50.266Z
* source : web
* type : Android
* url : https://github.com/Lauzy/PlayPauseView
* used : true
* who : Lauzy
*/
private String _id;
private String createdAt;
private String desc;
private String publishedAt;
private String source;
private String type;
private String url;
private boolean used;
private String who;
private List<String> images;
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getPublishedAt() {
return publishedAt;
}
public void setPublishedAt(String publishedAt) {
this.publishedAt = publishedAt;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public boolean isUsed() {
return used;
}
public void setUsed(boolean used) {
this.used = used;
}
public String getWho() {
return who;
}
public void setWho(String who) {
this.who = who;
}
public List<String> getImages() {
return images;
}
public void setImages(List<String> images) {
this.images = images;
}
@Override
public int type(TypeFactory factory) {
return factory.type(this);
}
}
使用:
public class WechatActivity extends AppCompatActivity implements CommonImpl {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.wechat_xry)
RecyclerView wechatXry;
private MultiTypeAdapter adapter;
private List<Vistable> moudles= new ArrayList<>();
private MultiMoudle recommendMoudle;
private GridLayoutManager manager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wechat);
ButterKnife.bind(this);
initoolbar();
initView();
initData();
initListener();
}
private void initListener() {
// adapter.setmOnItemClickListener(this);
}
private void initData() {
recommendMoudle.getAllData(this);
}
private void initView() {
CustomProgressDialog.show(this,"正在獲取數據...",false,null);
recommendMoudle = new MultiMoudle();
//設置默認的
manager = new GridLayoutManager(this,2);
wechatXry.setLayoutManager(manager);
wechatXry.setNestedScrollingEnabled(false);
wechatXry.setHasFixedSize(false);
wechatXry.setItemAnimator(new DefaultItemAnimator());
adapter = new MultiTypeAdapter(moudles,this);
wechatXry.setAdapter(adapter);
}
private void initoolbar() {
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setTitle("乾貨集錦");
toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
@Override
public void loadFailed() {
CustomProgressDialog.dismisses();
}
@Override
public void addDisaposed(Disposable disposable) {
}
@Override
public void loadMultiSuccess(List<Vistable> vistable) {
moudles.addAll(vistable);
CustomProgressDialog.dismisses();
adapter.notifyDataSetChanged();
}
接下說一下數據獲取的處理:因爲我們有三個數據源,我們希望等全部數據獲取完畢後,再去加載數據,那麼用Rxjava怎麼實現呢:
這就用到了zip操作符:它可以監視多個Observable,等所有的Observable上游事件處理完畢,再將其按順序進行合併,這正是我們想要的效果
來看實際運用:相信大家一看就明白了
public void getAllData(final CommonImpl listener){
ApiService service = ServiceManager.getInstance(Constants.API_GANKIO).creat(ApiService.class);
Observable<AndroidData> androidDataObservable = service
.getAndroid()
.subscribeOn(Schedulers.io());
Observable<BeautifulGirlBean> beautifulGirlBeanObservable = service
.getGirls()
.subscribeOn(Schedulers.io());
Observable<IosData> iosDataObservable = service
.getIos()
.subscribeOn(Schedulers.io());
// Observable<WeChatListBean> weChatListBeanObservable = ServiceManager.getInstance(Constants.API_MOB).creat(ApiService.class)
// .weChatSearchListBeanList(cid, page, 20)
// .subscribeOn(Schedulers.io());
Observable.zip(androidDataObservable, beautifulGirlBeanObservable, iosDataObservable, new Function3<AndroidData, BeautifulGirlBean, IosData, List<Vistable>>() {
@Override
public List<Vistable> apply(@NonNull AndroidData androidData, @NonNull BeautifulGirlBean beautifulGirlBean, @NonNull IosData iosData) throws Exception {
List<Vistable> list = new ArrayList<Vistable>();
list.addAll(androidData.getResults());
list.addAll(beautifulGirlBean.getResults());
list.addAll(iosData.getResults());
return list;
}
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<List<Vistable>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull List<Vistable> vistables) {
listener.loadMultiSuccess(vistables);
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
}