1--安卓多媒体之图片综合篇

作者: e4e52c116681 | 来源:发表于2018-10-24 10:20 被阅读14次
    零、前言

    本篇将涉及:
    1.调用系统相机、上传到服务器操作
    2.大照片通过采样并压缩尺寸避免OOM
    3.media中图片的内容提供者使用方法,增删改查,获取手机所有图片路径
    4.显示最近100张照片
    5.通过系统图库选择一张加载到界面


    实验一:拍一张图片上传到服务器:

    1.打开系统系统相机
    // 注:Cons.CAMERA_RESULT = 1
     startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE), Cons.CAMERA_RESULT);
    
    2.接收返回的Bitmap
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            //通过intent获取Bundle中的"data"键的数据(即Bitmap)
            Bitmap bitmap = (Bitmap) data.getExtras().get("data");
            //上传照片逻辑
            doUpload(bitmap);
        }
    }
    
    3.基于OKHttp实现上传逻辑

    查看源码发现RequestBody.create不止可以接收File,还可以接收字节数组byte[]。思路:
    网络权限:<uses-permission android:name="android.permission.INTERNET"/>
    1.通过ByteArrayOutputStream拷贝Bitmap的字节
    2.通过MultipartBody模拟表单,生成请求对象Request
    3.将Request封装为Call对象,并执行Call

    /**
     * 模拟表单上传Bitmap:通过MultipartBody
     */
    private void doUpload(Bitmap bitmap) {
        //0.准备一个字节数组,准备将Bitmap放入其中
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
        
        //1.获取OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        //2.获取Request对象
        RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), baos.toByteArray());
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file", "test.jpg", fileBody)
                .build();
        Request request = new Request.Builder()
                .url(Cons.BASE_URL + "upload").post(requestBody).build();
        //3.将Request封装为Call对象,并执行Call
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e(TAG, "onFailure: " + e);
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                Log.e(TAG, "onResponse: " + result);
                runOnUiThread(() -> ToastUtil.showAtOnce(MainActivity.this, result));
            }
        });
    }
    
    4.SpringBoot实现服务端代码

    客户端完成了,多文件上传的服务端使用SpringBoot很轻松可以实现

    /**
     * 多文件上传(包括一个)
     *
     * @param files
     * @return
     */
    @PostMapping(value = "/upload")
    public @ResponseBody
    String uploadImg(@RequestParam("file") List<MultipartFile> files) {
        StringBuilder result = new StringBuilder();
        for (MultipartFile file : files) {
            if (file.isEmpty()) {
                return "false";
            }
            String fileName = file.getOriginalFilename();//获取名字
            String path = "F:/SpringBootFiles/imgs/";
            File dest = new File(path + "/" + fileName);
            if (!dest.getParentFile().exists()) { //判断文件父目录是否存在
                dest.getParentFile().mkdir();
            }
            try {
                file.transferTo(dest); //保存文件
                result.append(fileName + "上传成功!\n");
            } catch (IllegalStateException | IOException e) {
                e.printStackTrace();
                result.append(fileName + "上传失败!\n");
            }
        }
        return result.toString();
    }
    
    • 上传成功:不过仔细一看大小--195*260
    手机拍照.png

    实验二、Bitmap的采样,加载大图片

    内存问题:避免大图片导致的OOM(加载一个9.2M的图片,点两下):

    private void bitmapTest() {
        //生成Bitmap对象
        Bitmap bitmap = BitmapFactory.decodeFile(
                Environment.getExternalStorageDirectory() + "/DCIM/Camera/IMG20181018103528.jpg");
        mImageView.setImageBitmap(bitmap);
    }
    
    OOM时.png 传说中的OOM.png
    1.采样后适量缩小,解决OOM:思路

    1)创建Options对象op,对Bitmap做配置
    2)只获取Bitmap信息,不分配内存:op.inJustDecodeBounds = true
    3)设置压缩率,根据需求自己设置,这里为适应屏幕
    4)设置op解析出可显示的Bitmap,使用

    private void bitmapTest() {
        String pathName = Environment.getExternalStorageDirectory() + "/DCIM/Camera/IMG20181018103528.jpg";
        //1.创建Options对象op,对Bitmap做配置
        BitmapFactory.Options op = new BitmapFactory.Options();
        //2.只获取Bitmap信息,不分配内存
        op.inJustDecodeBounds = true;
        //以op配置来解析出Bitmap:fakeBitmap由于inJustDecodeBounds=true,无法显示
        Bitmap fakeBitmap = BitmapFactory.decodeFile(pathName, op);
        L.d(op.outWidth + "*" + op.outHeight + L.l());// 6240*8320
        //3.设置压缩率
        //获取屏幕尺寸
        int winH = ScrUtil.getScreenHeight(this);
        int winW = ScrUtil.getScreenWidth(this);
        op.inSampleSize = (int) (op.outHeight > op.outWidth ?
                Math.ceil(op.outHeight / winH) :
                Math.ceil(op.outWidth / winW));
        L.d(op.inSampleSize + L.l());// 4
        op.inJustDecodeBounds = false;
        //4.设置op解析出可显示的Bitmap,使用
        Bitmap realBitmap = BitmapFactory.decodeFile(pathName, op);
        mImageView.setImageBitmap(realBitmap);
    
    加载正常.png

    实验三、图片与内容提供者:

    media作为手机的三鼎之一,自然是少不了内容提供者来向外界暴漏信息
    主要储存在external.db(外部)internal.db(内部)两个数据库中
    数据库中图片的主要字段有:

    _id:id标识             _data: 图片绝对路径         _size: 图片大小            mime_type: 类型
    data_added:添加的时间   data_modifide:最后修改时间  _display_name:显示名称     description:描述
    width:宽                height:高
    
    media的内容提供者数据库.png
    1.获取内容提供者并添加一条自定义信息的图片
    private void insertImg() {
        //1.创建ContentValues对象,记录插入照片信息
        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.DISPLAY_NAME, "张风捷特烈");
        values.put(MediaStore.Images.Media.DESCRIPTION, "天下无双");
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        //2.获取内容提供者,插入(外部图片存储Uri,values),返回插入图片的Uri
        Uri imgFileUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        L.d(imgFileUri + L.l());//content://media/external/images/media/1064830
        //3.通过打开图片的意图添加额外信息将imgFileUri发送给系统相机
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imgFileUri);
        startActivity(intent);
    }
    
    2.通过内容提供者读取刚才插入的图片
     private void readImg() {
         try {
             //1.获取内容提供者,通过刚才的Uri打开输入流
             Uri imgUri = Uri.parse("content://media/external/images/media/1064830");
             InputStream is = getContentResolver().openInputStream(imgUri);
             //2.将图片解码展示
             Bitmap bitmap = BitmapFactory.decodeStream(is);
             mImageView.setImageBitmap(bitmap);
         } catch (FileNotFoundException e) {
             e.printStackTrace();
         }
     }
    
    3.更新描述信息
    private void updateImg() {
        ContentValues values = new ContentValues(2);
        values.put(MediaStore.Images.Media.DISPLAY_NAME, "Toly");
        values.put(MediaStore.Images.Media.DESCRIPTION, "Only Me");
        //1.获取内容提供者,通过刚才的Uri打开输入流
        Uri imgUri = Uri.parse("content://media/external/images/media/1064830");
        getContentResolver().update(imgUri, values, null, null);
    }
    
    4.查表

    既然是内容提供者,玩个表再所难免,借此回顾一下内容提供者的使用
    可见上面的修改方法成功

    private void queryImg() {
        //1.查询获得游标
        Cursor cursor = getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, "_id=1064830",
                null, null, null);
        //2.让游标移动,到尾为止
        while (cursor.moveToNext()) {
            String filePath = cursor.getString(cursor.getColumnIndex("_data"));
            String name = cursor.getString(cursor.getColumnIndex("_display_name"));
            String description = cursor.getString(cursor.getColumnIndex("description"));
            L.d(filePath + L.l());//storage/emulated/0/DCIM/Camera/1539834068417.jpg
            L.d(name + L.l());//Toly   
            L.d(description + L.l());//Only Me   
        }
    
    5.删除
    private void deleteImg() {
        Uri imgUri = Uri.parse("content://media/external/images/media/1064830");
        int delete = getContentResolver().delete(imgUri, "_id=1064830", null);
        L.d(delete + L.l());//1 表示删除了1行
    }
    
    6.获取所有图片的路径

    一共12540张图片,方法耗时:1.289秒,属于耗时操作应该放在子线程
    可以获取数据库中的字段,封装一个图片的实体类,以便使用

    private ArrayList<String> queryAllImg() {
        ArrayList<String> imgPaths = new ArrayList<>();
        //1.查询获得游标
        Cursor cursor = getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, "",
                null, null, null);
        //2.让游标移动,到尾为止
        while (cursor.moveToNext()) {
            String filePath = cursor.getString(cursor.getColumnIndex("_data"));
            imgPaths.add(filePath);
        }
        return imgPaths;
    }
    

    查询所有图片.png

    实验四、显示最近100张图片

    为了简便,使用Picasso来加载图片:详情可见--O2-开源框架使用之Picasso

    查询最近100张图片.png
    1.获取最近100条数据库记录

    排序条件:"date_added desc"表示根据date_added字段倒序查询
    将数据盛放在List中,并根据列表元素个数来决定跳出while循环

    private ArrayList<String> queryPic100() {
        ArrayList<String> imgPaths = new ArrayList<>();
        //1.查询获得游标
        String queryCol = MediaStore.Images.Media.DATE_ADDED;
        Cursor cursor = getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, "",
                null, "date_added desc", null);
        //2.让游标移动,到尾为止
        while (cursor.moveToNext()) {
            if (imgPaths.size() >= 100) {
                break;
            }
            String filePath = cursor.getString(cursor.getColumnIndex("_data"));
            imgPaths.add(filePath);
        }
        return imgPaths;
    }
    
    2.RecyclerView的简单使用(布局很简单就免了)

    1).创建适配器类和ViewHolder
    2).设置RecyclerView样式

    /**
     * 适配器
     */
    class PicRVAdapter extends RecyclerView.Adapter<PicViewHolder> {
        @NonNull
        @Override
        public PicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(Pic100Activity.this).inflate(R.layout.item_img, null);
            return new PicViewHolder(view);
        }
        @Override
        public void onBindViewHolder(@NonNull PicViewHolder holder, int position) {
            //使用Picasso加载文件图片
            Picasso.get().setIndicatorsEnabled(true);
            Picasso.get()
                    .load(new File(mList.get(position)))//文件
                    .resize(200,200)//重设尺寸
                    .into(holder.mIv_icon);
        }
        @Override
        public int getItemCount() {
            return mList.size();
        }
    }
    
    /**
     * ViewHolder
     */
    public class PicViewHolder extends RecyclerView.ViewHolder {
        public final ImageView mIv_icon;
        /**
         * itemView为MyViewHolder中onCreateViewHolder加载的布局
         *
         * @param itemView 条目
         */
        public PicViewHolder(View itemView) {
            super(itemView);
            mIv_icon = itemView.findViewById(R.id.id_iv_item);
        }
    }
    
    //1.设置适配器
    mIdRvPic100.setAdapter(new PicRVAdapter());
    //2.!!创建布局管理器
    mGLM = new GridLayoutManager(this, 4, GridLayoutManager.VERTICAL, false);
    //3.!!!设置布局管理器
    mIdRvPic100.setLayoutManager(mGLM);
    

    实验五、选择图片

     @OnClick(R.id.imageView)
     public void onViewClicked() {
         //打开相册
         Intent picIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
         startActivityForResult(picIntent, 0);
     }
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
         if (resultCode == RESULT_OK) {
             //获取返回的图片Uri
             Uri picUri = data.getData();
             InputStream is = null;
             try {
                 //将Uri开流,形成输入流
                 is = getContentResolver().openInputStream(picUri);
                 Bitmap bitmap = BitmapFactory.decodeStream(is);
                 mImageView.setImageBitmap(bitmap);
             } catch (FileNotFoundException e) {
                 e.printStackTrace();
             } finally {
                 try {
                     if (is != null) {
                         is.close();
                     }
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
         }
     }
    
    选择图片.png

    后记:捷文规范

    1.本文成长记录及勘误表
    项目源码 日期 备注
    V0.1--无 2018-10-24 1--安卓多媒体之图片综合篇
    2.更多关于我
    笔名 QQ 微信 爱好
    张风捷特烈 1981462002 zdl1994328 语言
    我的github 我的简书 我的CSDN 个人网站
    3.声明

    1----本文由张风捷特烈原创,转载请注明
    2----欢迎广大编程爱好者共同交流
    3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
    4----看到这里,我在此感谢你的喜欢与支持

    icon_wx_200.png

    相关文章

      网友评论

        本文标题:1--安卓多媒体之图片综合篇

        本文链接:https://www.haomeiwen.com/subject/phjttqtx.html