使用MVP,OKHttp封装类及其拦截器,RecyclerView,SpringView,ImageLoader实现数据的多条目加载

1.  导包:gson包,ImageLoader包


2. 添加依赖:

(1)butterknife自动生成控件id和点击事件:

     compile 'com.jakewharton:butterknife:7.0.0'

(2)okhttp依赖:
     compile 'com.squareup.okhttp3:okhttp:3.9.0'

(3)recyclerview依赖(我自己的版本需要把SDK改为25版本):

     compile 'com.android.support:recyclerview-v7:25.3.1'
     compile 'com.yqritc:recyclerview-flexibledivider:1.4.0'

(4)springview依赖

     compile 'com.liaoinstan.springview:library:1.3.0'


一 . 首先编写OKhttp的封装类

import java.io.File;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
/**
 * Okhttp 单例 范型的封装
 */
public class OkhttpUtils {
    private static OkhttpUtils okhttpUtils = null ;
    private OkhttpUtils(){
    }

    public static OkhttpUtils getInstance(){
        if(okhttpUtils == null){
            okhttpUtils = new OkhttpUtils();
            client = new OkHttpClient.Builder()
                    .readTimeout(20, TimeUnit.SECONDS)
                    .writeTimeout(20,TimeUnit.SECONDS)
                    .connectTimeout(20,TimeUnit.SECONDS)
                    .addInterceptor(new LoggingInterceptor())
                    .build();
        }
        return okhttpUtils ;
    }

    private static OkHttpClient client ;

    public void asy(Map<String,String> params,String url,AbstractUiCallBack callBack){
        Request request = null ;
        if(params != null){
            FormBody.Builder builder = new FormBody.Builder() ;
            for(Map.Entry<String,String> entry : params.entrySet()){
                builder.add(entry.getKey(),entry.getValue());
            }
            FormBody body =  builder.build();
            request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();
        } else {
            request = new Request.Builder()
                    .url(url)
                    .build();
        }
        client.newCall(request).enqueue(callBack);
    }

    private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");

    public static void postFile(Map<String,String> map, String url, File file,AbstractUiCallBack callBack) {

        String[] array = file.getAbsolutePath().split("\\/");

        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);

        for (Map.Entry<String, String> entry : map.entrySet()) {
            builder.addFormDataPart(entry.getKey(), entry.getValue());
        }
        builder.addFormDataPart("imageFileName", array[array.length - 1]);

        if (file.exists() && file.length() > 0) {
            builder.addFormDataPart("image", array[array.length - 1], RequestBody.create(MEDIA_TYPE_PNG, file));
        }
        MultipartBody body = builder.build();

        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        client.newCall(request).enqueue(callBack);
    }
}

   OKhttp封装需实现的接口类   

import android.os.Handler;
import android.os.Looper;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
/**
 *  * Okhttp 单例 范型的封装
 */
public  abstract  class AbstractUiCallBack<T> implements Callback {
    /**
     * 成功回调
     * @param t
     */
    public abstract void success(T t);

    /**
     * 失败回调
     * @param e
     */
    public abstract void failure(Exception e);

    private Handler handler = null ;
    private Class clazz ;

    public AbstractUiCallBack(){
        handler = new Handler(Looper.getMainLooper());

        //  得到的是一个 AbstractUiCallBack<T> 的Type
       Type type =  getClass().getGenericSuperclass() ;

        // 得到的是T的实际Type
       Type [] arr =  ((ParameterizedType)type).getActualTypeArguments() ;

        clazz = (Class) arr[0] ;
    }

