1. 程式人生 > >詳情跳轉到購物車

詳情跳轉到購物車

> 依賴

```

compile 'com.android.support:appcompat-v7:26.+'

compile 'com.android.support.constraint:constraint-layout:1.0.2'

compile 'io.reactivex.rxjava2:rxjava:2.0.7'

compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

compile 'com.squareup.retrofit2:retrofit:2.1.0'

compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

compile 'com.squareup.retrofit2:converter-scalars:2.1.0'

compile 'com.jakewharton:butterknife:8.8.1'

compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'

compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'

compile 'com.facebook.fresco:fresco:0.12.0'

compile 'com.github.bumptech.glide:glide:3.7.0'

compile 'org.greenrobot:eventbus:3.1.1'

compile 'com.android.support:design:26.0.0-alpha1'

compile 'com.dou361.ijkplayer:jjdxm-ijkplayer:1.0.5'

testCompile 'junit:junit:4.12'

annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

```

> 許可權

```

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

```

Utils

=====

> DownLoadFile

--------------

```

public class DownLoadFile {

    private static final String SP_NAME = "download_file";  

    private static final String CURR_LENGTH = "curr_length";  

    private static final int DEFAULT_THREAD_COUNT = 4;//預設下載執行緒數  

    //以下為執行緒狀態  

    private static final String DOWNLOAD_INIT = "1";  

    private static final String DOWNLOAD_ING = "2";  

    private static final String DOWNLOAD_PAUSE = "3";  

    private Context mContext;

    private String loadUrl;//網路獲取的url  

    private String filePath;//下載到本地的path  

    private int threadCount = DEFAULT_THREAD_COUNT;//下載執行緒數  

    private int fileLength;//檔案總大小  

    //使用volatile防止多執行緒不安全  

    private volatile int currLength;//當前總共下載的大小  

    private volatile int runningThreadCount;//正在執行的執行緒數  

    private Thread[] mThreads;  

    private String stateDownload = DOWNLOAD_INIT;//當前執行緒狀態  

    private DownLoadListener mDownLoadListener;  

    public void setOnDownLoadListener(DownLoadListener mDownLoadListener) {  

        this.mDownLoadListener = mDownLoadListener;  

    }  

    public interface DownLoadListener {

        //返回當前下載進度的百分比  

        void getProgress(int progress);  

        void onComplete();  

        void onFailure();  

    }  

    public DownLoadFile(Context mContext, String loadUrl, String filePath) {  

        this(mContext, loadUrl, filePath, DEFAULT_THREAD_COUNT, null);  

    }  

    public DownLoadFile(Context mContext, String loadUrl, String filePath, DownLoadListener mDownLoadListener) {  

        this(mContext, loadUrl, filePath, DEFAULT_THREAD_COUNT, mDownLoadListener);  

    }  

    public DownLoadFile(Context mContext, String loadUrl, String filePath, int threadCount) {  

        this(mContext, loadUrl, filePath, threadCount, null);  

    }  

    public DownLoadFile(Context mContext, String loadUrl, String filePath, int threadCount, DownLoadListener mDownLoadListener) {  

        this.mContext = mContext;  

        this.loadUrl = loadUrl;  

        this.filePath = filePath;  

        this.threadCount = threadCount;  

        runningThreadCount = 0;  

        this.mDownLoadListener = mDownLoadListener;  

    }  

    /**

     * 開始下載

     */

    public void downLoad() {

        //線上程中執行,防止anr  

        new Thread(new Runnable() {  

            @Override  

            public void run() {  

                try {  

                    //初始化資料  

                    if (mThreads == null)  

                        mThreads = new Thread[threadCount];  

                    //建立連線請求  

                    URL url = new URL(loadUrl);

                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

                    conn.setConnectTimeout(5000);  

                    conn.setRequestMethod("GET");  

                    int code = conn.getResponseCode();//獲取返回碼  

                    if (code == 200) {//請求成功,根據檔案大小開始分多執行緒下載  

                        fileLength = conn.getContentLength();  

                        //根據檔案大小,先建立一個空檔案  

                        //“r“——以只讀方式開啟。呼叫結果物件的任何 write 方法都將導致丟擲 IOException。  

                        //“rw“——開啟以便讀取和寫入。如果該檔案尚不存在,則嘗試建立該檔案。  

                        //“rws“—— 開啟以便讀取和寫入,對於 “rw”,還要求對檔案的內容或元資料的每個更新都同步寫入到底層儲存裝置。  

                        //“rwd“——開啟以便讀取和寫入,對於 “rw”,還要求對檔案內容的每個更新都同步寫入到底層儲存裝置。  

                        RandomAccessFile raf = new RandomAccessFile(filePath, "rwd");

                        raf.setLength(fileLength);  

                        raf.close();  

                        //計算各個執行緒下載的資料段  

                        int blockLength = fileLength / threadCount;  

                        SharedPreferences sp = mContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);

                        //獲取上次取消下載的進度,若沒有則返回0  

                        currLength = sp.getInt(CURR_LENGTH, 0);  

                        for (int i = 0; i < threadCount; i++) {  

                            //開始位置,獲取上次取消下載的進度,預設返回i*blockLength,即第i個執行緒開始下載的位置  

                            int startPosition = sp.getInt(SP_NAME + (i + 1), i * blockLength);  

                            //結束位置,-1是為了防止上一個執行緒和下一個執行緒重複下載銜接處資料  

                            int endPosition = (i + 1) * blockLength - 1;  

                            //將最後一個執行緒結束位置擴大,防止檔案下載不完全,大了不影響,小了檔案失效  

                            if ((i + 1) == threadCount)  

                                endPosition = endPosition * 2;  

                            mThreads[i] = new DownThread(i + 1, startPosition, endPosition);  

                            mThreads[i].start();  

                        }  

                    }else {  

                        handler.sendEmptyMessage(FAILURE);  

                    }  

                } catch (Exception e) {  

                    e.printStackTrace();  

                    handler.sendEmptyMessage(FAILURE);  

                }  

            }  

        }).start();  

    }  

    /**

     * 取消下載

     */  

    protected void cancel() {  

        if (mThreads != null) {  

            //若執行緒處於等待狀態,則while迴圈處於阻塞狀態,無法跳出迴圈,必須先喚醒執行緒,才能執行取消任務  

            if (stateDownload.equals(DOWNLOAD_PAUSE))  

                onStart();  

            for (Thread dt : mThreads) {  

                ((DownThread) dt).cancel();  

            }  

        }  

    }  

    /**

     * 暫停下載

     */

    public void onPause() {

        if (mThreads != null)  

            stateDownload = DOWNLOAD_PAUSE;  

    }  

    /**

     * 繼續下載

     */

    public void onStart() {

        if (mThreads != null)  

            synchronized (DOWNLOAD_PAUSE) {  

                stateDownload = DOWNLOAD_ING;  

                DOWNLOAD_PAUSE.notifyAll();  

            }  

    }  

    public void onDestroy() {

        if (mThreads != null)  

            mThreads = null;  

    }  

    private class DownThread extends Thread {  

        private boolean isGoOn = true;//是否繼續下載  

        private int threadId;  

        private int startPosition;//開始下載點  

        private int endPosition;//結束下載點  

        private int currPosition;//當前執行緒的下載進度  

        private DownThread(int threadId, int startPosition, int endPosition) {  

            this.threadId = threadId;  

            this.startPosition = startPosition;  

            currPosition = startPosition;  

            this.endPosition = endPosition;  

            runningThreadCount++;  

        }  

        @Override  

        public void run() {  

            SharedPreferences sp = mContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);  

            try {  

                URL url = new URL(loadUrl);  

                HttpURLConnection conn = (HttpURLConnection) url.openConnection();  

                conn.setRequestMethod("GET");  

                conn.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);  

                conn.setConnectTimeout(5000);  

                //若請求頭加上Range這個引數,則返回狀態碼為206,而不是200  

                if (conn.getResponseCode() == 206) {  

                    InputStream is = conn.getInputStream();

                    RandomAccessFile raf = new RandomAccessFile(filePath, "rwd");  

                    raf.seek(startPosition);//跳到指定位置開始寫資料  

                    int len;  

                    byte[] buffer = new byte[1024];  

                    while ((len = is.read(buffer)) != -1) {  

                        //是否繼續下載  

                        if (!isGoOn)  

                            break;  

                        //回調當前進度  

                        if (mDownLoadListener != null) {  

                            currLength += len;  

                            int progress = (int) ((float) currLength / (float) fileLength * 100);  

                            handler.sendEmptyMessage(progress);  

                        }  

                        raf.write(buffer, 0, len);  

                        //寫完後將當前指標後移,為取消下載時儲存當前進度做準備  

                        currPosition += len;  

                        synchronized (DOWNLOAD_PAUSE) {  

                            if (stateDownload.equals(DOWNLOAD_PAUSE)) {  

                                DOWNLOAD_PAUSE.wait();  

                            }  

                        }  

                    }  

                    is.close();  

                    raf.close();  

                    //執行緒計數器-1  

                    runningThreadCount--;  

                    //若取消下載,則直接返回  

                    if (!isGoOn) {  

                        //此處採用SharedPreferences儲存每個執行緒的當前進度,和三個執行緒的總下載進度  

                        if (currPosition < endPosition) {  

                            sp.edit().putInt(SP_NAME + threadId, currPosition).apply();  

                            sp.edit().putInt(CURR_LENGTH, currLength).apply();  

                        }  

                        return;  

                    }  

                    if (runningThreadCount == 0) {  

                        sp.edit().clear().apply();  

                        handler.sendEmptyMessage(SUCCESS);  

                        handler.sendEmptyMessage(100);  

                        mThreads = null;  

                    }  

                } else {  

                    sp.edit().clear().apply();  

                    handler.sendEmptyMessage(FAILURE);  

                }  

            } catch (Exception e) {  

                sp.edit().clear().apply();  

                e.printStackTrace();  

                handler.sendEmptyMessage(FAILURE);  

            }  

        }  

        public void cancel() {  

            isGoOn = false;  

        }  

    }  

    private final int SUCCESS = 0x00000101;  

    private final int FAILURE = 0x00000102;  

    private Handler handler = new Handler() {

        @Override  

        public void handleMessage(Message msg) {

            if (mDownLoadListener != null) {  

                if (msg.what == SUCCESS) {  

                    mDownLoadListener.onComplete();  

                } else if (msg.what == FAILURE) {  

                    mDownLoadListener.onFailure();  

                } else {  

                    mDownLoadListener.getProgress(msg.what);  

                }  

            }  

        }  

    };  

}  

```

