关于startActivityForResult() 被废弃这件事

关于startActivityForResult() G了这件事

就很奇怪

register.setOnClickListener(view -> {
            startActivityForResult(new Intent(MainActivity.this,SecondActivity.class),1);
        });

就一个简单的带返回数据的请求启动,结果…

startActivityForResult(new Intent(MainActivity.this,SecondActivity.class),1);

被弃用了?

先来看看可爱(失智)的官方怎么说,好像没找到,那就去看看网上那群大佬Android博主咋说。

看了大佬们的一顿操作之后,全是kotlin,焯。整一篇java的供java人们食用

registerForActivityResult()是startActivityForResult()的替代,简化了数据回调的写法

个人理解,之前以startActivityForReslut(Intent intent,int requestCode)这种方式启动Activity,然后在启动的Activity那里重写一个onActivityResult(int requestCode, int resultCode, Intent data)进行回调,官方jio得太复杂了。而且代码冗余,还得通过requestCode单独去判断到底是谁启动的哪个Activity。我们来看看原来的写法:

//启动Activity
{
    startActivityForResult(new Intent(One.this,Two.class),1);
}
//然后启动的Activity结束之后的回调
{
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1){
            if (resultCode == RESULT_OK){
                if (data!=null){
                    //进行取数据操作
                }
            }
        }
    }
}

emmm,貌似不是很麻烦欸,别急看看官方用的

ActivityResultLauncher<Intent> launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
            if (result.getResultCode() == RESULT_OK) {
                Intent data = result.getData();
                if (data != null) {
                   //进行数据操作
                }
            }
        });
        register.setOnClickListener(view -> {
            launcher.launch(new Intent(MainActivity.this, SecondActivity.class));
        });

怎么说,感觉其实也没省几行代码,registerForActivityResult的两个参数大致为启动类型,桥豆麻袋,我看见了好玩的东西,先上一段官方的代码

val getContent = registerForActivityResult(GetContent()) { uri: Uri? ->
    // Handle the returned Uri
}

override fun onCreate(savedInstanceState: Bundle?) {
    // ...

    val selectButton = findViewById<Button>(R.id.select_button)

    selectButton.setOnClickListener {
        // Pass in the mime type you'd like to allow the user to select
        // as the input
        getContent.launch("image/*")
    }
}

介玩意儿竟然能直接选图片!

我们来看一下示例

//在onCreate里面先注册一个拍照返回bitmap的启动成员变量
takePhotoBitmapResult = registerForActivityResult(new ActivityResultContracts.TakePicturePreview(), new ActivityResultCallback<Bitmap>() {
            @Override
            public void onActivityResult(Bitmap result) {
                ImageView imageView = getImageView();
                imageView.setImageBitmap(result);
                //将ImageView放入布局中
                addView(imageView);
            }
            //因为只需要获得预览图
        });
/*   */
//然后在一个监听事件中调用一下这个
takePhotoBitmapResult.launch(null);

然后就

在这里插入图片描述

图片就这么被转换成bitmap了?我的天哪!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!OH!

妈妈再也不用担心new File() 出来个 permission denied了(上次Android 12 的小米 录音文件授权了也获取不到,Manifests.xml加了

android:requestLegacyExternalStorage="true"

也没用)

但不是说不用授权就可以访问图片和拍照了(想脾持),肯定还是要动态申请权限的,对于registerForActivityResult来说,权限申请啥的也是完全没问题

private ActivityResultLauncher<String> permissionResult = registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback<Boolean>() {
            @Override
            public void onActivityResult(Boolean result) {
                if (result) {
                    Toast.makeText(TakePhoto.this, "您同意了该权限", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(TakePhoto.this, "您拒绝了该权限", Toast.LENGTH_SHORT).show();
                }
            }
            //在这里加入你要请求的权限
        });

        //获取单个权限
        requestPermission.setOnClickListener(view -> {
            //获取相机权限
            permissionResult.launch(Manifest.permission.CAMERA);
        });