    @Override
    public void onFailure(Call call, IOException e) {
        failure(e);
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        try {
            String result = response.body().string();
            System.out.println("result = " + result);
            Gson gson = new Gson();

            final T t = (T) gson.fromJson(result,clazz);

            handler.post(new Runnable() {
                @Override
                public void run() {
                    success(t);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
            failure(e);
        } catch (JsonSyntaxException e) {
            e.printStackTrace();
            failure(e);
        }
    }
}

二. 拦截器类

import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

//拦截器类
public class LoggingInterceptor implements Interceptor{
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();  //请求对象
        /**
         * 返回最准确的可用系统计时器的当前值,以毫微秒为单位
         * 返回值表示从某一固定但任意的时间算起的毫微秒数
         */
        long time1 = System.nanoTime();

        Response response = chain.proceed(request);  //响应对象
        long time2 = System.nanoTime();

        System.out.println("响应时长 = "+(time2 - time1));
        return response;
    }
}

三. model层

import com.bwie.secondweek.bean.MyDataBean;
import com.bwie.secondweek.okhttp.AbstractUiCallBack;
import com.bwie.secondweek.okhttp.OkhttpUtils;

/**
 * model层,数据的存取
 */
public class DataModel {
    //上拉刷新下拉加载更多
    public void onRefresh(boolean b, final DataModelCallBack modelCallBack){
        OkhttpUtils.getInstance().asy(null, "http://v.juhe.cn/toutiao/index?type=toutiao&key=c4479ad58f41e7f78a8fa073d0b1f1b5", new AbstractUiCallBack<MyDataBean>() {
            @Override
            public void success(MyDataBean dataBean) {
                modelCallBack.success(dataBean);
            }

            @Override
            public void failure(Exception e) {
                modelCallBack.failure(e);
            }
        });
    }

    //定义接口
    public interface DataModelCallBack{
        public void success(MyDataBean dataBean);   //成功获取数据
        public void failure(Exception e);            //数据获取失败
    }
}

四. view层

import com.bwie.secondweek.bean.MyDataBean;
/**
 * view层,UI界面的搭建
 */
public interface DataView {
    public void success(MyDataBean dataBean);   //成功获取数据
    public void failure(Exception e);            //数据获取失败
}

五. presenter层

import com.bwie.secondweek.bean.MyDataBean;
import com.bwie.secondweek.model.DataModel;
import com.bwie.secondweek.view.DataView;

/**
 * presenter层,进行model和view层之间数据的交互
 */
public class DataPresenter {
    private DataView dataView;
    private DataModel dataModel;

    //构造方法中声明view层,初始化model层数据
    public DataPresenter(DataView dataView) {
        this.dataView = dataView;
        dataModel = new DataModel();
    }

    //调用model层接口,上拉加载下拉刷新
    public void onRefresh(final boolean b){
        dataModel.onRefresh(b, new DataModel.DataModelCallBack() {
            @Override
            public void success(MyDataBean dataBean) {
                dataView.success(dataBean);
            }

            @Override
            public void failure(Exception e) {
                dataView.failure(e);
            }
        });
    }
}

六. imageloader工具类及其全局初始化配置

(1)全局初始化配置类:

package com.bwie.secondweek.util;

import android.app.Application;
//全局初始化Application类
public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        //配置imageLoader
        ImageLoaderUtil.init(this);
    }
}

(2)imageloader工具类:

package com.bwie.secondweek.util;
import android.content.Context;
import android.graphics.Bitmap;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.decode.BaseImageDecoder;
import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import com.nostra13.universalimageloader.utils.StorageUtils;

import java.io.File;
public class ImageLoaderUtil {
    /**
     * 初始化imageLoader
     * @param context
     */
    public static void init(Context context) {
        //1.获取配置config对象
        File cacheDir = StorageUtils.getCacheDirectory(context);  //缓存文件夹路径

        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)