> MyApp

-------

```

public class MyApp extends Application {

    @Override

    public void onCreate() {

        super.onCreate();

        //配置磁碟快取

        DiskCacheConfig diskSmallCacheConfig = DiskCacheConfig.newBuilder(this)

                .setBaseDirectoryPath(this.getCacheDir())//快取圖片基路徑

                .setBaseDirectoryName(getString(R.string.app_name))//資料夾名

                .build();

        ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig.newBuilder(this)

                .setBitmapsConfig(Bitmap.Config.RGB_565)

                .setSmallImageDiskCacheConfig(diskSmallCacheConfig)

                .build();

        //初始化Fresco

        Fresco.initialize(this, imagePipelineConfig);

    }

}

```

net

===

> ServiceApi

------------

```

public interface ServiceApi {

    //商品詳情

    @GET(Urls.PRODUCTDETAIL)

    Observable<ProductDetailBean> getDetail(@Query("pid") String pid);

    //新增購物車

    @GET(Urls.ADDCART)

    Observable<AddCartBean> addCart(@Query("pid") String pid, @Query("uid") String uid);

    //查詢購物車

    @GET(Urls.GETCARTS)

    Observable<CartBean> getCarts(@Query("uid") String uid);

}

```

> OnNetListener

---------------

```

public interface OnNetListener<T> {

    public void onSuccess(T t);

    public void onFailure(Throwable throwable);

}

```

