瀏覽代碼

完成京东商品展示

詹子聪 5 年之前
父節點
當前提交
425fc20705

+ 0 - 1
app/build.gradle

@@ -75,7 +75,6 @@ dependencies {
     api project(path: ':common')
     implementation project(path: ':network')
     implementation project(path: ':mvp')
-    implementation project(path: ':adapter')
     //compile "androidx.core:core-ktx:+"
     //compile "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
     //implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

+ 5 - 0
app/src/main/java/com/itant/shibei/base/ApiService.java

@@ -4,6 +4,7 @@ import com.itant.shibei.bean.BeiUser;
 import com.itant.shibei.bean.GoodsBean;
 import com.miekir.network.core.base.BaseResponse;
 
+import java.util.List;
 import java.util.Map;
 
 import io.reactivex.Observable;
@@ -45,4 +46,8 @@ public interface ApiService {
     /**删除京东商品*/
     @GET("/shibei/api/deleteGoodsById")
     Observable<BaseResponse<String>> deleteGoodsById(@Query("goodsId") long goodsId);
+
+    /**分页查询京东商品*/
+    @GET("/shibei/api/getGoodsList")
+    Observable<BaseResponse<List<GoodsBean>>> getGoodsList(@Query("pageNum") int pageNum, @Query("pageSize") int pageSize);
 }

+ 85 - 37
app/src/main/java/com/itant/shibei/net/RetrofitHelper.java

@@ -1,6 +1,7 @@
 package com.itant.shibei.net;
 
 import android.content.Context;
+import android.util.Log;
 
 import com.itant.shibei.manager.UserInfoManager;
 import com.miekir.network.BuildConfig;
@@ -8,12 +9,27 @@ import com.miekir.network.core.RetrofitInstaller;
 import com.readystatesoftware.chuck.ChuckInterceptor;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 import java.util.concurrent.TimeUnit;
 
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
 import okhttp3.Interceptor;
 import okhttp3.OkHttpClient;
 import okhttp3.Request;
 import okhttp3.Response;
+import okhttp3.logging.HttpLoggingInterceptor;
 import retrofit2.Retrofit;
 import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
 import retrofit2.converter.gson.GsonConverterFactory;
@@ -30,13 +46,61 @@ public class RetrofitHelper {
 
     private Context mContext;
     private Retrofit mRetrofit;
+    private Retrofit mOtherRetrofit;
     private OkHttpClient mOkHttpClient;
+    private OkHttpClient mOtherClient;
+
+    private Interceptor mHeaderInterceptor = new Interceptor() {
+        @Override
+        public Response intercept(Chain chain) throws IOException {
+            String token = "";
+            String email = "";
+            if (UserInfoManager.getInstance().isLogin()) {
+                token = UserInfoManager.getInstance().getBeiUser().token;
+                email = UserInfoManager.getInstance().getBeiUser().email;
+            }
+            Request request = chain.request()
+                    .newBuilder()
+                    .addHeader("token", token)
+                    .addHeader("email", email)
+                    .build();
+            return chain.proceed(request);
+        }
+    };
+
+    private static SSLSocketFactory getSSLContext (Context context){
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            //privatekey.crt证书文件,将它放在Assets目录下
+            InputStream is =  context.getAssets().open("lomsxj.crt");
+
+            Certificate ca = cf.generateCertificate(is);
+            Log.i("getSSLContext ", "ca=" + ((X509Certificate) ca).getSubjectDN());
+
+            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+            keyStore.load(null,null);
+            keyStore.setCertificateEntry("ca",ca);
+
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+            tmf.init(keyStore);
+
+            SSLContext ssContext = SSLContext.getInstance("TLSv1", "AndroidOpenSSL");
+            ssContext.init(null,tmf.getTrustManagers(),null);
+
+            return ssContext.getSocketFactory();
+
+        } catch (CertificateException | KeyManagementException | NoSuchProviderException | NoSuchAlgorithmException | KeyStoreException | IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
 
     private RetrofitHelper() {
         mContext = RetrofitInstaller.mInstallerContext;
 
         // 默认请求的超时等配置
         mOkHttpClient = getDefaultOkHttpClient();
+        mOtherClient = getDefaultOkHttpClient();
 
         // 默认请求的地址、转换规则等配置,Base URL以不能包含路径,只能是http://加上IP或域名
         mRetrofit = new Retrofit.Builder()
@@ -60,53 +124,23 @@ public class RetrofitHelper {
         }
     }
 
-    /**
-     * 设置请求的host,转换规则也用默认的
-     * @param baseUrl 请求的host
-     */
-    public void setRequestHost(String baseUrl) {
-        mRetrofit = new Retrofit.Builder()
-                .baseUrl(baseUrl)
-                .client(mOkHttpClient)
-                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
-                .addConverterFactory(GsonConverterFactory.create())
-                .build();
-    }
-
-    /**
-     * 设置请求的客户端
-     */
-    public void setRetrofit(Retrofit retrofit) {
-        mRetrofit = retrofit;
-    }
-
     /**
      *
      * @return 默认的请求设置
      */
     public OkHttpClient getDefaultOkHttpClient() {
-        Interceptor headInterceptor = new Interceptor() {
+        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
             @Override
-            public Response intercept(Chain chain) throws IOException {
-                String token = "";
-                String email = "";
-                if (UserInfoManager.getInstance().isLogin()) {
-                    token = UserInfoManager.getInstance().getBeiUser().token;
-                    email = UserInfoManager.getInstance().getBeiUser().email;
-                }
-                Request request = chain.request()
-                        .newBuilder()
-                        .addHeader("token", token)
-                        .addHeader("email", email)
-                        .build();
-                return chain.proceed(request);
+            public void log(String message) {
+                //LogTool.logInfo("Retrofit:", message);
             }
-        };
+        });
+        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
 
         return new OkHttpClient.Builder()
-                .addInterceptor(headInterceptor)
+                .addInterceptor(mHeaderInterceptor)
                 //.addInterceptor(interceptor)
-                //.addInterceptor(dataInterceptor)
+                //.sslSocketFactory(getSSLContext(context))
                 .addInterceptor(new ChuckInterceptor(mContext))
                 .retryOnConnectionFailure(true)
                 .connectTimeout(20, TimeUnit.SECONDS)
@@ -122,4 +156,18 @@ public class RetrofitHelper {
     public <T> T getRequestApi(Class<T> apiClass) {
         return mRetrofit.create(apiClass);
     }
+
+    /**
+     *
+     * @return 请求接口
+     */
+    public <T> T getRequestApi(Class<T> apiClass, String baseUrl) {
+        mOtherRetrofit = new Retrofit.Builder()
+                .baseUrl(baseUrl)
+                .client(mOtherClient)
+                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
+                .addConverterFactory(GsonConverterFactory.create())
+                .build();
+        return mOtherRetrofit.create(apiClass);
+    }
 }

+ 0 - 5
app/src/main/java/com/itant/shibei/tool/DataTool.java

@@ -81,11 +81,6 @@ public class DataTool {
         goodsBean.salesPerMonth = 1022;
         goodsBean.goodCommentPercent = 0.98d;
         goodsList.add(goodsBean);
-        goodsList.add(goodsBean);
-        goodsList.add(goodsBean);
-        goodsList.add(goodsBean);
-        goodsList.add(goodsBean);
-        goodsList.add(goodsBean);
         return goodsList;
     }
 }

+ 9 - 11
app/src/main/java/com/itant/shibei/ui/function/template/TemplateAdapter.java

@@ -6,13 +6,16 @@ import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.widget.ImageView;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.bumptech.glide.Glide;
 import com.bumptech.glide.load.engine.DiskCacheStrategy;
 import com.bumptech.glide.request.RequestOptions;
 import com.bumptech.glide.request.target.SimpleTarget;
 import com.bumptech.glide.request.transition.Transition;
-import com.itant.library.recyclerview.CommonAdapter;
-import com.itant.library.recyclerview.base.ViewHolder;
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.BaseViewHolder;
 import com.itant.shibei.R;
 import com.itant.shibei.bean.CouponBean;
 import com.miekir.common.utils.ActivityTool;
@@ -21,25 +24,20 @@ import com.miekir.common.utils.ToastTool;
 import java.util.List;
 
 /**
- *
- *
  * @author Miekir
  * @date 2020/7/6 20:08
  * Description: 首页商品适配器
  */
-public class TemplateAdapter extends CommonAdapter<CouponBean> {
-    private List<CouponBean> mTemplateList;
+public class TemplateAdapter extends BaseQuickAdapter<CouponBean, BaseViewHolder> {
     //private int mRadius = 8;
 
-    public TemplateAdapter(Context context, List<CouponBean> couponBeanList) {
-        super(context, R.layout.item_template, couponBeanList);
-        mTemplateList = couponBeanList;
+    public TemplateAdapter(Context context, @Nullable List<CouponBean> data) {
+        super(R.layout.item_template, data);
         //mRadius = (int) context.getResources().getDimension(R.dimen.margin_s);
     }
 
-
     @Override
-    protected void convert(ViewHolder holder, CouponBean couponBean, int position) {
+    protected void convert(@NonNull BaseViewHolder holder, CouponBean couponBean) {
         ImageView iv_template = holder.getView(R.id.iv_template);
         // 圆角
         Glide.with(mContext).load(couponBean.coverUrl)

+ 1 - 2
app/src/main/java/com/itant/shibei/ui/function/template/TemplateFragment.java

@@ -6,7 +6,6 @@ import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.itant.library.recyclerview.CommonAdapter;
 import com.itant.shibei.R;
 import com.itant.shibei.base.ITopActionListener;
 import com.itant.shibei.bean.CouponBean;
@@ -24,7 +23,7 @@ import java.util.List;
 public class TemplateFragment extends BaseMVPFragment implements ITemplateView, ITopActionListener {
     private int mTemplateType = FunctionFragment.TEMPLATE_TYPE_BONUS;
     private List<CouponBean> mCouponBeanList = new ArrayList<>();
-    private CommonAdapter<CouponBean> mAdapter;
+    private TemplateAdapter mAdapter;
     private RecyclerView rv_template;
 
     @InjectPresenter

+ 10 - 11
app/src/main/java/com/itant/shibei/ui/home/GoodsAdapter.java

@@ -9,6 +9,8 @@ import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.appcompat.widget.AppCompatImageView;
 
 import com.bumptech.glide.Glide;
@@ -17,8 +19,8 @@ import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
 import com.bumptech.glide.request.RequestOptions;
 import com.bumptech.glide.request.target.SimpleTarget;
 import com.bumptech.glide.request.transition.Transition;
-import com.itant.library.recyclerview.CommonAdapter;
-import com.itant.library.recyclerview.base.ViewHolder;
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.BaseViewHolder;
 import com.itant.shibei.R;
 import com.itant.shibei.bean.GoodsBean;
 import com.itant.shibei.common.ConstantString;
@@ -35,19 +37,18 @@ import java.util.List;
  * @date 2020/7/6 20:08
  * Description: 首页商品适配器
  */
-public class GoodsAdapter extends CommonAdapter<GoodsBean> {
+public class GoodsAdapter extends BaseQuickAdapter<GoodsBean, BaseViewHolder> {
     private Context mContext;
     private int mRadius;
 
-    public GoodsAdapter(Context context, List<GoodsBean> goodsList) {
-        super(context, R.layout.item_goods, goodsList);
-        mContext = context;
+    public GoodsAdapter(Context context, @Nullable List<GoodsBean> data) {
+        super(R.layout.item_goods, data);
         mRadius = (int) context.getResources().getDimension(R.dimen.margin_ss);
+        mContext = context;
     }
 
-
     @Override
-    protected void convert(ViewHolder holder, GoodsBean goodsBean, int position) {
+    protected void convert(@NonNull BaseViewHolder holder, GoodsBean goodsBean) {
         holder.setText(R.id.tv_title, goodsBean.title);
         holder.setText(R.id.tv_shop_name, goodsBean.shopName);
 
@@ -117,7 +118,7 @@ public class GoodsAdapter extends CommonAdapter<GoodsBean> {
             View view = holder.getView(R.id.cv_goods);
             view.setOnLongClickListener(v -> {
                 if (goodsLongClickListener != null) {
-                    goodsLongClickListener.onGoodsLongClick(position);
+                    goodsLongClickListener.onGoodsLongClick(holder.getLayoutPosition());
                 }
                 return false;
             });
@@ -125,7 +126,6 @@ public class GoodsAdapter extends CommonAdapter<GoodsBean> {
     }
 
     private GoodsLongClickListener goodsLongClickListener;
-
     public GoodsLongClickListener getGoodsLongClickListener() {
         return goodsLongClickListener;
     }
@@ -133,7 +133,6 @@ public class GoodsAdapter extends CommonAdapter<GoodsBean> {
     public void setGoodsLongClickListener(GoodsLongClickListener goodsLongClickListener) {
         this.goodsLongClickListener = goodsLongClickListener;
     }
-
     public interface GoodsLongClickListener {
         void onGoodsLongClick(int position);
     }

+ 70 - 8
app/src/main/java/com/itant/shibei/ui/home/GoodsFragment.java

@@ -10,12 +10,15 @@ import androidx.annotation.Nullable;
 import androidx.appcompat.app.AlertDialog;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
 import com.itant.shibei.R;
 import com.itant.shibei.base.ITopActionListener;
 import com.itant.shibei.bean.GoodsBean;
+import com.itant.shibei.tool.DataTool;
 import com.itant.shibei.ui.mine.goods.AddGoodsActivity;
 import com.itant.shibei.widget.DividerItemDecoration;
+import com.itant.shibei.widget.bottomlistener.OnRcvScrollListener;
 import com.miekir.common.utils.ToastTool;
 import com.miekir.mvp.presenter.InjectPresenter;
 import com.miekir.mvp.view.BaseMVPFragment;
@@ -36,16 +39,20 @@ import static android.app.Activity.RESULT_OK;
  */
 public class GoodsFragment extends BaseMVPFragment implements IGoodsView, ITopActionListener {
     private static final int PAGE_START = 0;
+    private static final int PAGE_SIZE = 20;
 
     @InjectPresenter
     GoodsPresenter mPresenter;
 
+    private SwipeRefreshLayout srl_goods;
     private GoodsAdapter mAdapter;
     private RecyclerView rv_goods;
     private List<GoodsBean> mGoodsList = new ArrayList<>();
 
     /**当前页*/
     private int mCurrentPage = PAGE_START;
+    /**是否下拉获取数据*/
+    private boolean mIsRefresh = true;
 
     private ImageView iv_empty;
 
@@ -67,12 +74,47 @@ public class GoodsFragment extends BaseMVPFragment implements IGoodsView, ITopAc
         int dividerWidth = (int) getResources().getDimension(R.dimen.margin_s);
         DividerItemDecoration decoration = new DividerItemDecoration(dividerWidth);
         rv_goods.addItemDecoration(decoration);
+        // 本地写死的数据
+        mGoodsList.addAll(DataTool.getGoodsList());
         mAdapter = new GoodsAdapter(getActivity(), mGoodsList);
         mAdapter.setGoodsLongClickListener(this::showAdminDialog);
         rv_goods.setAdapter(mAdapter);
+        // 不要滑动一段距离
+        rv_goods.smoothScrollToPosition(0);
+        srl_goods = rootView.findViewById(R.id.srl_goods);
+        srl_goods.setColorSchemeResources(
+                R.color.black_theme,
+                R.color.blue_droid,
+                R.color.yellow_droid,
+                R.color.red_droid);
+
+        // 下拉刷新
+        srl_goods.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+            @Override
+            public void onRefresh() {
+                mIsRefresh = true;
+                mCurrentPage = PAGE_START;
+                mPresenter.getGoodsData(mCurrentPage, PAGE_SIZE);
+            }
+        });
+
+        // 加载更多
+        rv_goods.addOnScrollListener(new OnRcvScrollListener(){
+            @Override
+            public void onBottom() {
+                super.onBottom();
+                // 如果到底部了,而且不是正在加载状态,就变为正在加载状态,并及时去加载数据
+                if (!srl_goods.isRefreshing()) {
+                    mIsRefresh = false;
+                    srl_goods.setRefreshing(true);
+                    mPresenter.getGoodsData(mCurrentPage, PAGE_SIZE);
+                }
+            }
+        });
 
         // 获取数据
-        mPresenter.getGoodsData();
+        srl_goods.setRefreshing(true);
+        mPresenter.getGoodsData(mCurrentPage, PAGE_SIZE);
     }
 
     /**
@@ -125,22 +167,37 @@ public class GoodsFragment extends BaseMVPFragment implements IGoodsView, ITopAc
         alertDialog.show();
     }
 
+    /**
+     * 获取商品结果
+     * @param success
+     * @param message
+     * @param goodsList
+     */
     @Override
-    public void onGoodsDataCome(List<GoodsBean> goodsList) {
-        // todo 分页或者刷新
+    public void onGoodsDataCome(boolean success, String message, List<GoodsBean> goodsList) {
+        srl_goods.setRefreshing(false);
+        if (!success) {
+            ToastTool.showShort(message);
+            return;
+        }
+
         if (mCurrentPage == PAGE_START) {
             mGoodsList.clear();
+            // 本地写死的数据
+            mGoodsList.addAll(DataTool.getGoodsList());
             mGoodsList.addAll(goodsList);
             mAdapter.notifyDataSetChanged();
-            // 如果是第0页数据,要与顶部对齐
+            // 如果是下拉刷新获取的第0页数据,item不要自动滚动一段距离
             // 或者用这个mLayoutManager.scrollToPositionWithOffset(0, 0);
-            rv_goods.smoothScrollToPosition(0);
+            if (mIsRefresh) {
+                rv_goods.smoothScrollToPosition(0);
+            }
         } else {
             mGoodsList.addAll(goodsList);
             mAdapter.notifyDataSetChanged();
         }
 
-        // 请求成功且有更多数据时,页数自增
+        // 请求到数据了,页数自增
         if (goodsList != null && goodsList.size() > 0) {
             mCurrentPage++;
         }
@@ -150,11 +207,16 @@ public class GoodsFragment extends BaseMVPFragment implements IGoodsView, ITopAc
         } else {
             iv_empty.setVisibility(View.GONE);
         }
-
     }
 
+    /**
+     * 删除商品结果
+     * @param success
+     * @param message
+     * @param position
+     */
     @Override
-    public void onDeleteGoodsResult(int position, boolean success, String message) {
+    public void onDeleteGoodsResult(boolean success, String message, int position) {
         if (success) {
             mAdapter.notifyItemRemoved(position);
             ToastTool.showShort("删除成功");

+ 23 - 8
app/src/main/java/com/itant/shibei/ui/home/GoodsPresenter.java

@@ -5,7 +5,6 @@ import android.text.TextUtils;
 import com.itant.shibei.base.ApiService;
 import com.itant.shibei.bean.GoodsBean;
 import com.itant.shibei.net.RetrofitHelper;
-import com.itant.shibei.tool.DataTool;
 import com.miekir.mvp.presenter.BasePresenter;
 import com.miekir.network.core.base.BaseObserver;
 
@@ -22,11 +21,27 @@ import io.reactivex.schedulers.Schedulers;
  * Description: 商品的相关数据接口处理
  */
 public class GoodsPresenter extends BasePresenter<IGoodsView> {
-    public void getGoodsData() {
-        List<GoodsBean> goodsList = DataTool.getGoodsList();
-        if (getView() != null) {
-            getView().onGoodsDataCome(goodsList);
-        }
+    public void getGoodsData(int pageNum, int pageSize) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .getGoodsList(pageNum, pageSize)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<List<GoodsBean>>() {
+                    @Override
+                    public void onSuccess(List<GoodsBean> result) {
+                        if (getView() != null) {
+                            getView().onGoodsDataCome(true, "", result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onGoodsDataCome(false, TextUtils.isEmpty(errMsg) ? "获取失败:"+e.getMessage() : errMsg, null);
+                        }
+                    }
+                });
     }
 
     public void deleteGoodsById(int position, long goodsId) {
@@ -39,14 +54,14 @@ public class GoodsPresenter extends BasePresenter<IGoodsView> {
                     @Override
                     public void onSuccess(String result) {
                         if (getView() != null) {
-                            getView().onDeleteGoodsResult(position, true, result);
+                            getView().onDeleteGoodsResult(true, result, position);
                         }
                     }
 
                     @Override
                     public void onFailure(Throwable e, String errMsg) {
                         if (getView() != null) {
-                            getView().onDeleteGoodsResult(position, false, TextUtils.isEmpty(errMsg) ? "删除失败"+e.getMessage() : errMsg);
+                            getView().onDeleteGoodsResult(false, TextUtils.isEmpty(errMsg) ? "删除失败"+e.getMessage() : errMsg, position);
                         }
                     }
                 });

+ 2 - 2
app/src/main/java/com/itant/shibei/ui/home/IGoodsView.java

@@ -13,6 +13,6 @@ import java.util.List;
  * Description: 商品的View回调
  */
 public interface IGoodsView extends IView {
-    void onGoodsDataCome(List<GoodsBean> goodsList);
-    void onDeleteGoodsResult(int position, boolean success, String message);
+    void onGoodsDataCome(boolean success, String message, List<GoodsBean> goodsList);
+    void onDeleteGoodsResult(boolean success, String message, int position);
 }

+ 10 - 0
app/src/main/java/com/itant/shibei/widget/bottomlistener/OnBottomListener.java

@@ -0,0 +1,10 @@
+package com.itant.shibei.widget.bottomlistener;
+
+/**
+ * @author Jack Tony
+ * @brief
+ * @date 2015/4/6
+ */
+public interface OnBottomListener {
+    public void onBottom();
+}

+ 117 - 0
app/src/main/java/com/itant/shibei/widget/bottomlistener/OnRcvScrollListener.java

@@ -0,0 +1,117 @@
+package com.itant.shibei.widget.bottomlistener;
+
+
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
+
+/**
+ * @author Jack Tony
+ * @brief recyle view 滚动监听器
+ * @date 2015/4/6
+ */
+public class OnRcvScrollListener extends RecyclerView.OnScrollListener implements OnBottomListener {
+    private String TAG = getClass().getSimpleName();
+
+    public static enum LAYOUT_MANAGER_TYPE {
+        LINEAR,
+        GRID,
+        STAGGERED_GRID
+    }
+
+    /**
+     * layoutManager的类型(枚举)
+     */
+    protected LAYOUT_MANAGER_TYPE layoutManagerType;
+
+    /**
+     * 最后一个的位置
+     */
+    private int[] lastPositions;
+
+    /**
+     * 最后一个可见的item的位置
+     */
+    private int lastVisibleItemPosition;
+/*    *//**
+     * 是否正在加载
+     *//*
+    private boolean isLoadingMore = false;*/
+
+    /**
+     * 当前滑动的状态
+     */
+    private int currentScrollState = 0;
+
+    @Override
+    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+        super.onScrolled(recyclerView, dx, dy);
+
+        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+        //  int lastVisibleItemPosition = -1;
+        if (layoutManagerType == null) {
+            if (layoutManager instanceof LinearLayoutManager) {
+                layoutManagerType = LAYOUT_MANAGER_TYPE.LINEAR;
+            } else if (layoutManager instanceof GridLayoutManager) {
+                layoutManagerType = LAYOUT_MANAGER_TYPE.GRID;
+            } else if (layoutManager instanceof StaggeredGridLayoutManager) {
+                layoutManagerType = LAYOUT_MANAGER_TYPE.STAGGERED_GRID;
+            } else {
+                throw new RuntimeException(
+                        "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
+            }
+        }
+
+        switch (layoutManagerType) {
+            case LINEAR:
+                lastVisibleItemPosition = ((LinearLayoutManager) layoutManager)
+                        .findLastVisibleItemPosition();
+                break;
+            case GRID:
+                lastVisibleItemPosition = ((GridLayoutManager) layoutManager)
+                        .findLastVisibleItemPosition();
+                break;
+            case STAGGERED_GRID:
+                StaggeredGridLayoutManager staggeredGridLayoutManager
+                        = (StaggeredGridLayoutManager) layoutManager;
+                if (lastPositions == null) {
+                    lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
+                }
+                staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
+                lastVisibleItemPosition = findMax(lastPositions);
+                break;
+        }
+
+    }
+
+    @Override
+    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+        super.onScrollStateChanged(recyclerView, newState);
+        currentScrollState = newState;
+        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+        int visibleItemCount = layoutManager.getChildCount();
+        int totalItemCount = layoutManager.getItemCount();
+        if ((visibleItemCount > 0 && currentScrollState == RecyclerView.SCROLL_STATE_IDLE &&
+                (lastVisibleItemPosition) >= totalItemCount - 1)) {
+            //Log.d(TAG, "is loading more");
+            onBottom();
+        }
+    }
+
+
+    @Override
+    public void onBottom() {
+        //Log.d(TAG, "is onBottom");
+    }
+
+    private int findMax(int[] lastPositions) {
+        int max = lastPositions[0];
+        for (int value : lastPositions) {
+            if (value > max) {
+                max = value;
+            }
+        }
+        return max;
+    }
+}

文件差異過大導致無法顯示
+ 4 - 4
app/src/main/res/layout/fragment_about.xml


+ 2 - 1
app/src/main/res/layout/fragment_home_goods.xml

@@ -9,6 +9,7 @@
     <!--todo RecyclerView还是会自动获取焦点-->
 
     <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+        android:id="@+id/srl_goods"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
     <!--去掉下拉阴影android:overScrollMode="never"-->
@@ -35,7 +36,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="bottom|end"
-        android:layout_margin="@dimen/fab_margin"
+        android:layout_margin="16dp"
         app:srcCompat="@android:drawable/ic_dialog_info"
         android:visibility="gone"/>
 </FrameLayout>

+ 6 - 0
app/src/main/res/values/colors.xml

@@ -83,6 +83,12 @@
     <color name="green_pressed">#118d58</color>
     <color name="green_search_bg">#3fb179</color>
     <color name="green_light">#263fb179</color>
+    <color name="green_droid">#42C662</color>
+    <color name="black_droid_text">#6D6D6D</color>
+    <color name="red_droid">#F47C88</color>
+    <color name="blue_droid">#66ABF2</color>
+    <color name="blue_droid_bright">#66D6F2</color>
+    <color name="yellow_droid">#FFB966</color>
 
     <color name="green">#5CB85C</color>
     <color name="green_dark">#449D44</color>

+ 2 - 0
common/build.gradle

@@ -62,4 +62,6 @@ dependencies {
     api 'com.github.bumptech.glide:glide:4.11.0'
     annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
 
+    // 适配器
+    api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.50'
 }

+ 1 - 1
network/build.gradle

@@ -62,5 +62,5 @@ dependencies {
     api 'com.squareup.retrofit2:converter-gson:2.2.0'
     // 使用 retrofit + rx + gson 实现网络请求与解析end<-----
 
-
+    api "com.squareup.okhttp3:logging-interceptor:3.6.0"
 }