                .threadPoolSize(3) // default  线程池内加载的数量
                .threadPriority(Thread.NORM_PRIORITY - 2) // default 设置当前线程的优先级
                .tasksProcessingOrder(QueueProcessingType.FIFO) // default
                .denyCacheImageMultipleSizesInMemory()
                .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) //可以通过自己的内存缓存实现
                .memoryCacheSize(2 * 1024 * 1024)  // 内存缓存的最大值
                .memoryCacheSizePercentage(13) // default
                .diskCache(new UnlimitedDiscCache(cacheDir)) // default 可以自定义缓存路径
                .diskCacheSize(50 * 1024 * 1024) // 50 Mb sd卡(本地)缓存的最大值
                .diskCacheFileCount(100)  // 可以缓存的文件数量
                // default为使用HASHCODE对UIL进行加密命名, 还可以用MD5(new Md5FileNameGenerator())加密
                .diskCacheFileNameGenerator(new HashCodeFileNameGenerator())
                .imageDownloader(new BaseImageDownloader(context)) // default
                .imageDecoder(new BaseImageDecoder(true)) // default
                .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default
                .writeDebugLogs() // 打印debug log
                .build(); //开始构建


        //2.初始化配置...ImageLoader.getInstance()图片加载器的对象,单例模式
        ImageLoader.getInstance().init(config);
    }

    /**
     * imageLoader加载图片的默认选项
     * @return
     */
    public static DisplayImageOptions getDefaultOption(){

        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.mipmap.ic_launcher) // 设置图片下载期间显示的默认图片
                .showImageForEmptyUri(R.mipmap.ic_launcher) // 设置图片Uri为空或是错误的时候显示的图片
                .showImageOnFail(R.mipmap.ic_launcher) // 设置图片加载或解码过程中发生错误显示的图片
                .resetViewBeforeLoading(true)  // default 设置图片在加载前是否重置、复位
                .delayBeforeLoading(1000)  // 下载前的延迟时间
                .cacheInMemory(true) // default  设置下载的图片是否缓存在内存中
                .cacheOnDisk(true) // default  设置下载的图片是否缓存在SD卡中

                .considerExifParams(true) // default
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示
                .bitmapConfig(Bitmap.Config.RGB_565) // default 设置图片的解码类型

                .displayer(new SimpleBitmapDisplayer()) // default  还可以设置圆角图片new RoundedBitmapDisplayer(20)

                .build();

        return options;
    }

    /**
     * imageLoader加载圆角图片....指定圆角的大小
     * @return
     */
    public static DisplayImageOptions getRoundedOption(int corner){

        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.mipmap.ic_launcher) // 设置图片下载期间显示的图片
                .showImageForEmptyUri(R.mipmap.ic_launcher) // 设置图片Uri为空或是错误的时候显示的图片
                .showImageOnFail(R.mipmap.ic_launcher) // 设置图片加载或解码过程中发生错误显示的图片
                .resetViewBeforeLoading(true)  // default 设置图片在加载前是否重置、复位
                .delayBeforeLoading(1000)  // 下载前的延迟时间
                .cacheInMemory(true) // default  设置下载的图片是否缓存在内存中
                .cacheOnDisk(true) // default  设置下载的图片是否缓存在SD卡中

                .considerExifParams(true) // default
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示
                .bitmapConfig(Bitmap.Config.RGB_565) // default 设置图片的解码类型
                .displayer(new RoundedBitmapDisplayer(corner)) // default  还可以设置圆角图片new RoundedBitmapDisplayer(20)

                .build();

        return options;
    }

}

七. 数据接口封装的bean类(根据自己需要定义)

八. 主功能代码MainActivity

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;
import com.bwie.secondweek.adapter.DataAdapter;
import com.bwie.secondweek.bean.MyDataBean;
import com.bwie.secondweek.presenter.DataPresenter;
import com.bwie.secondweek.view.DataView;
import com.liaoinstan.springview.container.DefaultFooter;
import com.liaoinstan.springview.container.DefaultHeader;
import com.liaoinstan.springview.widget.SpringView;
import butterknife.Bind;
import butterknife.ButterKnife;
//主功能代码类,实现view层,进行数据UI的获取
public class MainActivity extends AppCompatActivity implements DataView {
    @Bind(R.id.recyclerView)
    RecyclerView recyclerView;
    @Bind(R.id.springview)
    SpringView springview;
    private DataPresenter dataPresenter;
    private DataAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        //声明presenter层
        dataPresenter = new DataPresenter(this);

        //设置布局适配器,,,线性布局管理器
        adapter = new DataAdapter(this);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(adapter);

        //设置SpringView进行多条目加载的头布局和尾布局
        springview.setHeader(new DefaultHeader(this));
        springview.setFooter(new DefaultFooter(this));

        //设置SpringView的刷新监听事件
        springview.setListener(new SpringView.OnFreshListener() {
            @Override
            public void onRefresh() {
                dataPresenter.onRefresh(true);
            }

            @Override
            public void onLoadmore() {
                dataPresenter.onRefresh(false);
            }
        });

        dataPresenter.onRefresh(true);  //设置一直刷新数据
    }

    @Override
    public void success(MyDataBean dataBean) {
        //只要有数据就一直加载
        if (springview != null){
            springview.onFinishFreshAndLoad();
        }
        adapter.addData(dataBean.getResult().getData());
    }

    @Override
    public void failure(Exception e) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this,"数据出错",Toast.LENGTH_SHORT).show();
            }
        });
    }
}

九. 自定义适配器类

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bwie.secondweek.R;
import com.bwie.secondweek.bean.MyDataBean;
import com.bwie.secondweek.util.ImageLoaderUtil;
import com.nostra13.universalimageloader.core.ImageLoader;
import java.util.ArrayList;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;

/**
 * 条目布局适配器
 */