> RetrofitHelper

----------------

```

public class RetrofitHelper {

    private static OkHttpClient okHttpClient;

    private static ServiceApi serviceApi;

    static {

        initOkHttpClient();

    }

    /**

     * 建立OkHttpClient

     */

    private static void initOkHttpClient() {

        if (okHttpClient == null) {

            synchronized (RetrofitHelper.class) {

                if (okHttpClient == null) {

                    //設定攔截器

                    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

                    logging.setLevel(HttpLoggingInterceptor.Level.BODY);

                    okHttpClient = new OkHttpClient.Builder()

                            .addInterceptor(logging)//新增攔截器

                            .addInterceptor(new MyInterceptor())

                            .connectTimeout(5, TimeUnit.SECONDS)//設定連線超時

                            .build();

                }

            }

        }

    }

    /**

     * 定義一個泛型方法

     *

     * @param tClass

     * @param url

     * @param <T>

     * @return

     */

    public static <T> T createAPi(Class<T> tClass, String url) {

        Retrofit retrofit = new Retrofit.Builder()

                .baseUrl(url)

                .client(okHttpClient)

                .addConverterFactory(GsonConverterFactory.create())

                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

                .build();

        return retrofit.create(tClass);

    }

    /**

     * 初始化ServiceApi

     *

     * @return

     */

    public static ServiceApi getServiceApi() {

        if (serviceApi == null) {

            synchronized (ServiceApi.class) {

                if (serviceApi == null) {

                    serviceApi = createAPi(ServiceApi.class, Urls.BASE_URL);

                }

            }

        }

        return serviceApi;

    }

    /**

     * 新增公共引數攔截器

     */

    static class MyInterceptor implements Interceptor {

        @Override

        public Response intercept(Chain chain) throws IOException {

            Request request = chain.request();

            HttpUrl httpUrl = request.url()

                    .newBuilder()

                    .addQueryParameter("source", "android")

                    .build();

            Request build = request.newBuilder()

                    .url(httpUrl)

                    .build();

            return chain.proceed(build);

        }

    }

}

```

> Urls

-----