//请求多个权限
private ActivityResultLauncher<String[]> permissionsResult = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
            @Override
            public void onActivityResult(Map<String, Boolean> result) {
                //请求完成回调后权限名称和是否同意授权被封装到了一个Map<String,Boolean>中
                Set<Map.Entry<String, Boolean>> set = result.entrySet();
                for (Map.Entry<String, Boolean> item : set) {
                    switch (item.getKey()) {
                        case Manifest.permission.CAMERA: {
                            showMsg(item, "相机");
                            break;
                        }
                        case Manifest.permission.WRITE_EXTERNAL_STORAGE: {
                            showMsg(item, "读写");
                            break;
                        }
                        case Manifest.permission.READ_CONTACTS: {
                            showMsg(item, "读取通讯录");
                            break;
                        }
                    }
                }
            }
        });

演示:

show2

不仅如此,官方还非常给了非常多人性化的接口调用:
Contract介绍
StartActivityForResult通用的Contract,不做任何转换,Intent作为输入,ActivityResult作为输出,这也是最常用的一个协定
RequestPermission用于请求单个权限
RequestMultiplePermissions用于请求一组权限
TakePicturePreview调用MediaStore.ACTION_IMAGE_CAPTURE拍照,返回值为Bitmap图片
TakePicture调用MediaStore.ACTION_IMAGE_CAPTURE拍照,并将图片保存到给定的Uri地址,返回true表示保存成功
TakeVideo调用MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频,保存到给定的Uri地址,返回一张缩略图
PickContact从通讯录APP获取联系人
GetContent提示用选择一条内容,返回一个通过ContentResolver.openInputStream(Uri)访问原生数据的Uri地址(content://形式) 。默认情况下,它增加了Intent.CATEGORY_OPENABLE, 返回可以表示流的内容
CreateDocument提示用户选择一个文档,返回一个(file:/http:/content:)开头的Uri
OpenMultipleDocuments提示用户选择文档(可以选择多个),分别返回它们的Uri,以List的形式
OpenDocumentTree提示用户选择一个目录,并返回用户选择的作为一个Uri返回,应用程序可以完全管理返回目录中的文档

注意:所有的registerForActivityResult()都必须的Activity生命周期中的onStart()方法前调用,换言之创建ActivityResultLauncher 这种操作全部都只能在onCreate()里面,那么也就意味着 ActivityResultLauncher 类型的所有变量都必须为全局的,如果在按钮或View带的点击监听中取注册一个ActivityResultLauncher ,那么他就是在View点击的时候创建的,就会报错,所以只能在onCreate里面创建,然后在View的监听里进行操作,类似于:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        
        // 前面的一些操作
        
        ActivityResultLauncher<Intent> launcher = registerForActivityResult(new           ActivityResultContracts.StartActivityForResult(), result -> {
            if (result.getResultCode() == RESULT_OK) {
                Intent data = result.getData();
                if (data != null) {
                    String user = data.getStringExtra("user");
                    String pwd = data.getStringExtra("pwd");
                    username.setText(user);
                    password.setText(pwd);
                }
            }
        });
        register.setOnClickListener(view -> {
            launcher.launch(new Intent(MainActivity.this, SecondActivity.class));
        });
    }

合着其实好像以没方便到哪去…(小声bb),可能是我还没发现更方便的操作吧。registerForActivityResult()不止可以使用这些内置的接口,还可以自定义,关于自定义本蒟蒻没有涉及太多,常用的场景官方都已经封装的差不多了。

下面是代码

Activity测试代码:
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;

import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import com.bumptech.glide.Glide;

import java.util.List;
import java.util.Map;
import java.util.Set;

