【安卓开发之图片分享应用6:显示网络图片且点击会放大图片】


开发过程中遇到的问题:CLEARTEXT communication to xxx.xxx.xxx not permitted by network security policy


1、W/System.err: java.net.UnknownServiceException:

报错

W/System.err: java.net.UnknownServiceException: 
CLEARTEXT communication to xxx.xxx.xxx not permitted by network security policy


问题分析:

  为保证用户数据和设备的安全,Google针对下一代 Android 系统(Android P) 的应用程序,将要求默认使用加密连接,这意味着 Android P 将禁止 App 使用所有未加密的连接,因此运行 Android P 系统的安卓设备无论是接收或者发送流量,未来都不能明码传输,需要使用下一代(Transport Layer Security)传输层安全协议,而 Android Nougat 和 Oreo 则不受影响。
  在Android P系统的设备上,如果应用使用的是非加密的明文流量的http网络请求,则会导致该应用无法进行网络请求,https则不会受影响,同样地,如果应用嵌套了webview,webview也只能使用https请求。



解决方法:往AndroidManifestapplication中设置下列属性即可。

android:usesCleartextTraffic="true"

在这里插入图片描述


一、效果演示


这次主要是实现的功能有以下几点:

  • 通过网络图片链接显示网络图片。
  • 点击该图片后会放大图片。(主要是实现这个

如下gif所示:通过之前的博客,我们已经实现了上传图片到服务器,我们可以得到上传图片的链接,接着就可以通过图片链接来访问到图片,并在页面展示出来。并点击之后实现放大功能。

在这里插入图片描述




二、 导入相关依赖

(1)导入Glide框架依赖

显示网络图片我们可以导入Glide图片框架。且Glide框架版本不能小于4.12.0。我们在build.gradle里面添加下面代码即可。

    //glide图片框架
    implementation "com.github.bumptech.glide:glide:4.12.0"
    implementation 'com.github.bumptech.glide:annotations:4.12.0'
    implementation 'com.github.bumptech.glide:okhttp3-integration:4.12.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
    implementation 'jp.wasabeef:glide-transformations:4.3.0'


(2)导入点击图片打开大图依赖

实现图片放大的话我们可以导入下面这个库。我们在build.gradle里面添加下面代码即可。

    implementation 'com.github.FlyJingFish.OpenImage:OpenImageGlideLib:v1.2.92'

该作者的Github网址为:https://github.com/FlyJingFish/OpenImage,想深入了解的可以进去看看。


三、 实现显示图片以及点击放大图片的工具类:

(1)MyApplicationMyAppGlideModuleBigImageHelperImpl以及MyImageLoader

MyApplication类:
工具类,不用看,主要是加载大图。复制到项目里面即可,报错也先别管,先把后面的类也用上。

import android.app.Application;

import com.flyjingfish.openimagelib.OpenImageConfig;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyApplication extends Application {
    public static MyApplication mInstance;
    public static ExecutorService cThreadPool = Executors.newFixedThreadPool(5);
    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
        //初始化大图加载器
        OpenImageConfig.getInstance().setBigImageHelper(new BigImageHelperImpl());
    }
}

MyAppGlideModule类:
工具类,不用看。复制到项目里面即可,报错也先别管,先把后面的类也用上。

import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;

import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;

@GlideModule
public class MyAppGlideModule extends AppGlideModule {

    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        super.applyOptions(context, builder);
        builder.setLogLevel(Log.DEBUG);
    }
}

MyImageLoader类:
我们主要是调用这个类来显示图片,也不用看,后面会有怎么使用。

import android.graphics.drawable.Drawable;
import android.widget.ImageView;

import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;

import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
//import com.example.picture10.GlideApp;
//import com.example.picture10.MyApplication;
import com.flyjingfish.openimagelib.enums.ImageDiskMode;
import com.flyjingfish.openimagelib.utils.ActivityCompatHelper;
import com.flyjingfish.openimagelib.utils.ScreenUtils;

import jp.wasabeef.glide.transformations.BlurTransformation;