```

public class Urls {

    public static final String BASE_URL = "https://www.zhaoapi.cn/";

    //詳情

    public static final String PRODUCTDETAIL = "product/getProductDetail";

    //新增購物車

    public static final String ADDCART = "product/addCart";

    //查詢購物車

    public static final String GETCARTS = "product/getCarts";

}

```

View層

=====

> MainActivity

--------------

```

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    /**

     * 下載

     */

    private Button mBtXiazai;

    /**

     * 暫停

     */

    private Button mBtZanting;

    /**

     * 繼續

     */

    private Button mBtJixu;

    private ProgressBar mPro;

    /**

     * 下載:0%

     */

    private TextView mTvProgress;

    /**

     * 進入詳情

     */

    private Button mBtXiangqing;

    private DownLoadFile downLoadFile;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        initView();

    }

    private void initView() {

        mBtXiazai = (Button) findViewById(R.id.bt_xiazai);

        mBtXiazai.setOnClickListener(this);

        mBtZanting = (Button) findViewById(R.id.bt_zanting);

        mBtZanting.setOnClickListener(this);

        mBtJixu = (Button) findViewById(R.id.bt_jixu);

        mBtJixu.setOnClickListener(this);

        mPro = (ProgressBar) findViewById(R.id.pro);

        mTvProgress = (TextView) findViewById(R.id.tv_progress);

        mBtXiangqing = (Button) findViewById(R.id.bt_xiangqing);

        mBtXiangqing.setOnClickListener(this);

        File f = new File(Environment.getExternalStorageDirectory() + "/wenjian/");

        if (!f.exists()) {

            f.mkdir();

        }

        //儲存地址

        String path = Environment.getExternalStorageDirectory() + "/wenjian/ww.mp4";

        //設定最大度

        mPro.setMax(100);

        //例項化

        downLoadFile = new DownLoadFile(this,

                "http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4"

                , path, 10, new DownLoadFile.DownLoadListener() {

            @Override

            public void getProgress(int progress) {

                mTvProgress.setText("當前進度:" + progress + "%");

                mPro.setProgress(progress);

            }

            @Override

            public void onComplete() {

                Toast.makeText(MainActivity.this, "下載完成", Toast.LENGTH_SHORT).show();

            }

            @Override

            public void onFailure() {

                Toast.makeText(MainActivity.this, "下載失敗", Toast.LENGTH_SHORT).show();

            }

        }

        );

    }

    @Override

    public void onClick(View v) {

        switch (v.getId()) {

            default:

                break;

            case R.id.bt_xiazai:

                downLoadFile.downLoad();

                break;

            case R.id.bt_zanting:

                downLoadFile.onPause();

                break;

            case R.id.bt_jixu:

                downLoadFile.onStart();

                break;

            case R.id.bt_xiangqing:

                Intent intent = new Intent(MainActivity.this, ProductDetailActivity.class);

                startActivity(intent);

                break;

        }

    }

    @Override

    protected void onDestroy() {

        super.onDestroy();

        downLoadFile.onDestroy();

    }

}

```

> CartActivity

--------------

```

public class CartActivity extends AppCompatActivity implements ICartView{

    private ExpandableListView mElv;

    private CheckBox mCbAll;

    /**

     * 全選

     */

    private TextView mTvQuxuan;

    /**

     * 合計 :¥550.90

     */

    private TextView mTvPrice;

    /**

     * 去支付(0)

     */

    private TextView mTvNum;

    private CartPresenter cartPresenter;

    private List<List<CartBean.DataBean.ListBean>> lists;

    private MyElvAdapter myElvAdapter;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_cart);

        initView();

        //繫結EventBus

        EventBus.getDefault().register(this);

        cartPresenter = new CartPresenter(this);

        cartPresenter.getCart();

    }

    private void initView() {

        mElv = (ExpandableListView) findViewById(R.id.elv);

        mCbAll = (CheckBox) findViewById(R.id.cb_All);

        mTvQuxuan = (TextView) findViewById(R.id.tv_quxuan);

        mTvPrice = (TextView) findViewById(R.id.tv_price);

        mTvNum = (TextView) findViewById(R.id.tv_num);

        mTvNum.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                Intent intent = new Intent(CartActivity.this,DingGoodsActivity.class);

                startActivity(intent);

            }

        });

        //全選

        mCbAll.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                myElvAdapter.changeAllListCbState(mCbAll.isChecked());

            }

        });

    }

    @Override

    public void getCart(CartBean cartBean) {

        float price = 0;

        int num = 0;

        List<CartBean.DataBean> dataBeans = cartBean.getData();

        lists = new ArrayList<>();

        for (int i = 0; i < dataBeans.size(); i++) {

            List<CartBean.DataBean.ListBean> list = dataBeans.get(i).getList();

            lists.add(list);

        }

        //設定介面卡

        myElvAdapter = new MyElvAdapter(this, dataBeans, lists);

        mElv.setAdapter(myElvAdapter);

        for (int i = 0; i < dataBeans.size(); i++) {

            //預設二級列表展開

            mElv.expandGroup(i);

        }

        //取消小箭頭

        mElv.setGroupIndicator(null);

        //預設全選

        for (int i = 0; i < lists.size(); i++) {

            for (int j = 0; j < lists.get(i).size(); j++) {

                CartBean.DataBean.ListBean listBean = lists.get(i).get(j);

                price += listBean.getNum() * listBean.getPrice();

                num += listBean.getNum();

            }

        }

        mTvNum.setText(num);

        mTvPrice.setText(price + "");

    }

    @Subscribe

    public void onMessageEvent(MessageEvent event) {

        mCbAll.setChecked(event.isChecked());

    }

    @Subscribe

    public void onMessageEvent(PriceAndCountEvent event) {

        mTvPrice.setText("合計:¥" + event.getPrice() * event.getCount());

        mTvPrice.setText("總額:¥" + event.getPrice() * event.getCount());

        mTvNum.setText("去結算(" + event.getCount() + ")");

    }

    /**

     * 取消繫結,防止記憶體溢位

     */

    @Override

    protected void onDestroy() {

        super.onDestroy();

        //解除繫結

        EventBus.getDefault().unregister(this);

        cartPresenter.onDetach();

    }

}

```

