精华内容
下载资源
问答
  • 1.Android手机客户端,拍照(或选择图片),然后上传到服务器。 2.服务器端接收手机端上传上来的图片。 二、实现步骤: 1.按惯例,先放效果图: 项目结构: 2.activity_main.xml <?xml version=1.0 encoding=utf...
  • 这个demo实现了Android选择图片上传图片,包括上传单张图片和上传多张图片
  • 压缩文件包含了android端和web端,web端使用myeclipse8.5开发的,...具体实现了手机选择相册图片或者拍照能预览图片图片上传到服务器。发布到手机上测试可能需要手动在手机权限管理中打开摄像头和文件读写的权限。
  • 一个android上传图片的模块,选择系统相册,使用了一个第三方库takephoto,可以扩展上传到服务器
  • 1.选择图片上传界面,包括上传完成和异常的回调监听 package com.spring.sky.image.upload; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.app....
  • Android 选择图片上传图片之PictureSelector

    万次阅读 多人点赞 2018-02-08 16:55:34
    之前出过一篇 Android 选择图片上传图片之ImagePicker,这个是okgo作者出的,就一般需求来讲是够了,但是没有压缩,需要自己去搞。 后来业务需求提升,页面要美,体验要好,便不是那么满足需求了,所幸在github...

    效果图:
    这里写图片描述这里写图片描述这里写图片描述这里写图片描述

    【注意】Demo已更新到最新版本,并稍作调整。(2019-07-05)


    之前出过一篇 Android 选择图片、上传图片之ImagePicker,这个是okgo作者出的,就一般需求来讲是够了,但是没有压缩,需要自己去搞。
    后来业务需求提升,页面要美,体验要好,便不是那么满足需求了,所幸在github上找到PictureSelector(然后当时没多久Matisse就开源了…可以看这里Android 选择图片、上传图片之Matisse),也不用自己再撸一个了,下面来介绍介绍PictureSelector

    github

    https://github.com/LuckSiege/PictureSelector

    目前是一直在维护的,支持从相册或拍照选择图片或视频、音频,支持动态权限获取、裁剪(单图or多图裁剪)、压缩、主题自定义配置等功能、适配android 6.0+系统,而且你能遇到的问题,README文档都有解决方案。

    功能特点

    功能齐全,且兼容性好,作者也做了兼容测试

    1.适配android6.0+系统
    2.解决部分机型裁剪闪退问题
    3.解决图片过大oom闪退问题
    4.动态获取系统权限,避免闪退
    5.支持相片or视频的单选和多选
    6.支持裁剪比例设置,如常用的 1:1、3:4、3:2、16:9 默认为图片大小
    7.支持视频预览
    8.支持gif图片
    9.支持.webp格式图片
    10.支持一些常用场景设置:如:是否裁剪、是否预览图片、是否显示相机等
    11.新增自定义主题设置
    12.新增图片勾选样式设置
    13.新增图片裁剪宽高设置
    14.新增图片压缩处理
    15.新增录视频最大时间设置
    16.新增视频清晰度设置
    17.新增QQ选择风格,带数字效果
    18.新增自定义 文字颜色 背景色让风格和项目更搭配
    19.新增多图裁剪功能
    20.新增LuBan多图压缩
    21.新增单独拍照功能
    22.新增压缩大小设置
    23.新增Luban压缩档次设置
    24.新增圆形头像裁剪
    25.新增音频功能查询

    主题配置

    这个就想怎么改就怎么改了

    <!--默认样式 注意* 样式只可修改,不能删除任何一项 否则报错-->
        <style name="picture.default.style" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
            <!--标题栏背景色-->
            <item name="colorPrimary">@color/bar_grey</item>
            <!--状态栏背景色-->
            <item name="colorPrimaryDark">@color/bar_grey</item>
            <!--是否改变图片列表界面状态栏字体颜色为黑色-->
            <item name="picture.statusFontColor">false</item>
            <!--返回键图标-->
            <item name="picture.leftBack.icon">@drawable/picture_back</item>
            <!--标题下拉箭头-->
            <item name="picture.arrow_down.icon">@drawable/arrow_down</item>
            <!--标题上拉箭头-->
            <item name="picture.arrow_up.icon">@drawable/arrow_up</item>
            <!--标题文字颜色-->
            <item name="picture.title.textColor">@color/white</item>
            <!--标题栏右边文字-->
            <item name="picture.right.textColor">@color/white</item>
            <!--图片列表勾选样式-->
            <item name="picture.checked.style">@drawable/checkbox_selector</item>
            <!--开启图片列表勾选数字模式-->
            <item name="picture.style.checkNumMode">false</item>
            <!--选择图片样式0/9-->
            <item name="picture.style.numComplete">false</item>
            <!--图片列表底部背景色-->
            <item name="picture.bottom.bg">@color/color_fa</item>
            <!--图片列表预览文字颜色-->
            <item name="picture.preview.textColor">@color/tab_color_true</item>
            <!--图片列表已完成文字颜色-->
            <item name="picture.complete.textColor">@color/tab_color_true</item>
            <!--图片已选数量圆点背景色-->
            <item name="picture.num.style">@drawable/num_oval</item>
            <!--预览界面标题文字颜色-->
            <item name="picture.ac_preview.title.textColor">@color/white</item>
            <!--预览界面已完成文字颜色-->
            <item name="picture.ac_preview.complete.textColor">@color/tab_color_true</item>
            <!--预览界面标题栏背景色-->
            <item name="picture.ac_preview.title.bg">@color/bar_grey</item>
            <!--预览界面底部背景色-->
            <item name="picture.ac_preview.bottom.bg">@color/bar_grey_90</item>
            <!--预览界面状态栏颜色-->
            <item name="picture.status.color">@color/bar_grey_90</item>
            <!--预览界面返回箭头-->
            <item name="picture.preview.leftBack.icon">@drawable/picture_back</item>
            <!--是否改变预览界面状态栏字体颜色为黑色-->
            <item name="picture.preview.statusFontColor">false</item>
            <!--裁剪页面标题背景色-->
            <item name="picture.crop.toolbar.bg">@color/bar_grey</item>
            <!--裁剪页面状态栏颜色-->
            <item name="picture.crop.status.color">@color/bar_grey</item>
            <!--裁剪页面标题文字颜色-->
            <item name="picture.crop.title.color">@color/white</item>
            <!--相册文件夹列表选中图标-->
            <item name="picture.folder_checked_dot">@drawable/orange_oval</item>
        </style>
    

    功能配置

    // 进入相册 以下是例子:用不到的api可以不写
     PictureSelector.create(MainActivity.this)
     	.openGallery()//全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()
     	.theme()//主题样式(不设置为默认样式) 也可参考demo values/styles下 例如:R.style.picture.white.style
     	.maxSelectNum()// 最大图片选择数量 int
     	.minSelectNum()// 最小选择数量 int
    	.imageSpanCount(4)// 每行显示个数 int
     	.selectionMode()// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
     	.previewImage()// 是否可预览图片 true or false
     	.previewVideo()// 是否可预览视频 true or false
    	.enablePreviewAudio() // 是否可播放音频 true or false
     	.isCamera()// 是否显示拍照按钮 true or false
    	.imageFormat(PictureMimeType.PNG)// 拍照保存图片格式后缀,默认jpeg
    	.isZoomAnim(true)// 图片列表点击 缩放效果 默认true
    	.sizeMultiplier(0.5f)// glide 加载图片大小 0~1之间 如设置 .glideOverride()无效
    	.setOutputCameraPath("/CustomPath")// 自定义拍照保存路径,可不填
     	.enableCrop()// 是否裁剪 true or false
     	.compress()// 是否压缩 true or false
     	.glideOverride()// int glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
     	.withAspectRatio()// int 裁剪比例 如16:9 3:2 3:4 1:1 可自定义
     	.hideBottomControls()// 是否显示uCrop工具栏,默认不显示 true or false
     	.isGif()// 是否显示gif图片 true or false
    	.compressSavePath(getPath())//压缩图片保存地址
     	.freeStyleCropEnabled()// 裁剪框是否可拖拽 true or false
     	.circleDimmedLayer()// 是否圆形裁剪 true or false
     	.showCropFrame()// 是否显示裁剪矩形边框 圆形裁剪时建议设为false   true or false
     	.showCropGrid()// 是否显示裁剪矩形网格 圆形裁剪时建议设为false    true or false
     	.openClickSound()// 是否开启点击声音 true or false
     	.selectionMedia()// 是否传入已选图片 List<LocalMedia> list
     	.previewEggs()// 预览图片时 是否增强左右滑动图片体验(图片滑动一半即可看到上一张是否选中) true or false
     	.cropCompressQuality()// 裁剪压缩质量 默认90 int
     	.minimumCompressSize(100)// 小于100kb的图片不压缩 
     	.synOrAsy(true)//同步true或异步false 压缩 默认同步
     	.cropWH()// 裁剪宽高比,设置如果大于图片本身宽高则无效 int 
     	.rotateEnabled() // 裁剪是否可旋转图片 true or false
     	.scaleEnabled()// 裁剪是否可放大缩小图片 true or false
     	.videoQuality()// 视频录制质量 0 or 1 int
    	.videoMaxSecond(15)// 显示多少秒以内的视频or音频也可适用 int 
        .videoMinSecond(10)// 显示多少秒以内的视频or音频也可适用 int 
    	.recordVideoSecond()//视频秒数录制 默认60s int
    	.isDragFrame(false)// 是否可拖动裁剪框(固定)
     	.forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code     
    

    集成方式

    compile引入

    dependencies {
        implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.2.3'
    }
    

    build.gradle加入

    allprojects {
       repositories {
          jcenter()
          maven { url 'https://jitpack.io' }
       }
    }
    

    使用

    使用非常简单,你想要的基本上都有

    
    package com.yechaoa.pictureselectordemo;
    
    import android.Manifest;
    import android.annotation.SuppressLint;
    import android.content.Intent;
    import android.graphics.Color;
    import android.graphics.drawable.ColorDrawable;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.GridLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.view.Gravity;
    import android.view.View;
    import android.view.WindowManager;
    import android.widget.PopupWindow;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.luck.picture.lib.PictureSelector;
    import com.luck.picture.lib.config.PictureConfig;
    import com.luck.picture.lib.config.PictureMimeType;
    import com.luck.picture.lib.entity.LocalMedia;
    import com.luck.picture.lib.permissions.Permission;
    import com.luck.picture.lib.permissions.RxPermissions;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import io.reactivex.functions.Consumer;
    
    public class MainActivity extends AppCompatActivity {
    
        private int maxSelectNum = 9;
        private List<LocalMedia> selectList = new ArrayList<>();
        private GridImageAdapter adapter;
        private RecyclerView mRecyclerView;
        private PopupWindow pop;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mRecyclerView = findViewById(R.id.recycler);
    
            initWidget();
        }
    
        private void initWidget() {
            FullyGridLayoutManager manager = new FullyGridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false);
            mRecyclerView.setLayoutManager(manager);
            adapter = new GridImageAdapter(this, onAddPicClickListener);
            adapter.setList(selectList);
            adapter.setSelectMax(maxSelectNum);
            mRecyclerView.setAdapter(adapter);
            adapter.setOnItemClickListener(new GridImageAdapter.OnItemClickListener() {
                @Override
                public void onItemClick(int position, View v) {
                    if (selectList.size() > 0) {
                        LocalMedia media = selectList.get(position);
                        String pictureType = media.getPictureType();
                        int mediaType = PictureMimeType.pictureToVideo(pictureType);
                        switch (mediaType) {
                            case 1:
                                // 预览图片 可自定长按保存路径
                                //PictureSelector.create(MainActivity.this).externalPicturePreview(position, "/custom_file", selectList);
                                PictureSelector.create(MainActivity.this).externalPicturePreview(position, selectList);
                                break;
                            case 2:
                                // 预览视频
                                PictureSelector.create(MainActivity.this).externalPictureVideo(media.getPath());
                                break;
                            case 3:
                                // 预览音频
                                PictureSelector.create(MainActivity.this).externalPictureAudio(media.getPath());
                                break;
                        }
                    }
                }
            });
        }
    
        private GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() {
    
            @SuppressLint("CheckResult")
            @Override
            public void onAddPicClick() {
                //获取写的权限
                RxPermissions rxPermission = new RxPermissions(MainActivity.this);
                rxPermission.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                        .subscribe(new Consumer<Permission>() {
                            @Override
                            public void accept(Permission permission) {
                                if (permission.granted) {// 用户已经同意该权限
                                    //第一种方式,弹出选择和拍照的dialog
                                    showPop();
    
                                    //第二种方式,直接进入相册,但是 是有拍照得按钮的
    //                                showAlbum();
                                } else {
                                    Toast.makeText(MainActivity.this, "拒绝", Toast.LENGTH_SHORT).show();
                                }
                            }
                        });
            }
        };
    
        private void showAlbum() {
            //参数很多,根据需要添加
            PictureSelector.create(MainActivity.this)
                    .openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()
                    .maxSelectNum(maxSelectNum)// 最大图片选择数量
                    .minSelectNum(1)// 最小选择数量
                    .imageSpanCount(4)// 每行显示个数
                    .selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选PictureConfig.MULTIPLE : PictureConfig.SINGLE
                    .previewImage(true)// 是否可预览图片
                    .isCamera(true)// 是否显示拍照按钮
                    .isZoomAnim(true)// 图片列表点击 缩放效果 默认true
                    //.setOutputCameraPath("/CustomPath")// 自定义拍照保存路径
                    .enableCrop(true)// 是否裁剪
                    .compress(true)// 是否压缩
                    //.sizeMultiplier(0.5f)// glide 加载图片大小 0~1之间 如设置 .glideOverride()无效
                    .glideOverride(160, 160)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
                    .withAspectRatio(1, 1)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义
                    //.selectionMedia(selectList)// 是否传入已选图片
                    //.previewEggs(false)// 预览图片时 是否增强左右滑动图片体验(图片滑动一半即可看到上一张是否选中)
                    //.cropCompressQuality(90)// 裁剪压缩质量 默认100
                    //.compressMaxKB()//压缩最大值kb compressGrade()为Luban.CUSTOM_GEAR有效
                    //.compressWH() // 压缩宽高比 compressGrade()为Luban.CUSTOM_GEAR有效
                    //.cropWH()// 裁剪宽高比,设置如果大于图片本身宽高则无效
                    .rotateEnabled(false) // 裁剪是否可旋转图片
                    //.scaleEnabled()// 裁剪是否可放大缩小图片
                    //.recordVideoSecond()//录制视频秒数 默认60s
                    .forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code
        }
    
        private void showPop() {
            View bottomView = View.inflate(MainActivity.this, R.layout.layout_bottom_dialog, null);
            TextView mAlbum = bottomView.findViewById(R.id.tv_album);
            TextView mCamera = bottomView.findViewById(R.id.tv_camera);
            TextView mCancel = bottomView.findViewById(R.id.tv_cancel);
    
            pop = new PopupWindow(bottomView, -1, -2);
            pop.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
            pop.setOutsideTouchable(true);
            pop.setFocusable(true);
            WindowManager.LayoutParams lp = getWindow().getAttributes();
            lp.alpha = 0.5f;
            getWindow().setAttributes(lp);
            pop.setOnDismissListener(new PopupWindow.OnDismissListener() {
    
                @Override
                public void onDismiss() {
                    WindowManager.LayoutParams lp = getWindow().getAttributes();
                    lp.alpha = 1f;
                    getWindow().setAttributes(lp);
                }
            });
            pop.setAnimationStyle(R.style.main_menu_photo_anim);
            pop.showAtLocation(getWindow().getDecorView(), Gravity.BOTTOM, 0, 0);
    
            View.OnClickListener clickListener = new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    switch (view.getId()) {
                        case R.id.tv_album:
                            //相册
                            PictureSelector.create(MainActivity.this)
                                    .openGallery(PictureMimeType.ofImage())
                                    .maxSelectNum(maxSelectNum)
                                    .minSelectNum(1)
                                    .imageSpanCount(4)
                                    .selectionMode(PictureConfig.MULTIPLE)
                                    .forResult(PictureConfig.CHOOSE_REQUEST);
                            break;
                        case R.id.tv_camera:
                            //拍照
                            PictureSelector.create(MainActivity.this)
                                    .openCamera(PictureMimeType.ofImage())
                                    .forResult(PictureConfig.CHOOSE_REQUEST);
                            break;
                        case R.id.tv_cancel:
                            //取消
                            //closePopupWindow();
                            break;
                    }
                    closePopupWindow();
                }
            };
    
            mAlbum.setOnClickListener(clickListener);
            mCamera.setOnClickListener(clickListener);
            mCancel.setOnClickListener(clickListener);
        }
    
        public void closePopupWindow() {
            if (pop != null && pop.isShowing()) {
                pop.dismiss();
                pop = null;
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            List<LocalMedia> images;
            if (resultCode == RESULT_OK) {
                if (requestCode == PictureConfig.CHOOSE_REQUEST) {// 图片选择结果回调
    
                    images = PictureSelector.obtainMultipleResult(data);
                    selectList.addAll(images);
    
                    //selectList = PictureSelector.obtainMultipleResult(data);
    
                    // 例如 LocalMedia 里面返回三种path
                    // 1.media.getPath(); 为原图path
                    // 2.media.getCutPath();为裁剪后path,需判断media.isCut();是否为true
                    // 3.media.getCompressPath();为压缩后path,需判断media.isCompressed();是否为true
                    // 如果裁剪并压缩了,以取压缩路径为准,因为是先裁剪后压缩的
                    adapter.setList(selectList);
                    adapter.notifyDataSetChanged();
                }
            }
        }
    
    }
    
    
    

    Demo:https://github.com/yechaoa/PictureSelectorDemo


    展开全文
  • 主要介绍了Android实现图片选择以及图片上传的功能,有需要的朋友跟着学习下吧。
  • Android选择本地图片上传,本demo实现了从本地选择多张图片,但未实现上传部分代码
  • 最近要搞一个项目,需要上传相册和拍照的图片,不负所望,终于完成了! 不过需要说明一下,其实网上很多教程拍照的图片,都是缩略图不是很清晰,所以需要在调用照相机的时候,事先生成一个地址,用于标识拍照的图片...
  • Android webview打开相册选择图片并上传到服务器,(亲测可用)
  • Android图片上传,可以选择多张图片,缩放预览,拍照上传等
  • 1.Android手机客户端,拍照(或选择图片),然后上传到服务器。 2.服务器端接收手机端上传上来的图片。 二、实现步骤: 1.按惯例,先放效果图: 项目结构: 2.activity_main.xml <?xml version="1.0...

    作为一个Android新手,想实现手机拍照并上传的功能,经过查找资料,已实现此功能。在此记录备忘。老鸟请忽略。

    一、实现思路:

    1.Android手机客户端,拍照(或选择图片),然后上传到服务器。

    2.服务器端接收手机端上传上来的图片。

    二、实现步骤:

    1.按惯例,先放效果图:

    项目结构:

    2.activity_main.xml

    <?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="match_parent"
        android:orientation="vertical"
        android:padding="5dp">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="图片预览" />
    
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="400dp"
            android:background="#fff"
            android:padding="1dp"
            android:scaleType="fitXY" />
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:orientation="horizontal">
    
            <Button
                android:id="@+id/btnPhoto"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="拍照" />
    
            <Button
                android:id="@+id/btnSelect"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="选择" />
        </LinearLayout>
    </LinearLayout>

    3.MainActivity.java

    package com.qingshan.note;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.RequiresApi;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.app.ActivityCompat;
    import androidx.core.content.ContextCompat;
    
    import android.Manifest;
    import android.app.AlertDialog;
    import android.content.ContentValues;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Matrix;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Environment;
    import android.provider.MediaStore;
    import android.provider.Settings;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.Toast;
    
    import java.io.BufferedReader;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private Button btnPhoto, btnSelect;
        private Intent intent;
        private final int CAMERA = 1;//事件枚举(可以自定义)
        private final int CHOOSE = 2;//事件枚举(可以自定义)
        private final String postUrl = "http://qingshanboke.com/Home/AndoridUploadFile";//接收上传图片的地址
        String photoPath = "";//要上传的图片路径
        private final int permissionCode = 100;//权限请求码
    
        //权限集合,对应在AndroidManifest.xml文件中添加配置
        //    <uses-permission android:name="android.permission.CAMERA" />
        //    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        //    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        //    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
        //    <uses-permission android:name="android.permission.INTERNET"/>
        String[] permissions = new String[]{
                Manifest.permission.CAMERA,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.INTERNET
        };
        AlertDialog alertDialog;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //6.0才用动态权限
            if (Build.VERSION.SDK_INT >= 23) {
                checkPermission();
            }
    
            btnPhoto = findViewById(R.id.btnPhoto);
            btnSelect = findViewById(R.id.btnSelect);
            btnPhoto.setOnClickListener(this);
            btnSelect.setOnClickListener(this);
        }
    
        //检查权限
        private void checkPermission() {
            List<String> permissionList = new ArrayList<>();
            for (int i = 0; i < permissions.length; i++) {
                if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
                    permissionList.add(permissions[i]);
                }
            }
            if (permissionList.size() <= 0) {
                //说明权限都已经通过,可以做你想做的事情去
    
            } else {
                //存在未允许的权限
                ActivityCompat.requestPermissions(this, permissions, permissionCode);
            }
        }
    
        //授权后回调函数
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            boolean haspermission = false;
            if (permissionCode == requestCode) {
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults[i] == -1) {
                        haspermission = true;
                    }
                }
                if (haspermission) {
                    //跳转到系统设置权限页面,或者直接关闭页面,不让他继续访问
                    permissionDialog();
                } else {
                    //全部权限通过,可以进行下一步操作
                }
            }
        }
    
        //打开手动设置应用权限
        private void permissionDialog() {
            if (alertDialog == null) {
                alertDialog = new AlertDialog.Builder(this)
                        .setTitle("提示信息")
                        .setMessage("当前应用缺少必要权限,该功能暂时无法使用。如若需要,请单击【确定】按钮前往设置中心进行权限授权。")
                        .setPositiveButton("设置", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                cancelPermissionDialog();
                                Uri packageURI = Uri.parse("package:" + getPackageName());
                                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
                                startActivity(intent);
                            }
                        })
                        .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                cancelPermissionDialog();
                            }
                        })
                        .create();
            }
            alertDialog.show();
        }
    
        //用户取消授权
        private void cancelPermissionDialog() {
            alertDialog.cancel();
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
    
                //拍照按钮事件
                case R.id.btnPhoto:
                    //方法一:这样拍照只能取到缩略图(不清晰)
                    //intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                    //startActivityForResult(intent, CAMERA);
    
    
                    //方法二:指定加载路径图片路径(保存原图,清晰)
                    String SD_PATH = Environment.getExternalStorageDirectory().getPath() + "/拍照上传示例/";
                    SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
                    String fileName = format.format(new Date(System.currentTimeMillis())) + ".JPEG";
                    photoPath = SD_PATH + fileName;
                    File file = new File(photoPath);
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
    
                    //兼容7.0以上的版本
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        try {
                            ContentValues values = new ContentValues(1);
                            values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
                            values.put(MediaStore.Images.Media.DATA, photoPath);
                            Uri tempuri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                            if (tempuri != null) {
                                intent.putExtra(MediaStore.EXTRA_OUTPUT, tempuri);
                                intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
                            }
                            startActivityForResult(intent, CAMERA);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else {
                        intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        Uri uri = Uri.fromFile(file);
                        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); //指定拍照后的存储路径,保存原图
                        startActivityForResult(intent, CAMERA);
                    }
                    break;
    
                //选择按钮事件
                case R.id.btnSelect:
                    intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                    startActivityForResult(intent, CHOOSE);
                    break;
            }
        }
    
        @RequiresApi(api = Build.VERSION_CODES.O)
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            switch (requestCode) {
                // 调用照相机拍照
                case CAMERA:
                    if (resultCode == RESULT_OK) {
                        //对应方法一:图片未保存,需保存文件到本地
    //                    Bundle bundle = data.getExtras();
    //                    Bitmap bitmap = (Bitmap) bundle.get("data");
    //                    String savePath;
    //                    String SD_PATH = Environment.getExternalStorageDirectory().getPath() + "/拍照上传示例/";
    //                    SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
    //                    String fileName = format.format(new Date(System.currentTimeMillis())) + ".JPEG";
    //                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    //                        savePath = SD_PATH;
    //                    } else {
    //                        Toast.makeText(MainActivity.this, "保存失败!", Toast.LENGTH_SHORT).show();
    //                        return;
    //                    }
    //                    photoPath = savePath + fileName;
    //                    File file = new File(photoPath);
    //                    try {
    //                        if (!file.exists()) {
    //                            file.getParentFile().mkdirs();
    //                            file.createNewFile();
    //                        }
    //                        FileOutputStream stream = new FileOutputStream(file);
    //                        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    //                        Toast.makeText(MainActivity.this, "保存成功,位置:" + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
    //                    } catch (IOException e) {
    //                        e.printStackTrace();
    //                    }
    
                        //对应方法二:图片已保存,只需读取就行了
                        try {
                            FileInputStream stream = new FileInputStream(photoPath);
                            Bitmap bitmap = BitmapFactory.decodeStream(stream);
    
                            //预览图片
                            ImageView image = findViewById(R.id.imageView);
                            image.setImageBitmap(bitmap);
    
                            //上传图片(Android 4.0 之后不能在主线程中请求HTTP请求)
                            File file = new File(photoPath);
                            if (file.exists()) {
                                new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        //文本字段(用于验证用户身份)
                                        HashMap<String, String> form = new HashMap<String, String>();
                                        form.put("username", "zhangqs");
                                        form.put("password", "123456");
    
                                        //图片字段
                                        HashMap<String, String> file = new HashMap<String, String>();
                                        file.put(PathHelper.getFileNameFromPath(photoPath), photoPath);
                                        formUpload(postUrl, form, file);
                                    }
                                }).start();
                            }
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                // 选择图片库的图片
                case CHOOSE:
                    if (resultCode == RESULT_OK) {
                        try {
                            Uri uri = data.getData();
                            photoPath = PathHelper.getRealPathFromUri(MainActivity.this, uri);
                            Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
    
                            //压缩图片
                            bitmap = scaleBitmap(bitmap, (float) 0.5);
    
                            //预览图片
                            ImageView image = findViewById(R.id.imageView);
                            image.setImageBitmap(bitmap);
    
                            //上传图片(Android 4.0 之后不能在主线程中请求HTTP请求)
                            File file = new File(photoPath);
                            if (file.exists()) {
                                new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        //文本字段(用于验证用户身份)
                                        HashMap<String, String> form = new HashMap<String, String>();
                                        form.put("username", "zhangqs");
                                        form.put("password", "123456");
    
                                        //图片字段
                                        HashMap<String, String> file = new HashMap<String, String>();
                                        file.put(PathHelper.getFileNameFromPath(photoPath), photoPath);
                                        formUpload(postUrl, form, file);
                                    }
                                }).start();
                            }
    
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
            }
        }
    
        //压缩图片
        public Bitmap scaleBitmap(Bitmap origin, float ratio) {
            if (origin == null) {
                return null;
            }
            int width = origin.getWidth();
            int height = origin.getHeight();
            Matrix matrix = new Matrix();
            matrix.preScale(ratio, ratio);
            Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
            return newBM;
        }
    
        //POST 表单提交
        @RequiresApi(api = Build.VERSION_CODES.O)
        public static String formUpload(String posturl, Map<String, String> textMap, Map<String, String> fileMap) {
            String res = "";
            HttpURLConnection conn = null;
            String BOUNDARY = "---------------------------123821742118716"; //boundary就是request头和上传文件内容的分隔符
            try {
                URL url = new URL(posturl);
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(30000);
                conn.setDoOutput(true);
                conn.setDoInput(true);
                conn.setUseCaches(false);
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Connection", "Keep-Alive");
                conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
                conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
    
                OutputStream out = new DataOutputStream(conn.getOutputStream());
    
                // text
                if (textMap != null) {
                    StringBuffer buffer = new StringBuffer();
                    Iterator iter = textMap.entrySet().iterator();
                    while (iter.hasNext()) {
                        Map.Entry entry = (Map.Entry) iter.next();
                        String inputName = (String) entry.getKey();
                        String inputValue = (String) entry.getValue();
                        if (inputValue == null) {
                            continue;
                        }
                        buffer.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                        buffer.append("Content-Disposition: form-data; name=\"" + inputName + "\"\r\n\r\n");
                        buffer.append(inputValue);
                    }
                    out.write(buffer.toString().getBytes());
                }
    
                // file
                if (fileMap != null) {
                    Iterator iter = fileMap.entrySet().iterator();
                    while (iter.hasNext()) {
                        Map.Entry entry = (Map.Entry) iter.next();
                        String inputName = (String) entry.getKey();
                        String inputValue = (String) entry.getValue();
                        if (inputValue == null) {
                            continue;
                        }
                        File file = new File(inputValue);
                        String filename = file.getName();
                        String contentType = "";
                        if (filename.endsWith(".jpg")) {
                            contentType = "image/jpg";
                        } else if (filename.endsWith(".png")) {
                            contentType = "image/png";
                        } else if (contentType == null || contentType.equals("")) {
                            contentType = "application/octet-stream";
                        }
    
                        StringBuffer buffer = new StringBuffer();
                        buffer.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                        buffer.append("Content-Disposition: form-data; name=\"" + inputName + "\"; filename=\"" + filename + "\"\r\n");
                        buffer.append("Content-Type:" + contentType + "\r\n\r\n");
    
                        out.write(buffer.toString().getBytes());
    
                        DataInputStream in = new DataInputStream(new FileInputStream(file));
                        int bytes = 0;
                        byte[] bufferOut = new byte[1024];
                        while ((bytes = in.read(bufferOut)) != -1) {
                            out.write(bufferOut, 0, bytes);
                        }
                        in.close();
                    }
                }
    
                byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
                out.write(endData);
                out.flush();
                out.close();
    
                // 读取返回数据
                StringBuffer buffer = new StringBuffer();
                BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null) {
                    buffer.append(line).append("\n");
                }
                res = buffer.toString();
                reader.close();
                reader = null;
            } catch (Exception e) {
                System.out.println("发送POST请求出错。" + posturl);
                e.printStackTrace();
            } finally {
                if (conn != null) {
                    conn.disconnect();
                    conn = null;
                }
            }
            return res;
        }
    
    
    }
    

    4.辅助类 PathHelper.java

    package com.qingshan.note;
    
    import android.annotation.SuppressLint;
    import android.content.ContentUris;
    import android.content.Context;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Build;
    import android.provider.DocumentsContract;
    import android.provider.MediaStore;
    
    //Android 路径辅助类
    public class PathHelper {
    
        //适配api19以下(不包括api19),根据uri获取图片的绝对路径
        public static String getRealPathFromUri(Context context, Uri uri) {
            int sdkVersion = Build.VERSION.SDK_INT;
            if (sdkVersion >= 19) { // api >= 19
                return getRealPathFromUriAboveApi19(context, uri);
            } else { // api < 19
                return getRealPathFromUriBelowAPI19(context, uri);
            }
        }
    
        /**
         * 适配api19以下(不包括api19),根据uri获取图片的绝对路径
         *
         * @param context 上下文对象
         * @param uri     图片的Uri
         * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
         */
        private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
            return getDataColumn(context, uri, null, null);
        }
    
        /**
         * 适配api19及以上,根据uri获取图片的绝对路径
         *
         * @param context 上下文对象
         * @param uri     图片的Uri
         * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
         */
        @SuppressLint("NewApi")
        private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
            String filePath = null;
            if (DocumentsContract.isDocumentUri(context, uri)) {
                // 如果是document类型的 uri, 则通过document id来进行处理
                String documentId = DocumentsContract.getDocumentId(uri);
                if (isMediaDocument(uri)) { // MediaProvider
                    // 使用':'分割
                    String id = documentId.split(":")[1];
                    String selection = MediaStore.Images.Media._ID + "=?";
                    String[] selectionArgs = {id};
                    filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);
                } else if (isDownloadsDocument(uri)) { // DownloadsProvider
                    Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
                    filePath = getDataColumn(context, contentUri, null, null);
                }
            } else if ("content".equalsIgnoreCase(uri.getScheme())) {
                // 如果是 content 类型的 Uri
                filePath = getDataColumn(context, uri, null, null);
            } else if ("file".equals(uri.getScheme())) {
                // 如果是 file 类型的 Uri,直接获取图片对应的路径
                filePath = uri.getPath();
            }
            return filePath;
        }
    
        private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
            String path = null;
            String[] projection = new String[]{MediaStore.Images.Media.DATA};
            Cursor cursor = null;
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
                if (cursor != null && cursor.moveToFirst()) {
                    int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                    path = cursor.getString(columnIndex);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
            return path;
        }
    
        private static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
        private static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        //从路径中提取文件名
        public static String getFileNameFromPath(String path) {
            int start = path.lastIndexOf("/");
            int end = path.lastIndexOf(".");
            if (start != -1 && end != -1) {
                return path.substring(start + 1, end);
            } else {
                return null;
            }
    
        }
    }
    

    5.AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.qingshan.note">
    
        <!-- 因为拍照需要写入文件 所以需要申请读取内存的权限 -->
        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
        <uses-permission android:name="android.permission.INTERNET"/>
    
        <application
            android:networkSecurityConfig="@xml/network_security_config"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:usesCleartextTraffic="true"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

    6.\res\xml\network_security_config.xml

    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <base-config cleartextTrafficPermitted="true"  />
        <domain-config cleartextTrafficPermitted="true" >
            <domain includeSubdomains="true">127.0.0.1</domain>
            <domain includeSubdomains="true">192.168.100.192</domain>
            <domain includeSubdomains="true">localhost</domain>
            <domain includeSubdomains="true">qingshanboke.com</domain>
        </domain-config>
    </network-security-config>

    7.服务器端接收(asp.net mvc 接收)

            public ActionResult AndoridUploadFile()
            {
                var userName = Request.Params["username"];
                var password = Request.Params["password"];
                if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
                {
                    return Content("抱歉,用户名和密码错误!");
                }
                //todo:身份验证
    
                var dir = PathHelper.GetMapPath("~/Uploadfiles/" + DateTime.Now.ToString("yyyy-MM"));
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                for (int i = 0; i < Request.Files.Count; i++)
                {
                    var path = Path.Combine(dir, DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg");
                    if (Request.Files[i] != null)
                    {
                        Request.Files[i].SaveAs(path);
                    }
                }
                return Content("{\"isSuccess\":true}");
            }

    三、注意事项

    1.Android发起http请求时,默认请求地址需https,需要增加 network-security-config 配置来允许使用http。(详见上面6.\res\xml\network_security_config.xml)

    2.发起post提交时,往往需要做接口身份识别,需要将文本字段和图片字段一起提交,构造表单时,需要 "Content-Type", "multipart/form-data; boundary..."。

    3.拍照时,默认只能取到缩略图,不够清晰,若要取到原图,需要在拍照时,传入指定保存位置,在回调函数中只需读取就可以了。

    展开全文
  • 本篇文章主要介绍了Android设置拍照或者上传本地图片示例,可以拍照或者上传本地文件,有需要的可以了解一下。
  • 仿微信图片选择器,实现多张图片上传
  • 利用GridView实现图片批量上传服务器的功能,demo下载下来直接可以运行。其中存在一个bug,bug解决方案请看博客:http://www.cnblogs.com/1925yiyi/p/7419021.html
  • Android图片选择上传(ImagePicker)

    千次阅读 2018-11-26 14:28:48
    使用前,对于Android Studio的用户,可以选择添加: compile 'com.lzy.widget:imagepicker:0.6.1' //指定版本 2.具体使用  1.首先你需要继承 com.lzy.imagepicker.loader.ImageLoader 这个接口,实现其中的方法,...

    1.用法

    使用前,对于Android Studio的用户,可以选择添加:

    compile 'com.lzy.widget:imagepicker:0.6.1'  //指定版本

    2.具体使用

      1.首先你需要继承 com.lzy.imagepicker.loader.ImageLoader 这个接口,实现其中的方法,比如以下代码是使用Glide第三方加载库实现的

    public class GlideImageLoader implements ImageLoader {
    
        @Override
        public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) {
            /*Picasso.with(activity)                            //配置上下文
                    .load(Uri.fromFile(new File(path)))      //设置图片路径(fix #8,文件名包含%符号 无法识别和显示)
                    .error(R.drawable.bg_stack_blur_default)           //设置错误图片
                    .placeholder(R.drawable.bg_stack_blur_default)     //设置占位图片
                    .into(imageView);*/
    
            Glide.with(activity)                             //配置上下文
                    .load(Uri.fromFile(new File(path)))      //设置图片路径(fix #8,文件名包含%符号 无法识别和显示)
                    .error(R.mipmap.default_image)           //设置错误图片
                    .placeholder(R.mipmap.default_image)     //设置占位图片
                    .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存全尺寸
                    .into(imageView);
        }
    
    //在这里注意用glide加载图片的话一定要在下面这个方法 里面也配置上,否者会出现预览图片还有不显示图片
    @Override
    public void displayImagePreview(Activity activity, String path, ImageView imageView, int width, int height) {
        Glide.with(activity)                             //配置上下文
                .load(Uri.fromFile(new File(path)))      //设置图片路径(fix #8,文件名包含%符号 无法识别和显示)
                .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存全尺寸
                .into(imageView);
    }
    
    
        @Override
        public void clearMemoryCache() {}
        //这里是清除缓存的方法,根据需要自己实现
    }

       2.然后配置图片选择器,一般在Application初始化配置一次就可以,这里就需要将上面的图片加载器设置进来,其余的配置根据需要设置

    /**
         * 初始化图片选择器
         */
        private void initImagePicker() {
            ImagePicker imagePicker = ImagePicker.getInstance();
            imagePicker.setImageLoader(new GlideImageLoader());   //设置图片加载器
            imagePicker.setShowCamera(true);                      //显示拍照按钮
            imagePicker.setCrop(false);                            //允许裁剪(单选才有效)
            imagePicker.setSaveRectangle(true);                   //是否按矩形区域保存
            imagePicker.setSelectLimit(maxImgCount);              //选中数量限制
            imagePicker.setStyle(CropImageView.Style.RECTANGLE);  //裁剪框的形状
            imagePicker.setFocusWidth(800);                       //裁剪框的宽度。单位像素(圆形自动取宽高最小值)
            imagePicker.setFocusHeight(800);                      //裁剪框的高度。单位像素(圆形自动取宽高最小值)
            imagePicker.setOutPutX(1000);                         //保存文件的宽度。单位像素
            imagePicker.setOutPutY(1000);                         //保存文件的高度。单位像素
        }

       3.以上配置完成后,在适当的方法中开启相册,例如点击按钮时

    /**
         * 插入图片,打开图片选择器
         */
        private void insertPhoto() {
            ImagePicker.getInstance().setSelectLimit(maxImgCount);
            Intent intent = new Intent(NotePadNewActivity.this, ImageGridActivity.class);
            startActivityForResult(intent, 100);
        }

       4.如果你想直接调用相机

    Intent intent = new Intent(this, ImageGridActivity.class);
    intent.putExtra(ImageGridActivity.EXTRAS_TAKE_PICKERS,true); // 是否是直接打开相机
    startActivityForResult(intent, REQUEST_CODE_SELECT);

        5.重写onActivityResult方法,回调结果

    private ArrayList<ImageItem> selImageList; //当前选择的所有图片
    private int maxImgCount = 9;               //允许选择图片最大数
    
    //适当地方初始化
            selImageList = new ArrayList<>();
    
    @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == ImagePicker.RESULT_CODE_ITEMS) {
                //添加图片返回
                if (data != null && requestCode == 100) {
                    ArrayList<ImageItem> images = (ArrayList<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS);
                    if (images != null) {
                        selImageList.addAll(images);
                        adapter.setImages(selImageList);
                        for (int i = 0; i < selImageList.size(); i++) {
                            Log.d("图片地址=", selImageList.get(i).path);
                            Toast.makeText(getApplicationContext(), "图片地址=" + selImageList.get(i).path, Toast.LENGTH_SHORT).show();
                        }
                    }
                }
            } else if (resultCode == ImagePicker.RESULT_CODE_BACK) {
                //预览图片返回
                if (data != null && requestCode == REQUEST_CODE_PREVIEW) {
                    ArrayList<ImageItem> images = (ArrayList<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_IMAGE_ITEMS);
                    if (images != null) {
                        selImageList.clear();
                        selImageList.addAll(images);
                        adapter.setImages(selImageList);
                    }
                }
            }
    

     

     

     

     

     

     

     

     

    展开全文
  • Android图片上传

    2016-11-18 11:10:11
    Android图片上传
  • 使用HttpClient/HttpURLConection + Tomcat + JSP 页面技术实现/Struct2实现android图片上传功能
  • Android 选择图片上传图片之Matisse

    千次阅读 2018-02-09 12:26:50
    选择图片再次选择不能带过去 剪裁 压缩 权限 Glide版本过低 但是,也是有特点的 MD风格 白天模式和夜间模式 其他与同类相比也真的没什么了,唯一背书 就是知乎团队出的呗。。 相比之下,昨天...

    效果图:
    这里写图片描述这里写图片描述这里写图片描述这里写图片描述

    就目前效果图来看,好像也没什么毛病哈,其实我这个集成的过程是有点坎坷的。
    而且,功能也不算是很齐全吧…主要体现在以下几个点

    • 没有回调之后的预览
    • 选择之后不能删除已选
    • 已选择的图片再次选择不能带过去
    • 剪裁
    • 压缩
    • 权限
    • Glide版本过低

    但是,也是有特点的

    • MD风格
    • 白天模式和夜间模式

    其他与同类相比也真的没什么了,唯一背书 就是知乎团队出的呗。。
    相比之下,昨天出的Android 选择图片、上传图片之PictureSelector就更加友好和人性化了。

    下面来说说集成遇到的问题以及解决方案。

    gayhub:https://github.com/zhihu/Matisse

    集成

    Gradle:

    repositories {
        jcenter()
    }
    
    dependencies {
        compile 'com.zhihu.android:matisse:0.4.3'
    }

    releases最新是v0.5.0-beta3的,本文还是基于官方文档0.4.3的版本

    你以为这样就可以使用了吗,nonono,权限需要动态获取,你还需要RxPermissions或者其他权限库,或者自己封装

    compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar'

    这就完了吗,no,你还需要rxjava

    compile "io.reactivex.rxjava2:rxjava:2.1.9"

    现在总可以了吧,依然nonono,如果你项目集成了Glide,还是会报错,我在用的Glide版本是4.6.1的,Matisse中集成的是3.7.0的,是有区别的,具体你可以看这里 带你全面了解Glide 4的用法,你也可以用Picasso

    会报异常

    java.lang.NoSuchMethodError: com.bumptech.glide.RequestManager.load

    解决方案就是重新自定义图片加载方式GlideEngine,具体可以看这里Matisse 与 Glide – java.lang.NoSuchMethodError: com.bumptech.glide.RequestManager.load

    到这里你以为就ok了吗,还是nonono,还是会报异常,因为两个版本会冲突啊

    java.lang.NoClassDefFoundError: android.support.v4.animation.AnimatorCompatHelper

    解决方案看这里java.lang.NoClassDefFoundError: android.support.v4.animation.AnimatorCompatHelper

    Matisse:爱我你怕了吗

    终于可以使用了,哇的哭出声

    使用

    你以为集成都这么坎坷了,使用应该很方便吧,no啊大胸弟,
    虽然集成之前我看到150+的Issues有点头皮发麻,果然没让我失望,坎坷的路还长着呢。

    最快的方式集成第三方有两种,1.看官方文档,2.看例子。

    你以为从sample中copy copy代码,导下包就能跑起来了吗,nonono

    选择器不光是有图片的吧,你可能还有gif和视频啊,所以在配置的时候你要选择一个type啊

    sample是这样的

    Matisse.from(SampleActivity.this)
        .choose(MimeType.ofAll(), false)
        ...

    源码实际上是这样的

     public SelectionSpecBuilder choose(Set<MimeType> mimeType) {
            return new SelectionSpecBuilder(this, mimeType);
        }

    所以,你的应该是这样的

    Matisse.from(MainActivity.this)
        .choose(MimeType.allOf())
        ...

    没有boolean类型参数,而且也不是ofAll了,而是allOf

    上面是把所有的都列出来,那我如果只选图片怎么办呢

    sample是这样的

    Matisse.from(SampleActivity.this)
        .choose(MimeType.ofImage())
        ...

    尼玛。。实际上MimeType这个枚举类中根本就没有ofImage

    所以你的应该是这样的

    Matisse.from(MainActivity.this)
        .choose(MimeType.of(MimeType.JPEG))
        ...

    所以,刺不刺激?

    对了,你如果要用最新版本,比如v0.5.0-beta3,注意去掉前面的v。

    然后,你可以跑起来了,也不会报错了,仿佛一切都ok的样子(翻译一下:其实并没有,逃..)

    遇到几个点还没有解决,也懒得深入研究了,我要回家过年,哼

    1. 拍照还是选择相册,没有处理
    2. 预览,选择图片的时候可以预览,但是回调之后并不行,没有处理
    3. onActivityResult回调之后的图片不能直接删除,没有处理
    4. 剪裁,没有处理
    5. 压缩,没有处理
    6. 哦对了,如果可以预览了,那还得可以保存图片呢,也没有处理,因为预览没有处理,哈哈哈嗝
    7. 已选择的图片,再次选择的时候带过去,没有处理

    那有人就会说了,这么多没有的功能,或者文档没有介绍到的,不是可以自己去处理吗,这样岂不是定制化更高?比如筛选条件、主题…
    emmm…
    你说的对,但我不认同。哈哈哈

    哦对了,选择图片的时候可以预览,看一下是什么样的
    这里写图片描述

    啊。。scaleType不对就不说了,可是你让我的toolbar兄弟如何自处?又要挨window爸爸的打了。。

    哦对了,0.5的版本加了新功能,但是正式版还没有发布

    这里写图片描述

    最后,不要忘了加权限和FileProvider。
    然后贴一下MainActivity的代码和gayhub的地址

    package com.yechaoa.matissedemo;
    
    import android.Manifest;
    import android.content.Intent;
    import android.content.pm.ActivityInfo;
    import android.net.Uri;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.GridLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.Toast;
    
    import com.bumptech.glide.Glide;
    import com.tbruyelle.rxpermissions2.RxPermissions;
    import com.zhihu.matisse.Matisse;
    import com.zhihu.matisse.MimeType;
    import com.zhihu.matisse.internal.entity.CaptureStrategy;
    
    import java.util.List;
    
    import io.reactivex.Observer;
    import io.reactivex.disposables.Disposable;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        private UriAdapter mAdapter;
        private static final int REQUEST_CODE_CHOOSE = 23;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            findViewById(R.id.zhihu).setOnClickListener(this);
            findViewById(R.id.dracula).setOnClickListener(this);
    
            RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
            recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
            recyclerView.setAdapter(mAdapter = new UriAdapter());
        }
    
        /**
         * 1 预览  2 已选择带过去  3 剪裁  4 压缩
         * <p>
         * 120 显示三列  100显示四列
         */
    
        @Override
        public void onClick(final View v) {
            RxPermissions rxPermissions = new RxPermissions(MainActivity.this);
            rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    .subscribe(new Observer<Boolean>() {
                        @Override
                        public void onSubscribe(Disposable d) {
    
                        }
    
                        @Override
                        public void onNext(Boolean aBoolean) {
                            if (aBoolean) {
                                switch (v.getId()) {
                                    case R.id.zhihu:
                                        Matisse.from(MainActivity.this)
                                                .choose(MimeType.allOf())//ofAll()
                                                .theme(R.style.Matisse_Zhihu)//主题,夜间模式R.style.Matisse_Dracula
                                                .countable(true)//是否显示选中数字
                                                .capture(true)//是否提供拍照功能
                                                .captureStrategy(new CaptureStrategy(true, "com.zhihu.matisse.sample.fileprovider"))//存储地址
                                                .maxSelectable(9)//最大选择数
                                                //.addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))//筛选条件
                                                .gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size))//图片大小
                                                .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)//屏幕方向
                                                .thumbnailScale(0.85f)//缩放比例
                                                .imageEngine(new MyGlideEngine())//图片加载方式
                                                .forResult(REQUEST_CODE_CHOOSE);//请求码
                                        break;
                                    case R.id.dracula:
                                        Matisse.from(MainActivity.this)
                                                .choose(MimeType.of(MimeType.JPEG))//ofImage()
                                                .theme(R.style.Matisse_Dracula)
                                                .countable(false)
                                                .maxSelectable(9)
                                                .imageEngine(new MyGlideEngine())
                                                .forResult(REQUEST_CODE_CHOOSE);
                                        break;
                                }
                                mAdapter.setData(null);
                            } else {
                                Toast.makeText(MainActivity.this, "权限被拒绝了..", Toast.LENGTH_LONG).show();
                            }
                        }
    
                        @Override
                        public void onError(Throwable e) {
    
                        }
    
                        @Override
                        public void onComplete() {
    
                        }
                    });
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == REQUEST_CODE_CHOOSE && resultCode == RESULT_OK) {
                mAdapter.setData(Matisse.obtainResult(data));
            }
        }
    
        private class UriAdapter extends RecyclerView.Adapter<UriAdapter.UriViewHolder> {
    
            private List<Uri> mUris;
    
            void setData(List<Uri> uris) {
                mUris = uris;
                notifyDataSetChanged();
            }
    
            @Override
            public UriViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                return new UriViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.uri_item, parent, false));
            }
    
            @Override
            public void onBindViewHolder(UriViewHolder holder, int position) {
                Glide.with(MainActivity.this).load(mUris.get(position)).into(holder.mImg);
            }
    
            @Override
            public int getItemCount() {
                return mUris == null ? 0 : mUris.size();
            }
    
            class UriViewHolder extends RecyclerView.ViewHolder {
    
                private ImageView mImg;
    
                UriViewHolder(View contentView) {
                    super(contentView);
                    mImg = (ImageView) contentView.findViewById(R.id.img);
                }
            }
        }
    
    }
    

    gayhub:https://github.com/yechaoa/MatisseDemo

    展开全文
  • Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等 - 享受技术带来的快乐! - 博客频道 - CSDN.NET_files
  • 本篇文章主要介绍了Android中Okhttp3实现上传多张图片同时传递参数 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • android项目的时候总免不了遇到图片上传
  • android关于选取本地图片,返回路径不同,不正确问题;调用相机返回压缩图片的解决方法;图片压缩上传
  • 人生的磨难是很多的,所以我们不可对于每一件轻微的伤害都过于敏感。在生活磨难面前,精神上的坚强和无动于衷是我们抵抗罪恶和人生意外的最好武器。...红色箭头1表示对要上传图片做本地和网络的删除。 ...
  • webView选择图片并上传

    千次下载 热门讨论 2013-08-19 16:19:46
    android 使用webView选择图片并上传,相关联的服务器代码地址:http://download.csdn.net/detail/vipa1888/5975311
  • Android 选择图片上传图片之ImagePicker

    万次阅读 热门讨论 2017-04-28 18:12:46
    效果图:后来又出了两篇,也可以看一下Android 选择图片上传图片之PictureSelectorAndroid 选择图片上传图片之Matisse添加依赖:选择图片:compile 'com.lzy.widget:imagepicker:0.5.4'github地址:...
  • android简单的选择图片上传到服务端,保存到本地
  • Android图片上传服务器端,支持多文件上传。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 63,015
精华内容 25,206
关键字:

android选择图片并上传