public class MyImageLoader {
    public static int load_img_type = 0;
    public static final int GLIDE = 1;
    public static int loader_os_type = GLIDE;
    public static ImageDiskMode imageDiskMode = ImageDiskMode.CONTAIN_ORIGINAL;
    private MyImageLoader() {
    }

    private static MyImageLoader mInstance;

    public static MyImageLoader getInstance() {
        if (null == mInstance) {
            synchronized (MyImageLoader.class) {
                if (null == mInstance) {
                    mInstance = new MyImageLoader();
                }
            }
        }
        return mInstance;
    }

    public void load(ImageView iv, String url, @DrawableRes int p, @DrawableRes int err) {
        if (!ActivityCompatHelper.assertValidRequest(iv.getContext())){
            return;
        }
        into(url, iv, 0, 0, p, err, false, -1, false);
    }
    public void load(ImageView iv, String url, boolean isCircle, @DrawableRes int p, @DrawableRes int err) {
        if (!ActivityCompatHelper.assertValidRequest(iv.getContext())){
            return;
        }
        into(url, iv, 0, 0, p, err, isCircle, -1, false);
    }
    public void load(ImageView iv, String url, int w, int h, @DrawableRes int p, @DrawableRes int err) {
        if (!ActivityCompatHelper.assertValidRequest(iv.getContext()))
            return;
        into(url, iv, w, h, p, err, false, -1, false,null);
    }
    public void load(ImageView iv, String url, int w, int h, @DrawableRes int p, @DrawableRes int err,OnImageLoadListener requestListener) {
        if (!ActivityCompatHelper.assertValidRequest(iv.getContext()))
            return;
        into(url, iv, w, h, p, err, false, -1, false,requestListener);
    }
    public void load(ImageView iv, String url, int w, int h, boolean isCircle, @DrawableRes int p, @DrawableRes int err,OnImageLoadListener requestListener) {
        if (!ActivityCompatHelper.assertValidRequest(iv.getContext()))
            return;
        into(url, iv, w, h, p, err, isCircle, -1, false,requestListener);
    }

    public void loadRoundCorner(ImageView iv, String url, float radiusDp, @DrawableRes int p, @DrawableRes int err) {
        if (!ActivityCompatHelper.assertValidRequest(iv.getContext()))
            return;
        into(url, iv, 0, 0, p, err, false, radiusDp, false);
    }

    public void loadRoundCorner(ImageView iv, String url, float radiusDp, int w, int h, @DrawableRes int p, @DrawableRes int err,OnImageLoadListener requestListener) {
        if (!ActivityCompatHelper.assertValidRequest(iv.getContext()))
            return;
        into(url, iv, w, h, p, err, false, radiusDp, false,requestListener);
    }

    private void into(String url, ImageView iv, int w, int h, @DrawableRes int p, @DrawableRes int err, boolean isCircle, float radiusDp, boolean isBlur) {
        into(url, iv, w, h, p, err, isCircle, radiusDp, isBlur,null);
    }