> 介面

----

```

public interface ICartView {

    public void getCart(CartBean cartBean);

}

```

> ProductDetailActivity

-----------------------

```

public class ProductDetailActivity extends AppCompatActivity implements View.OnClickListener, IProductDetailView {

    private RecyclerView mXqRlv;

    private ImageView mIvGetcart;

    /**

     * 新增到購物車

     */

    private Button mBtAddcart;

    /**

     * 立即購買

     */

    private Button mBtTocart;

    private ProductDetailPresenter productDetailPresenter;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_product_detail);

        initView();

        //設定佈局管理器

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);

        //載入線性佈局

        mXqRlv.setLayoutManager(layoutManager);

        productDetailPresenter = new ProductDetailPresenter(this);

        productDetailPresenter.getProductDetail();

        /**

         * 播放視訊

         */

        String path = Environment.getExternalStorageDirectory() + "/wenjian/ww.mp4";

        //String url = Environment.getExternalStorageDirectory()+ "/wenjian/ww.mp4";

        new PlayerView(this)

                .setTitle("視屏播放")

                .setScaleType(PlayStateParams.fitparent)

                .hideMenu(true)

                .forbidTouch(false)

                .setPlaySource(path)

                .startPlay();

    }

    private void initView() {

        mXqRlv = (RecyclerView) findViewById(R.id.xq_rlv);

        mIvGetcart = (ImageView) findViewById(R.id.iv_getcart);

        mBtAddcart = (Button) findViewById(R.id.bt_addcart);

        mBtAddcart.setOnClickListener(this);

        mBtTocart = (Button) findViewById(R.id.bt_tocart);

        mBtTocart.setOnClickListener(this);

    }

    @Override

    public void onClick(View v) {

        switch (v.getId()) {

            case R.id.bt_addcart:

                //新增購物車

                productDetailPresenter.addCart();

                break;

            case R.id.bt_tocart:

                //跳轉到購物車

                Intent intent = new Intent(ProductDetailActivity.this, CartActivity.class);

                startActivity(intent);

                break;

        }

    }

    @Override

    public void getDetail(ProductDetailBean productDetailBean) {

        ProductDetailBean.DataBean dataBean = productDetailBean.getData();

        List<ProductDetailBean.DataBean> dataBeanList = new ArrayList<>();

        dataBeanList.add(dataBean);

        //設定介面卡

        DetailRlvAdapter detailRlvAdapter = new DetailRlvAdapter(this, dataBeanList);

        //展示資料

        mXqRlv.setAdapter(detailRlvAdapter);

    }

    @Override

    public void addCart(AddCartBean addCartBean) {

        if (addCartBean.getCode().equals("0")) {

            Toast.makeText(getApplicationContext(), addCartBean.getMsg(), Toast.LENGTH_SHORT).show();

        } else {

            Toast.makeText(getApplicationContext(), addCartBean.getMsg(), Toast.LENGTH_SHORT).show();

        }

    }

    /**

     * 取消繫結,防止記憶體溢位

     */

    @Override

    protected void onDestroy() {

        super.onDestroy();

        productDetailPresenter.onDetach();

    }

}

```

> 介面

----

```

public interface IProductDetailView {

    //商品詳情

    public void getDetail(ProductDetailBean productDetailBean);

    //新增購物車

    public void addCart(AddCartBean addCartBean);

}

```