public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context context;
    private List<MyDataBean.ResultBean.DataBean> list;

    public DataAdapter(Context context) {
        this.context = context;
    }

    //声明数据来源,添加数据
    public void addData(List<MyDataBean.ResultBean.DataBean> list) {
        if (this.list == null) {
            this.list = new ArrayList<>();
        }
        this.list.addAll(list);
        notifyDataSetChanged();
    }

    //创建条目布局
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == 0) {
            View view01 = LayoutInflater.from(context).inflate(R.layout.item1, parent, false);
            return new ViewHolder01(view01);
        } else if (viewType == 1) {
            View view02 = LayoutInflater.from(context).inflate(R.layout.item2, parent, false);
            return new ViewHolder02(view02);
        } else {
            View view03 = LayoutInflater.from(context).inflate(R.layout.item3, parent, false);
            return new ViewHolder03(view03);
        }
    }

    //绑定数据
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        //判断加载布局的类型
        if (holder instanceof ViewHolder01) {
            ViewHolder01 holder01 = (ViewHolder01) holder;
            ImageLoader.getInstance().displayImage(list.get(position).getThumbnail_pic_s(), holder01.listItem1Imageview, ImageLoaderUtil.getDefaultOption());
        } else if (holder instanceof ViewHolder02) {
            ViewHolder02 holder02 = (ViewHolder02) holder;
            ImageLoader.getInstance().displayImage(list.get(position).getThumbnail_pic_s(), holder02.listItem2Imageview1, ImageLoaderUtil.getDefaultOption());
            ImageLoader.getInstance().displayImage(list.get(position).getThumbnail_pic_s02(), holder02.listItem2Imageview2, ImageLoaderUtil.getDefaultOption());
        } else {
            ViewHolder03 holder03 = (ViewHolder03) holder;
            ImageLoader.getInstance().displayImage(list.get(position).getThumbnail_pic_s(), holder03.listItem3Imageview1, ImageLoaderUtil.getDefaultOption());
            ImageLoader.getInstance().displayImage(list.get(position).getThumbnail_pic_s02(), holder03.listItem3Imageview2, ImageLoaderUtil.getDefaultOption());
            ImageLoader.getInstance().displayImage(list.get(position).getThumbnail_pic_s03(), holder03.listItem3Imageview3, ImageLoaderUtil.getDefaultOption());
        }
    }

    @Override
    public int getItemViewType(int position) {
        //判断布局类型,加载不同数据
        if (!TextUtils.isEmpty(list.get(position).getThumbnail_pic_s03())) {
            return 2;
        }else if (!TextUtils.isEmpty(list.get(position).getThumbnail_pic_s02())) {
            return 1;
        }else {
            return 0;
        }
    }

    //首先加载三种图片布局
    @Override
    public int getItemCount() {
        return list == null ? 0 : list.size();
    }

    static class ViewHolder01 extends RecyclerView.ViewHolder {
        @Bind(R.id.list_item1_textview)
        TextView listItem1Textview;
        @Bind(R.id.list_item1_imageview)
        ImageView listItem1Imageview;

        ViewHolder01(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }

    static class ViewHolder02 extends RecyclerView.ViewHolder {
        @Bind(R.id.list_item2_textview)
        TextView listItem2Textview;
        @Bind(R.id.list_item2_imageview1)
        ImageView listItem2Imageview1;
        @Bind(R.id.list_item2_imageview2)
        ImageView listItem2Imageview2;
        ViewHolder02(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }

    static class ViewHolder03 extends RecyclerView.ViewHolder {
        @Bind(R.id.list_item3_textview)
        TextView listItem3Textview;
        @Bind(R.id.list_item3_imageview1)
        ImageView listItem3Imageview1;
        @Bind(R.id.list_item3_imageview2)
        ImageView listItem3Imageview2;
        @Bind(R.id.list_item3_imageview3)
        ImageView listItem3Imageview3;
        ViewHolder03(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}

十. 页面布局

1. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.liaoinstan.springview.widget.SpringView
        android:id="@+id/springview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
    </com.liaoinstan.springview.widget.SpringView>

</RelativeLayout>

2. 条目一:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:layout_gravity="center_horizontal"
        android:id="@+id/list_item1_imageview"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_marginTop="18dp"
        android:src="@mipmap/ic_launcher" />
</LinearLayout>


3. 条目二:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="18dp"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/list_item2_imageview1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher" />

        <ImageView
            android:id="@+id/list_item2_imageview2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher" />
    </LinearLayout>
</LinearLayout>


4. 条目三:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="18dp"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/list_item3_imageview1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher" />

        <ImageView
            android:id="@+id/list_item3_imageview2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher" />

        <ImageView
            android:id="@+id/list_item3_imageview3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher" />
    </LinearLayout>
</LinearLayout>

注:

最后在  清单文件中  AndroidManifest.xml中配置权限,全局配置imageloader类

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

android:name=".util.BaseApplication"


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值