    private void into(String url,ImageView iv, int w, int h, @DrawableRes int p, @DrawableRes int err, boolean isCircle, float radiusDp, boolean isBlur, OnImageLoadListener requestListener) {
        if (loader_os_type == GLIDE){
            RequestBuilder<Drawable> requestBuilder = GlideApp.with(iv).load(url);
            if (isBlur || isCircle || radiusDp != -1) {
                Transformation[] transformations = new Transformation[0];
                if (isBlur && !isCircle && radiusDp == -1) {
                    transformations = new Transformation[]{new CenterCrop(), new BlurTransformation()};
                } else if (isBlur && isCircle && radiusDp == -1) {
                    transformations = new Transformation[]{new CenterCrop(), new BlurTransformation(), new CircleCrop()};
                } else if (isBlur && !isCircle && radiusDp != -1) {
                    transformations = new Transformation[]{new CenterCrop(), new BlurTransformation(), new RoundedCorners(dp2px(radiusDp))};
                } else if (!isBlur && isCircle && radiusDp == -1) {
                    transformations = new Transformation[]{new CenterCrop(), new CircleCrop()};
                } else if (!isBlur && !isCircle && radiusDp != -1) {
                    transformations = new Transformation[]{new CenterCrop(), new RoundedCorners(dp2px(radiusDp))};
                }
                RequestOptions mRequestOptions = new RequestOptions().transform(transformations);

                requestBuilder.apply(mRequestOptions);
                if (w > 0 && h > 0)
                    mRequestOptions.override(w, h);
            } else if (w > 0 && h > 0) {
                requestBuilder.override(w, h);
            } else if (w == Target.SIZE_ORIGINAL && h == Target.SIZE_ORIGINAL) {
                requestBuilder.override(w, h);
            }
            if (imageDiskMode == ImageDiskMode.RESULT){
                requestBuilder.diskCacheStrategy(DiskCacheStrategy.RESOURCE);
            }if (imageDiskMode == ImageDiskMode.CONTAIN_ORIGINAL){
                requestBuilder.diskCacheStrategy(DiskCacheStrategy.ALL);
            }else if (imageDiskMode == ImageDiskMode.NONE){
                requestBuilder.diskCacheStrategy(DiskCacheStrategy.NONE);
            }
            if (p != -1)
                requestBuilder.placeholder(p);
            if (err != -1)
                requestBuilder.error(err);
            if (requestListener != null){
                requestBuilder.addListener(new RequestListener<Drawable>() {
                    @Override
                    public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                        requestListener.onFailed();
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                        requestListener.onSuccess();
                        return false;
                    }
                });
            }
            requestBuilder.into(iv);
        }
    }

    public interface OnImageLoadListener{
        void onSuccess();
        void onFailed();
    }

    public static int dp2px(float value) {
        return (int) ScreenUtils.dp2px(MyApplication.mInstance,value);
    }

}

BigImageHelperImpl类:
工具类,是加载大图的关键。

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition;
import com.flyjingfish.openimagelib.listener.BigImageHelper;
import com.flyjingfish.openimagelib.listener.OnLoadBigImageListener;

public class BigImageHelperImpl implements BigImageHelper {
    @Override
    public void loadImage(Context context, String imageUrl, OnLoadBigImageListener onLoadBigImageListener) {
            RequestOptions requestOptions = new RequestOptions()
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
                    .format(DecodeFormat.PREFER_RGB_565);
            Glide.with(context)
                    .load(imageUrl).apply(requestOptions).addListener(new RequestListener<Drawable>() {
                @Override
                public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                    onLoadBigImageListener.onLoadImageFailed();
                    return false;
                }

                @Override
                public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                    onLoadBigImageListener.onLoadImageSuccess(resource);
                    return false;
                }
            }).into(new CustomTarget<Drawable>() {
                @Override
                public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {

                }

                @Override
                public void onLoadCleared(@Nullable Drawable placeholder) {

                }
            });
    }

    @Override
    public void loadImage(Context context, String imageUrl, ImageView imageView) {
            RequestOptions requestOptions = new RequestOptions()
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
                    .format(DecodeFormat.PREFER_RGB_565);
            Glide.with(context)
                    .load(imageUrl).apply(requestOptions).into(imageView);
    }
}

(2)代码编写实现。

为了看懂,我写在一个Activity里。我将其命名为·TTTActivity·

MainActivity

import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import com.example.pictureapp.R;
import com.example.pictureapp.dao.UserDao;
import com.example.pictureapp.imageloader.MyImageLoader;
import com.flyjingfish.openimagelib.OpenImage;
import com.flyjingfish.openimagelib.beans.OpenImageUrl;
import com.flyjingfish.openimagelib.listener.ItemLoadHelper;
import com.flyjingfish.openimagelib.listener.OnLoadCoverImageListener;
import com.flyjingfish.openimagelib.listener.SourceImageViewIdGet;
import com.flyjingfish.openimagelib.transformers.ScaleInTransformer;