> AddDeleteView

---------------

```

public class AddDeleteView extends LinearLayout {

    private OnAddDelClickListener listener;

    private EditText etNumber;

    //對外提供一個點選的回撥介面

    public interface OnAddDelClickListener {

        void onAddClick(View v);

        void onDelClick(View v);

    }

    public void setOnAddDelClickListener(OnAddDelClickListener listener) {

        if (listener != null) {

            this.listener = listener;

        }

    }

    public AddDeleteView(Context context) {

        this(context, null);

    }

    public AddDeleteView(Context context, @Nullable AttributeSet attrs) {

        this(context, attrs, 0);

    }

    public AddDeleteView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

        initView(context, attrs, defStyleAttr);

    }

    private void initView(Context context, AttributeSet attrs, int defStyleAttr) {

        View.inflate(context, R.layout.adddelete, this);

        TextView txtDelete = (TextView) findViewById(R.id.tv_delete);

        TextView txtAdd = (TextView) findViewById(R.id.tv_add);

        etNumber = (EditText) findViewById(R.id.ed_num);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AddDeleteViewStyle);

        String leftText = typedArray.getString(R.styleable.AddDeleteViewStyle_left_text);

        String rightText = typedArray.getString(R.styleable.AddDeleteViewStyle_right_text);

        String middleText = typedArray.getString(R.styleable.AddDeleteViewStyle_middle_text);

        txtDelete.setText(leftText);

        txtAdd.setText(rightText);

        etNumber.setText(middleText);

        //回收

        typedArray.recycle();

        txtDelete.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View view) {

                listener.onDelClick(view);

            }

        });

        txtAdd.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View view) {

                listener.onAddClick(view);

            }

        });

    }

    //對外提供一個修改數字的方法

    public void setNumber(int number) {

        if (number > 0) {

            etNumber.setText(number + "");

        }

    }

    //對外提供一個獲取當前數字的方法

    public int getNumber() {

        String string = etNumber.getText().toString();

        int i = Integer.parseInt(string);

        return i;

    }

}

```

> DingGoodsActivity

-------------------

```

public class DingGoodsActivity extends AppCompatActivity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_ding_goods);

    }

}

```

 presenter層

============

> CartPresenter

---------------

```

public class CartPresenter {

    private ICartView iCartView;

    private final ICartModel iCartModel;

    public CartPresenter(ICartView iCartView) {

        this.iCartView = iCartView;

        iCartModel = new CartModel();

    }

    public void getCart() {

        iCartModel.getCarts("71", new OnNetListener<CartBean>() {

            @Override

            public void onSuccess(CartBean cartBean) {

                iCartView.getCart(cartBean);

            }

            @Override

            public void onFailure(Throwable throwable) {

            }

        });

    }

    //解綁,防止記憶體溢位

    public void onDetach() {

        if (iCartView != null) {

            iCartView = null;

        }

    }

}

```

> ProductDetailPresenter

------------------------

```

public class ProductDetailPresenter {

    private IProductDetailView iProductDetailView;

    private final IProductDetailModel iProductDetailModel;

    public ProductDetailPresenter(IProductDetailView iProductDetailView) {

        this.iProductDetailView = iProductDetailView;

        iProductDetailModel = new ProductDetailModel();

    }

    /**

     * 商品詳情

     */

    public void getProductDetail() {

        iProductDetailModel.getProductDetail("70", new OnNetListener<ProductDetailBean>() {

            @Override

            public void onSuccess(ProductDetailBean productDetailBean) {

                iProductDetailView.getDetail(productDetailBean);

            }

            @Override

            public void onFailure(Throwable throwable) {

            }

        });

    }

    /**

     * 新增購物車

     */

    public void addCart() {

        iProductDetailModel.addCart("70", "71", new OnNetListener<AddCartBean>() {

            @Override

            public void onSuccess(AddCartBean addCartBean) {

                iProductDetailView.addCart(addCartBean);

            }

            @Override

            public void onFailure(Throwable throwable) {

            }

        });

    }

    //解綁,防止記憶體溢位

    public void onDetach() {

        if (iProductDetailView != null) {

            iProductDetailView = null;

        }

    }

}

```

model

=====

> CartModel

-----------

```

public class CartModel implements ICartModel {

    @Override

    public void getCarts(String uid, final OnNetListener<CartBean> onNetListener) {

        ServiceApi serviceApi = RetrofitHelper.getServiceApi();

        serviceApi.getCarts(uid)

                .subscribeOn(Schedulers.io())

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(new Consumer<CartBean>() {

                    @Override

                    public void accept(CartBean cartBean) throws Exception {

                        onNetListener.onSuccess(cartBean);

                    }

                }, new Consumer<Throwable>() {

                    @Override

                    public void accept(Throwable throwable) throws Exception {

                        onNetListener.onFailure(throwable);

                    }

                });

    }

}

```