@RequiresApi(api = Build.VERSION_CODES.Q)
public class TakePhoto extends AppCompatActivity {
    private Button requestPermission;
    private Button requestPermissions;
    private Button selectPhoto;
    private Button takePhotoBitmap;
    private Button takePhotoUri;
    private Button readContacts;
    private Button selectDoc;
    private Button selectDocs;
    private Button selectTree;
    private LinearLayout body;
    private Button selectPhotos;
    private Button selectMany;
    private ActivityResultLauncher<String> permissionResult;
    private ActivityResultLauncher<String[]> permissionsResult;
    private ActivityResultLauncher<String[]> selectPhotoResult;
    private ActivityResultLauncher<String[]> selectPhotosResult;
    private ActivityResultLauncher<Void> takePhotoBitmapResult;
    private ActivityResultLauncher<Uri> takePhotoResult;
    private ActivityResultLauncher<Void> readContactsResult;
    private ActivityResultLauncher<String[]> selectTextResult;
    private ActivityResultLauncher<String[]> selectTextsResult;
    private ActivityResultLauncher<Uri> selectTreeResult;
    private ActivityResultLauncher<String[]> selectManyResult;
    private Uri uri;

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

    private void initRegisterActivity() {
        permissionResult = registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback<Boolean>() {
            @Override
            public void onActivityResult(Boolean result) {
                if (result) {
                    Toast.makeText(TakePhoto.this, "您同意了该权限", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(TakePhoto.this, "您拒绝了该权限", Toast.LENGTH_SHORT).show();
                }
            }
            //在这里加入你要请求的权限
        });
        //为了更好的理解这个回调 没有简写成lambda表达式
        permissionsResult = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
            @Override
            public void onActivityResult(Map<String, Boolean> result) {
                Set<Map.Entry<String, Boolean>> set = result.entrySet();
                for (Map.Entry<String, Boolean> item : set) {
                    switch (item.getKey()) {
                        case Manifest.permission.CAMERA: {
                            showMsg(item, "相机");
                            break;
                        }
                        case Manifest.permission.WRITE_EXTERNAL_STORAGE: {
                            showMsg(item, "读写");
                            break;
                        }
                        case Manifest.permission.READ_CONTACTS: {
                            showMsg(item, "读取通讯录");
                            break;
                        }
                    }
                }
            }
        });
        selectPhotoResult = registerForActivityResult(new ActivityResultContracts.OpenDocument(), new ActivityResultCallback<Uri>() {
            @Override
            public void onActivityResult(Uri result) {
                ImageView imageView = getImageView();
                addView(imageView);
                Glide.with(TakePhoto.this).load(result).into(imageView);
            }
        });
        selectPhotosResult = registerForActivityResult(new ActivityResultContracts.OpenMultipleDocuments(), new ActivityResultCallback<List<Uri>>() {
            @Override
            public void onActivityResult(List<Uri> result) {
                if (result != null && result.size() != 0) {
                    GridView gridView = new GridView(TakePhoto.this);
                    gridView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
                    gridView.setNumColumns(2);
                    gridView.setAdapter(new MyAdapter(result));
                    addView(gridView);
                    Toast.makeText(TakePhoto.this, ""+result.size(), Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(TakePhoto.this, "你没有选择任何图片", Toast.LENGTH_SHORT).show();
                }
            }
        });
        takePhotoBitmapResult = registerForActivityResult(new ActivityResultContracts.TakePicturePreview(), new ActivityResultCallback<Bitmap>() {
            @Override
            public void onActivityResult(Bitmap result) {
                ImageView imageView = getImageView();
                imageView.setImageBitmap(result);
                addView(imageView);
            }
            //因为只需要获得预览图
        });
        takePhotoResult = registerForActivityResult(new ActivityResultContracts.TakePicture(), new ActivityResultCallback<Boolean>() {
            @Override
            public void onActivityResult(Boolean result) {
                if (result) {
                    ImageView imageView = getImageView();
                    Glide.with(TakePhoto.this).load(uri).into(imageView);
                    Log.d("takePhotoUri", uri.getPath());
                    addView(imageView);
                } else {
                    //没有拍照
                    Toast.makeText(TakePhoto.this, "没有拍摄照片", Toast.LENGTH_SHORT).show();
                }
            }
        });
        readContactsResult = registerForActivityResult(new ActivityResultContracts.PickContact(), new ActivityResultCallback<Uri>() {
            @Override
            public void onActivityResult(Uri result) {
                //but为啥还要用ContentResolver...害
                if (result != null) {
                    Cursor query = getContentResolver().query(result, null, null, null);
                    if (query.moveToFirst()) {
                        @SuppressLint("Range") String name = query.getString(query.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                        @SuppressLint("Range") String number = query.getString(query.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
                        Toast.makeText(TakePhoto.this, "联系人名称:" + name + "\n" + "电话号码:" + number, Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
        selectTextResult = registerForActivityResult(new ActivityResultContracts.OpenDocument(), new ActivityResultCallback<Uri>() {
            @Override
            public void onActivityResult(Uri result) {
                //我暂时也不知道拿到uri之后应该干些啥坏事
                Toast.makeText(TakePhoto.this, result.getPath(), Toast.LENGTH_SHORT).show();
            }
        });
        selectTextsResult = registerForActivityResult(new ActivityResultContracts.OpenMultipleDocuments(), new ActivityResultCallback<List<Uri>>() {
            @Override
            public void onActivityResult(List<Uri> result) {
                //就显示拿了几个吧
                Toast.makeText(TakePhoto.this, "" + result.size(), Toast.LENGTH_SHORT).show();
            }
        });
        selectTreeResult = registerForActivityResult(new ActivityResultContracts.OpenDocumentTree(), new ActivityResultCallback<Uri>() {
            @Override
            public void onActivityResult(Uri result) {
                //提示用户选择一个目录,并返回用户选择的作为一个Uri返回,应用程序可以完全管理返回目录中的文档。
                Toast.makeText(TakePhoto.this, result.getPath(), Toast.LENGTH_SHORT).show();
            }
        });
        
        selectManyResult = registerForActivityResult(new ActivityResultContracts.OpenMultipleDocuments(), new ActivityResultCallback<List<Uri>>() {
            @Override
            public void onActivityResult(List<Uri> result) {
                Toast.makeText(TakePhoto.this, "" + result.size(), Toast.LENGTH_SHORT).show();
            }
        });
    }


    private void initView() {
        requestPermission = (Button) findViewById(R.id.request_permission);
        requestPermissions = (Button) findViewById(R.id.request_permissions);
        selectPhoto = (Button) findViewById(R.id.select_photo);
        selectPhotos = (Button) findViewById(R.id.select_photos);
        takePhotoBitmap = (Button) findViewById(R.id.take_photo_bitmap);
        takePhotoUri = (Button) findViewById(R.id.take_photo_uri);
        readContacts = (Button) findViewById(R.id.read_contacts);
        selectDoc = (Button) findViewById(R.id.select_doc);
        selectDocs = (Button) findViewById(R.id.select_docs);
        selectTree = (Button) findViewById(R.id.select_tree);
        selectMany = (Button) findViewById(R.id.select_many);
        body = (LinearLayout) findViewById(R.id.body);

        //获取单个权限
        requestPermission.setOnClickListener(view -> {
            permissionResult.launch(Manifest.permission.CAMERA);
        });

        //获取多个权限
        requestPermissions.setOnClickListener(view -> {
            //在这里加入你要请求的权限列表,为String[]的形式,和老版本差不多
            permissionsResult.launch(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_CONTACTS});
        });

        //选择一张图片
        selectPhoto.setOnClickListener(view -> {
           selectPhotoResult.launch(new String[]{"image/*"});
        });
        //选择多张图片
        selectPhotos.setOnClickListener(view -> {
            selectPhotosResult.launch(new String[]{"image/*"});
        });

        //获得拍照图片预览图
        takePhotoBitmap.setOnClickListener(view -> {
            takePhotoBitmapResult.launch(null);
        });

        //拍摄照片并获得Uri
        takePhotoUri.setOnClickListener(view -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                ContentValues contentValues = new ContentValues();
                contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "测试图片.jpg");
                contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
                uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
                takePhotoResult.launch(uri);
            } else {
                //写过比这个版本底的拍照获取图片方式QAQ
                Toast.makeText(this, "版本太低自行适配滑稽", Toast.LENGTH_SHORT).show();
            }
        });

        //读取联系人
        readContacts.setOnClickListener(view -> {
           readContactsResult.launch(null);
        });

        //选择一个文本文件
        selectDoc.setOnClickListener(view -> {
            selectTextResult.launch(new String[]{"text/plain"});
        });

        //选择多个文本文件
        selectDocs.setOnClickListener(view -> {
           selectTextsResult.launch(new String[]{"text/plain"});
        });

        //选择一个目录
        selectTree.setOnClickListener(view -> {
            //我也暂时不知道这个目录用来干嘛QAQ
            //selectTreeResult.launch();

        });

        //选择多种文件
        selectMany.setOnClickListener(view -> {
            selectManyResult.launch(new String[]{"image/*","text/plain"});
        });

    }

    private void addView(View view) {
        body.addView(view);
        new Handler().postDelayed(() -> {
            body.removeView(view);
        }, 10000);
    }

    private void showMsg(Map.Entry<String, Boolean> item, String name) {
        if (item.getValue()) {
            Toast.makeText(this, name + "权限获取成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, name + "权限获取失败", Toast.LENGTH_SHORT).show();
        }
    }

    //动态生成一个ImageView,用来显示拍照或相册选择出的图片
    private ImageView getImageView() {
        ImageView imageView = new ImageView(TakePhoto.this);
        imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        return imageView;
    }

    //选取多张图片后GridView的适配器
    class MyAdapter extends BaseAdapter {

        List<Uri> data;

        public MyAdapter(List<Uri> data) {
            this.data = data;
        }

        @Override
        public int getCount() {
            return data.size();
        }

        @Override
        public Object getItem(int i) {
            return data.get(i);
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            @SuppressLint("ViewHolder") View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.grid_view_item, null);
            ImageView imageView = v.findViewById(R.id.image_view);
            Glide.with(viewGroup.getContext()).load(data.get(i)).into(imageView);
            return v;
        }
    }

}

layout布局文件

<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp"
    tools:context=".TakePhoto">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:gravity="center_horizontal"
            >
            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="请求单个权限"
                android:id="@+id/request_permission"
                />

            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="请求多个权限"
                android:id="@+id/request_permissions"
                />

            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="选择一张图片"
                android:id="@+id/select_photo"
                />

            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="选择多张图片"
                android:id="@+id/select_photos"
                />

            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="拍照返回Bitmap"
                android:id="@+id/take_photo_bitmap"
                />


            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="拍照返回Uri"
                android:id="@+id/take_photo_uri"
                />

            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="读取联系人"
                android:id="@+id/read_contacts"
                />

            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="选择一个文档"
                android:id="@+id/select_doc"
                />

            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="选择多个文档"
                android:id="@+id/select_docs"
                />

            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="选择一个目录"
                android:id="@+id/select_tree"
                />

            <Button
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:text="选择多种文件"
                android:id="@+id/select_many"
                />
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:id="@+id/body"
            android:orientation="vertical"
            >



        </LinearLayout>
    </LinearLayout>
</ScrollView>

GridView的item布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    android:gravity="center">

    <androidx.cardview.widget.CardView
        android:layout_width="150dp"
        android:layout_height="110dp"
        app:cardCornerRadius="10dp"
        app:cardElevation="0dp"
        >

        <ImageView
            android:layout_width="150dp"
            android:layout_height="110dp"
            android:id="@+id/image_view"
            android:scaleType="centerCrop"
            android:layout_gravity="center"
            />
    </androidx.cardview.widget.CardView>

</LinearLayout>

最后,附上项目地址:https://gitee.com/thor19/register-for-activity-result.git

Anddroid萌新,有问题欢迎指正,大佬们轻点喷。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值