import java.util.ArrayList;
import java.util.List;

public class TTTActivity extends AppCompatActivity {
    private List<ImageDTO> onePieceList2 = new ArrayList<>();
    RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tttactivity);
        initView();
    }

    private void initView(){
        TextView tvName = findViewById(R.id.tvName);
        tvName.setText(UserDao.user.getNickname());
        
        ImageDTO imageEntity1 = new ImageDTO("http://xqzyyds.top/images/img_2.png");
        ImageDTO imageEntity2 = new ImageDTO("http://xqzyyds.top/images/img_3.png");
        ImageDTO imageEntity3 = new ImageDTO("http://xqzyyds.top/images/img_4.png");
        ImageDTO imageEntity4 = new ImageDTO("http://xqzyyds.top/images/img_5.png");

        onePieceList2.add(imageEntity1);
        onePieceList2.add(imageEntity2);
        onePieceList2.add(imageEntity3);
        onePieceList2.add(imageEntity4);
        onePieceList2.add(imageEntity1);
        onePieceList2.add(imageEntity2);
        onePieceList2.add(imageEntity3);
        onePieceList2.add(imageEntity4);


        recyclerView = findViewById(R.id.rv);
        StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(staggeredGridLayoutManager);
        TTTActivity.RvAdapter myAdapter = new RvAdapter(onePieceList2);
        recyclerView.setAdapter(myAdapter);

    }


    /**
     * 自定义图片瀑布流适配器
     */
    private class RvAdapter extends RecyclerView.Adapter<TTTActivity.RvAdapter.MyHolder> {
        List<ImageDTO> datas;

        public RvAdapter(List<ImageDTO> datas) {
            this.datas = datas;
        }

        @NonNull
        @Override
        public TTTActivity.RvAdapter.MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view;

            //设置布局
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_person, parent, false);

            return new TTTActivity.RvAdapter.MyHolder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull TTTActivity.RvAdapter.MyHolder holder, int position) {

            //图片
            MyImageLoader.getInstance().load(holder.ivImage, datas.get(position).getCoverImageUrl(), R.mipmap.img_load_placeholder, R.mipmap.img_load_placeholder);
            //设置点击图片后打开大图的监听器
            holder.ivImage.setOnClickListener(v -> {
                OpenImage.with(TTTActivity.this).setClickRecyclerView(recyclerView, new SourceImageViewIdGet() {
                            @Override
                            public int getImageViewId(OpenImageUrl data, int position) {
                                return R.id.iv_image;
                            }
                        })
                        .setAutoScrollScanPosition(true)
                        .setSrcImageViewScaleType(ImageView.ScaleType.CENTER_CROP, true)
                        .setImageUrlList(datas).setImageDiskMode(MyImageLoader.imageDiskMode)
                        .setItemLoadHelper(new ItemLoadHelper() {
                            @Override
                            public void loadImage(Context context, OpenImageUrl openImageUrl, String imageUrl, ImageView imageView, int overrideWidth, int overrideHeight, OnLoadCoverImageListener onLoadCoverImageListener) {

                                MyImageLoader.getInstance().load(imageView, imageUrl, overrideWidth, overrideHeight, R.mipmap.img_load_placeholder, R.mipmap.img_load_placeholder, new MyImageLoader.OnImageLoadListener() {

                                    @Override
                                    public void onSuccess() {
                                        onLoadCoverImageListener.onLoadImageSuccess();
                                    }

                                    @Override
                                    public void onFailed() {
                                        onLoadCoverImageListener.onLoadImageFailed();
                                    }
                                });
                            }
                        }).addPageTransformer(new ScaleInTransformer())
                        .setOpenImageStyle(R.style.DefaultPhotosTheme)
                        .setClickPosition(position).show();
            });
        }
        @Override
        public int getItemCount() {
            return datas.size();
        }

        class MyHolder extends RecyclerView.ViewHolder {
            ImageView ivImage;

            public MyHolder(@NonNull View itemView) {
                super(itemView);
                ivImage = (ImageView) itemView.findViewById(R.id.iv_image);
            }
        }
    }