> 介面

----

```

public interface ICartModel {

    public void getCarts(String uid, OnNetListener<CartBean> onNetListener);

}

```

> ProductDetailModel

--------------------

```

public class ProductDetailModel implements IProductDetailModel {

    @Override

    public void getProductDetail(String pid, final OnNetListener<ProductDetailBean> onNetListener) {

        ServiceApi serviceApi = RetrofitHelper.getServiceApi();

        serviceApi.getDetail(pid)

                .subscribeOn(Schedulers.io())

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(new Consumer<ProductDetailBean>() {

                    @Override

                    public void accept(ProductDetailBean productDetailBean) throws Exception {

                        onNetListener.onSuccess(productDetailBean);

                    }

                }, new Consumer<Throwable>() {

                    @Override

                    public void accept(Throwable throwable) throws Exception {

                        onNetListener.onFailure(throwable);

                    }

                });

    }

    @Override

    public void addCart(String pid, String uid, final OnNetListener<AddCartBean> onNetListener) {

        ServiceApi serviceApi = RetrofitHelper.getServiceApi();

        serviceApi.addCart(pid, uid)

                .subscribeOn(Schedulers.io())

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(new Consumer<AddCartBean>() {

                    @Override

                    public void accept(AddCartBean addCartBean) throws Exception {

                        onNetListener.onSuccess(addCartBean);

                    }

                }, new Consumer<Throwable>() {

                    @Override

                    public void accept(Throwable throwable) throws Exception {

                        onNetListener.onFailure(throwable);

                    }

                });

    }

}

```

> 介面

----

```

public interface IProductDetailModel {

    public void getProductDetail(String pid, OnNetListener<ProductDetailBean> onNetListener);

    public void addCart(String pid, String uid, OnNetListener<AddCartBean> onNetListener);

}

```

Adapter

=======

> DetailRlvAdapter

------------------

```

public class DetailRlvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context context;

    private List<ProductDetailBean.DataBean> dataList;

    private LayoutInflater inflater;

    public DetailRlvAdapter(Context context, List<ProductDetailBean.DataBean> dataList) {

        this.context = context;

        this.dataList = dataList;

        inflater = LayoutInflater.from(context);

    }

    @Override

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = inflater.inflate(R.layout.detail_rlv_adapter_item, null);

        return new MyViewHplder(view);

    }

    @Override

    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        MyViewHplder myViewHplder = (MyViewHplder) holder;

        ProductDetailBean.DataBean dataBean = dataList.get(position);

        String[] images = dataBean.getImages().split("\\!");

        myViewHplder.mDetailAdapterSdv.setImageURI(images[0]);

        myViewHplder.mTvDetailTitle.setText(dataBean.getTitle());

        myViewHplder.mTvDetailPrice.setText("¥" + dataBean.getPrice());

        myViewHplder.mTvDetailSj.setText("我是商家" + dataBean.getSellerid());

    }

    @Override

    public int getItemCount() {

        if (dataList == null) {

            return 0;

        }

        return dataList.size();

    }

    class MyViewHplder extends RecyclerView.ViewHolder {

        SimpleDraweeView mDetailAdapterSdv;

        TextView mTvDetailTitle;

        TextView mTvDetailPrice;

        TextView mTvDetailSj;

        public MyViewHplder(View itemView) {

            super(itemView);

            mDetailAdapterSdv = (SimpleDraweeView) itemView.findViewById(R.id.detail_adapter_sdv);

            mTvDetailTitle = (TextView) itemView.findViewById(R.id.tv_detail_title);

            mTvDetailPrice = (TextView) itemView.findViewById(R.id.tv_detail_price);

            mTvDetailSj = (TextView) itemView.findViewById(R.id.tv_detail_sj);

        }

    }

}

```

> MyElvAdapter

--------------

```

public class MyElvAdapter extends BaseExpandableListAdapter {

    private Context context;

        private List<CartBean.DataBean> groupList;

        private List<List<CartBean.DataBean.ListBean>> childList;

        private LayoutInflater inflater;

        public MyElvAdapter(Context context, List<CartBean.DataBean> groupList, List<List<CartBean.DataBean.ListBean>> childList) {

            this.context = context;

            this.groupList = groupList;

            this.childList = childList;

            inflater = LayoutInflater.from(context);

        }

        @Override

        public int getGroupCount() {

            return groupList.size();

        }

        @Override

        public int getChildrenCount(int groupPosition) {

            return childList.get(groupPosition).size();

        }

        @Override

        public Object getGroup(int groupPosition) {

            return groupList.get(groupPosition);

        }

        @Override

        public Object getChild(int groupPosition, int childPosition) {

            return childList.get(groupPosition).get(childPosition);

        }

        @Override

        public long getGroupId(int groupPosition) {

            return groupPosition;

        }

        @Override

        public long getChildId(int groupPosition, int childPosition) {

            return childPosition;

        }

        @Override

        public boolean hasStableIds() {

            return false;

        }

        @Override

        public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {

            View view;

            final GroupViewHolder holder;

            if (convertView == null) {

                holder = new GroupViewHolder();

                view = inflater.inflate(R.layout.cart_group_item, null);

                holder.cb_group = view.findViewById(R.id.cb_group);

                holder.tv_dian = view.findViewById(R.id.gou_dian);

                view.setTag(holder);

            } else {

                view = convertView;

                holder = (GroupViewHolder) view.getTag();

            }

            final CartBean.DataBean dataBean = groupList.get(groupPosition);

            holder.cb_group.setChecked(dataBean.isChecked());

            holder.tv_dian.setText(dataBean.getSellerName());

            //一級列表的Checkbox

            holder.cb_group.setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View v) {

                    dataBean.setChecked(holder.cb_group.isChecked());

                    //當一級選中時,改變二級列表CheckBox狀態

                    changeChildCbState(groupPosition, holder.cb_group.isChecked());

                    //將對應的數量和價格傳到PriceAndCountEvent

                    EventBus.getDefault().post(computer());

                    //當一級的全部選中是,改變全選CheckBox狀態

                    changeAllCbState(isAllGroupCbSelected());

                    //重新整理列表

                    notifyDataSetChanged();

                }

            });

            return view;

        }

        @Override

        public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {

            View view;

            final ChildViewHolder holder;

            if (convertView == null) {

                holder = new ChildViewHolder();

                view = inflater.inflate(R.layout.cart_child_item, null);

                holder.cb_child = view.findViewById(R.id.cb_child);

                holder.del = view.findViewById(R.id.del);

                holder.sdv = view.findViewById(R.id.child_sdv);

                holder.adv_main = view.findViewById(R.id.adv_main);

                holder.tv_info = view.findViewById(R.id.child_info);

                holder.tv_price = view.findViewById(R.id.child_price);

                holder.tv_tit = view.findViewById(R.id.child_tit);

                view.setTag(holder);

            } else {

                view = convertView;

                holder = (ChildViewHolder) view.getTag();

            }

            final CartBean.DataBean.ListBean listBean = childList.get(groupPosition).get(childPosition);

            holder.cb_child.setChecked(listBean.isChecked());

            String[] strings = listBean.getImages().split("\\!");

            holder.sdv.setImageURI(strings[0]);

            holder.tv_tit.setText(listBean.getSubhead());

            holder.tv_info.setText("日期:"+listBean.getCreatetime());

            holder.tv_price.setText("¥" + listBean.getBargainPrice());

            //給二級CheckBox設定點選事件

            holder.cb_child.setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View v) {

                    //設定該條目物件裡的checked屬性值

                    listBean.setChecked(holder.cb_child.isChecked());

                    PriceAndCountEvent priceAndCountEvent = computer();

                    EventBus.getDefault().post(priceAndCountEvent);

                    if (holder.cb_child.isChecked()) {

                        //當前checkbox是選中狀態

                        if (isAllChildCbSelected(groupPosition)) {

                            changeGroupCbState(groupPosition, true);

                            changeAllCbState(isAllGroupCbSelected());

                        }

                    } else {

                        changeGroupCbState(groupPosition, false);

                        changeAllCbState(isAllGroupCbSelected());

                    }

                    notifyDataSetChanged();

                }

            });

            //自定義View加減號

            holder.adv_main.setOnAddDelClickListener(new AddDeleteView.OnAddDelClickListener() {

                @Override

                public void onAddClick(View v) {

                    //加號

                    int num = listBean.getNum();

                    holder.adv_main.setNumber(++num);

                    listBean.setNum(num);

                    if (holder.cb_child.isChecked()) {

                        PriceAndCountEvent priceAndCountEvent = computer();

                        EventBus.getDefault().post(computer());

                    }

                }

                @Override

                public void onDelClick(View v) {

                    //減號

                    int num = listBean.getNum();

                    if (num == 1) {

                        return;

                    }

                    holder.adv_main.setNumber(--num);

                    listBean.setNum(num);

                    if (holder.cb_child.isChecked()) {

                        PriceAndCountEvent priceAndCountEvent = computer();

                        EventBus.getDefault().post(computer());

                    }

                }

            });

            holder.del.setOnLongClickListener(new View.OnLongClickListener() {

                @Override

                public boolean onLongClick(View view) {

                    AlertDialog.Builder builder = new AlertDialog.Builder(context);

                    builder.setIcon(R.mipmap.ic_l