上面的布局:activity_tttactivity.xml
因为有些资源是图片,所以换上自己的图片就行。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    tools:context=".activity.test.TTTActivity">

    <ScrollView
        android:scrollbars="none"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="80dp">

                <Button
                    android:id="@+id/set"
                    android:layout_width="35dp"
                    android:layout_height="35dp"
                    android:layout_alignParentEnd="true"
                    android:layout_alignParentBottom="true"
                    android:layout_marginEnd="30dp"
                    android:background="@mipmap/icon_setting" />

            </RelativeLayout>

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="130dp"
                android:gravity="center_vertical|bottom"
                android:paddingBottom="30dp">

                <androidx.cardview.widget.CardView
                    android:id="@+id/ivHead"
                    android:layout_width="60dp"
                    android:layout_height="60dp"
                    android:layout_marginStart="30dp"
                    android:layout_marginEnd="20dp"
                    app:cardElevation="10dp"
                    app:cardCornerRadius="12dp"
                    app:cardPreventCornerOverlap="true">

                    <ImageView
                        android:layout_width="60dp"
                        android:layout_height="60dp"
                        android:src="@drawable/icon_moren_usericon" />

                </androidx.cardview.widget.CardView>


                <TextView
                    android:id="@+id/tvName"
                    android:layout_width="200dp"
                    android:layout_height="30dp"
                    android:layout_toEndOf="@+id/ivHead"
                    android:ellipsize="end"
                    android:letterSpacing="0.1"
                    android:maxLines="1"
                    android:text="用户名"
                    android:textColor="#515151"
                    android:textSize="20sp"
                    android:textStyle="bold" />

                <TextView
                    android:id="@+id/tv_word"
                    android:layout_width="200dp"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/tvName"
                    android:layout_marginTop="10dp"
                    android:layout_toEndOf="@+id/ivHead"
                    android:text="留言:" />

                <TextView
                    android:id="@+id/tvMessage"
                    android:layout_width="200dp"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/tv_word"
                    android:layout_marginStart="30dp"
                    android:layout_toEndOf="@+id/ivHead"
                    android:maxLines="2"
                    android:text="这个人很懒,什么都没留下……" />
                
            </RelativeLayout>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="3dp"
                android:background="#e8e8e8"
                android:layout_below="@id/tvMessage"/>

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#03808080"
                android:paddingTop="5dp">

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv"
                    android:paddingBottom="60dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />

            </RelativeLayout>
        </LinearLayout>

    </ScrollView>

</FrameLayout>

单个图片布局:
item_person.xml

<?xml version="1.0" encoding="utf-8"?>
<ImageView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:id="@+id/iv_image"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:layout_margin="2dp"
    android:scaleType="fitXY">
</ImageView>

每个图片封装起来:
ImageDTO:

import com.flyjingfish.openimagelib.beans.OpenImageUrl;
import com.flyjingfish.openimagelib.enums.MediaType;

public class ImageDTO implements OpenImageUrl {
    public String url;

    public ImageDTO(String url) {
        this.url = url;
    }

    public ImageDTO() {
    }

    @Override
    public String getImageUrl() {
        return url;//大图链接(或视频的封面大图链接)
    }

    @Override
    public String getVideoUrl() {
        return null;//视频链接
    }

    @Override
    public String getCoverImageUrl() {
        return url;//封面小图链接(或视频的封面小图链接)
    }

    @Override
    public MediaType getType() {
        return MediaType.IMAGE;//数据是图片还是视频
    }
}

四、完善代码

全部写完之后这里会有一个爆红:
在这里插入图片描述
但是没关系,我们需要编译一下,然后重新点击这个红色的地方就可以import了,编译不行的话,就点击执行。


这里是图片加载不出来时显示的图片,可以换上自己要显示的图片:
在这里插入图片描述
比如:
在这里插入图片描述



最后大功告成,谢谢大家的观看,如有问题欢迎反馈。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值