一、权限问题

  1. 可能会遇到的问题

requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
Permission Denial: reading com.android.providers.media.MediaProvider
  1. 添加权限

首先在AndroidManifest.xml根节点下添加下面的权限,主要是访问网络、相机、读写权限。

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  1. 动态请求许可

再andorid新版本里面,上面申请了权限之后,还是需要动态在申请权限,所以再需要用到的界面的onCreate方法里面添加如下代码,进行申请。

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {requestPermissions(new String[] {Manifest.permission.CAMERA}, 1);}}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {requestPermissions(new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, 1);}}

二、调用相机

  1. 声明provider

首先,我们需要在主配置文件中声明provider,与activity同级别。之所以要用到provider,是因为从Android7.0开始,就不允许在 App 间,使用 file:// 的方式,传递一个 File ,否则就会抛出异常,而provider的作用恰好就是用过 content://的模式替换掉 file://,看上去只是换了个前缀,但其实是有真实路径转为了虚拟路径。

<providerandroid:authorities="com.example.yourpackage.provider"android:name="androidx.core.content.FileProvider"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths"/></provider>

file_paths的内容

<paths><external-pathname = "photo"path = "/"/>
</paths>
  1. 调用相机

首先创建一个文件,用于保存拍照图像,然后根据不同系统版本获取Uri,传递给Intent,然后调起相机(可以考虑将outputImage、imageUri设置为全局变量)。

int REQUEST_CODE = 1;  //事件请求CODE为1
outputImage = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES),"last.jpg");
if (outputImage.exists())outputImage.delete();try {outputImage.createNewFile();} catch (IOException e) {e.printStackTrace();}
//注意com.example.yourpackage.provider要和provider声明中的一致
imageUri = (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) ? FileProvider.getUriForFile(context,"com.example.yourpackage.provider",outputImage) : Uri.fromFile(outputImage);
Intent intent1 = new Intent("android.media.action.IMAGE_CAPTURE");
intent1.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent1,REQUEST_CODE);
  1. 处理回调

使用BitmapFactory读取imageUri,得到bitmap,然后进行一些压缩,然后显示。

if (resultCode == Activity.RESULT_OK) {ContentResolver contentResolver = getContentResolver();Bitmap bitmap = null;try {bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(imageUri));Log.i("TAG", "从相册回传bitmap:"+bitmap.getWidth());Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap,  bitmap.getWidth()/10 ,bitmap.getHeight()/10, true);img_imgview.setImageBitmap(bitmap2);this.flag = 1;} catch (FileNotFoundException e) {e.printStackTrace();}
}
  1. 获取图像绝对路径

我们使用outputImage,来获取绝对路径,用于上传或者其它操作。

outputImage.getAbsolutePath()

三、调用相册

  1. 调用相册

nt REQUEST_CODE = 2;
Intent intent1 = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent1.addCategory(Intent.CATEGORY_OPENABLE);
intent1.setType("image/*");
startActivityForResult(intent1,REQUEST_CODE);
  1. 处理回调

if (resultCode == Activity.RESULT_OK && data != null) {if (data.getData()!=null) {ContentResolver contentResolver = getContentResolver();Bitmap bitmap = null;try {imageUri = data.getData();bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(data.getData()));Log.i("TAG", "从相册回传bitmap:"+bitmap.getWidth());Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap,  bitmap.getWidth()/10 ,bitmap.getHeight()/10, true);img_imgview.setImageBitmap(bitmap2);this.flag = 2;} catch (FileNotFoundException e) {e.printStackTrace();}}
}
  1. 获取图像绝对路径

这里就要麻烦很多,详细方法见四

FileHelper.getFileAbsolutePath(context, imageUri)

四、从Uri获取文件绝对路径

这是一个完整的帮助类,可以基于Uri获取绝对路径。

public class FileHelper {/*** 根据Uri获取文件绝对路径,解决Android4.4以上版本Uri转换** @param context* @param imageUri*/public static String getFileAbsolutePath(Context context, Uri imageUri) {if (context == null || imageUri == null) {return null;}if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {return getRealFilePath(context, imageUri);}if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && DocumentsContract.isDocumentUri(context, imageUri)) {if (isExternalStorageDocument(imageUri)) {String docId = DocumentsContract.getDocumentId(imageUri);String[] split = docId.split(":");String type = split[0];if ("primary".equalsIgnoreCase(type)) {return Environment.getExternalStorageDirectory() + "/" + split[1];}} else if (isDownloadsDocument(imageUri)) {String id = DocumentsContract.getDocumentId(imageUri);Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));return getDataColumn(context, contentUri, null, null);} else if (isMediaDocument(imageUri)) {String docId = DocumentsContract.getDocumentId(imageUri);String[] split = docId.split(":");String type = split[0];Uri contentUri = null;if ("image".equals(type)) {contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;} else if ("video".equals(type)) {contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;} else if ("audio".equals(type)) {contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;}String selection = MediaStore.Images.Media._ID + "=?";String[] selectionArgs = new String[]{split[1]};return getDataColumn(context, contentUri, selection, selectionArgs);}} // MediaStore (and general)if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){return uriToFileApiQ(context,imageUri);}else if ("content".equalsIgnoreCase(imageUri.getScheme())) {// Return the remote addressif (isGooglePhotosUri(imageUri)) {return imageUri.getLastPathSegment();}return getDataColumn(context, imageUri, null, null);}// Fileelse if ("file".equalsIgnoreCase(imageUri.getScheme())) {return imageUri.getPath();}return null;}//此方法 只能用于4.4以下的版本private static String getRealFilePath(final Context context, final Uri uri) {if (null == uri) {return null;}final String scheme = uri.getScheme();String data = null;if (scheme == null) {data = uri.getPath();} else if (ContentResolver.SCHEME_FILE.equals(scheme)) {data = uri.getPath();} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {String[] projection = {MediaStore.Images.ImageColumns.DATA};Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);//            Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);if (null != cursor) {if (cursor.moveToFirst()) {int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);if (index > -1) {data = cursor.getString(index);}}cursor.close();}}return data;}/*** @param uri The Uri to check.* @return Whether the Uri authority is ExternalStorageProvider.*/private static boolean isExternalStorageDocument(Uri uri) {return "com.android.externalstorage.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is DownloadsProvider.*/private static boolean isDownloadsDocument(Uri uri) {return "com.android.providers.downloads.documents".equals(uri.getAuthority());}private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {Cursor cursor = null;String column = MediaStore.Images.Media.DATA;String[] projection = {column};try {cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);if (cursor != null && cursor.moveToFirst()) {int index = cursor.getColumnIndexOrThrow(column);return cursor.getString(index);}} finally {if (cursor != null) {cursor.close();}}return null;}/*** @param uri The Uri to check.* @return Whether the Uri authority is MediaProvider.*/private static boolean isMediaDocument(Uri uri) {return "com.android.providers.media.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is Google Photos.*/private static boolean isGooglePhotosUri(Uri uri) {return "com.google.android.apps.photos.content".equals(uri.getAuthority());}/*** Android 10 以上适配 另一种写法* @param context* @param uri* @return*/public static String getFileFromContentUri(Context context, Uri uri) {if (uri == null) {return null;}String filePath;String[] filePathColumn = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DISPLAY_NAME};ContentResolver contentResolver = context.getContentResolver();Cursor cursor = contentResolver.query(uri, filePathColumn, null,null, null);if (cursor != null) {cursor.moveToFirst();try {filePath = cursor.getString(cursor.getColumnIndex(filePathColumn[0]));return filePath;} catch (Exception e) {} finally {cursor.close();}}return "";}/*** Android 10 以上适配* @param context* @param uri* @return*/@RequiresApi(api = Build.VERSION_CODES.Q)private static String uriToFileApiQ(Context context, Uri uri) {File file = null;//android10以上转换if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {file = new File(uri.getPath());} else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {//把文件复制到沙盒目录ContentResolver contentResolver = context.getContentResolver();Cursor cursor = contentResolver.query(uri, null, null, null, null);if (cursor.moveToFirst()) {String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));try {InputStream is = contentResolver.openInputStream(uri);File cache = new File(context.getExternalCacheDir().getAbsolutePath(), Math.round((Math.random() + 1) * 1000) + displayName);FileOutputStream fos = new FileOutputStream(cache);FileUtils.copy(is, fos);file = cache;fos.close();is.close();} catch (IOException e) {e.printStackTrace();}}}return file.getAbsolutePath();}
}

五、http请求并上传

  1. 通过okhttp调用接口

修改模块的build.gradle 增加下面一行依赖配置

implementation 'com.squareup.okhttp3:okhttp:4.9.1
  1. Get请求

OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象
// 创建一个GET方式的请求结构
xRequest request = new Request.Builder()//.get() // 因为OkHttp默认采用get方式,所以这里可以不调get方法.header("Accept-Language", "zh-CN") // 给http请求添加头部信息.url("http://192.168.1.104:5291/myApi/GetList") // 指定http请求的调用地址.build();
Call call = client.newCall(request); // 根据请求结构创建调用对象
// 加入HTTP请求队列。异步调用,并设置接口应答的回调方法
call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) { // 请求失败// 回到主线程操纵界面runOnUiThread(() -> {Toast toast= Toast.makeText(context, "默认失败的Toast" + e.getMessage().toString(), Toast.LENGTH_SHORT);toast.show();});}@Overridepublic void onResponse(Call call, final Response response) throws IOException { // 请求成功String resp = response.body().string();// 回到主线程操纵界面runOnUiThread(() -> {Toast toast= Toast.makeText(context, "默认成功的的Toast" + resp, Toast.LENGTH_SHORT);toast.show();});}
});
  1. Post from表单上传文件和数据

//文件
File file = new File(picUrl);
//请求体
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
//数据1
builder.addFormDataPart("date", date);
//数据2
builder.addFormDataPart("banzu", banzu);
//文件,注意名称,这里是files,后台需要用这个名字接数据
builder.addFormDataPart("files", file.getName(), RequestBody.create(MediaType.parse("image/jpeg"), file));
MultipartBody body = builder.build();// 创建一个okhttp客户端对象,设置超时
OkHttpClient client = new OkHttpClient().newBuilder().connectTimeout(30, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).build();// 创建一个POST方式的请求结构
Request request = new Request.Builder().post(body).url("http://192.168.1.100:5290/upLoadFile").build();
Call call = client.newCall(request); // 根据请求结构创建调用对象
// 加入HTTP请求队列。异步调用,并设置接口应答的回调方法
call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) { // 请求失败// 回到主线程操纵界面runOnUiThread(() -> {Toast toast= Toast.makeText(context, "默认失败的Toast" + e.getMessage().toString(), Toast.LENGTH_SHORT);toast.show();//关闭loadingdialog.dismiss();});}@Overridepublic void onResponse(Call call, final Response response) throws IOException { // 请求成功String resp = response.body().string();// 回到主线程操纵界面runOnUiThread(() -> {Toast toast= Toast.makeText(context, "默认成功的Toast", Toast.LENGTH_SHORT);toast.show();//关闭loadingdialog.dismiss();});}
});
  1. Post Json数据

private void postJson() {String username = et_username.getText().toString();String password = et_password.getText().toString();String jsonString = "";try {JSONObject jsonObject = new JSONObject();jsonObject.put("username", username);jsonObject.put("password", password);jsonString = jsonObject.toString();} catch (Exception e) {e.printStackTrace();}// 创建一个POST方式的请求结构RequestBody body = RequestBody.create(jsonString, MediaType.parse("text/plain;charset=utf-8"));OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象Request request = new Request.Builder().post(body).url(URL_LOGIN).build();Call call = client.newCall(request); // 根据请求结构创建调用对象// 加入HTTP请求队列。异步调用,并设置接口应答的回调方法call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) { // 请求失败// 回到主线程操纵界面runOnUiThread(() -> tv_result.setText("调用登录接口报错:"+e.getMessage()));}@Overridepublic void onResponse(Call call, final Response response) throws IOException { // 请求成功.setText("调用登录接口返回:\n"+resp));}});}

六、参考代码下载

https://download.csdn.net/download/bashendixie5/87823865

Android开发 8.0及以上调用相机/相册,并根据Uri获取图像绝对路径,并进行文件上传相关推荐

  1. 学习日志day41(2021-09-03)(1、文件的上传 2、文件的查看 3、文件的下载 4、使用工具类上传文件 5、基于servlet3.0以上的文件上传 )

    学习内容:学习JavaWeb(Day41) 1.文件的上传 2.文件的查看 3.文件的下载 4.使用工具类上传文件 5.基于servlet3.0以上的文件上传 1.文件的上传 (1)实现文件的上传需要 ...

  2. Android 8.0+调用相机相册

    写在前面 近期项目的需求是需要去调用相机相册去拍照获取图片保存到服务器 公司的测试机试Android6.0以下的 所以之前调用相机一点都没问题 可是跑在Android8.0+的手机上 调用相机相册就会 ...

  3. 安卓系统android使用C# .NET Xamarin框架调用相机拍照

    安卓系统android使用C# .NET Xamarin框架调用相机拍照 引言 一.用到的软件.包 二.创建Android应用(Xamarin), 三.增加Nuget中库Xam.Plugin.Medi ...

  4. Struts2.0第三章(文件上传、ajax开发、json、Fastjson、Jackson、注解开发)

    Struts2.0文件上传: 浏览器端注意事项: 1.表单提交方式method = post: 2.表单中必须有一个<input type="file" name = &qu ...

  5. uniapp中调用相机相册/上传/扫码整理

    调用相机相册 uni.chooseImage({count: 1,sizeType: ['original', 'compressed'],sourceType: ['camera','album'] ...

  6. Android Retrofit 2.0文件上传

    Android Retrofit 实现(图文上传)文字(参数)和多张图片一起上传 使用Retrofit进行文件上传,肯定离不开Part & PartMap. public interface ...

  7. android文件上传413 nginx [error] 9679#0: *318855 client intended to send too large body: 1593409 bytes

    问题描述: android 图片文件上传服务器返回 413 ios 上传正常 排查: # whereis nginx # vi /etc/nginx/nginx.conf 查看日志存放地址 # cat ...

  8. Android-史上最优雅的实现文件上传、下载及进度的监听,android自定义控件开发入门与实战

    注:如果需要对Http的返回值做解析,可在使用uploadProgress操作符时,传入一个解析器Parser 下载 //文件存储路径 String destPath = getExternalCac ...

  9. android xutils3.0获取服务器图片,Android端使用xUtils3.0实现文件上传

    privatevoidupLoadOnClick(View v) {        String upUrl ="/mnt/sdcard/pic/test.jpg";//指定要上传 ...

最新文章

  1. 关于鼠标、键盘的几个例子
  2. Java类的基本运行顺序
  3. linux+date+命令+作业,Linux date命令的使用
  4. 光子 量子 DNA计算机的发展情况,科研萌新关于非冯诺依曼结构计算机的一些知识mewo~~...
  5. ubuntu下安装zabbix
  6. 智能家居 (3) ——智能家居工厂模式介绍实现继电器控制灯
  7. 中文巨量模型“源1.0”:模型结构与生成效果解析
  8. [Swift实际操作]七、常见概念-(12)使用DispatchGroup(调度组)管理线程数组
  9. Batch Normalization 算法解析
  10. 单片机音频谱曲软件_基于51单片机音乐播放仿真 乐谱制作软件 音乐资料
  11. AttributeError: module 'scipy.misc' has no attribute 'imrotate'
  12. 微信小程序 在wxml写过滤器 脱敏手机号
  13. 比360强力删除还暴力的删除文件(夹)方法
  14. 2022蓝桥模拟-子汉诺塔
  15. 推荐一个还不错的医学网站
  16. 百度首次发布3D地图 杨洋导航语音完整版上线
  17. Java 窗口透明化(无边框)
  18. ubuntu 安装 canon ip1180 打印机(图片打印未解决)
  19. 商业变现永不眠(三) — 社交产品的商业化
  20. linux 文件cache,Linux下哪些文件在消耗我们的Cache?

热门文章

  1. 乐视手机插电信卡显示无服务器,乐视手机1支持电信卡吗?乐视手机1支持联通卡吗?...
  2. Qt for WebAssembly 环境搭建 - Windows篇
  3. 【微信公众号】-目录
  4. python从集思录获取最近新发可转债信息
  5. 刀锋铁骑服务器维护,刀锋铁骑方向控制教程 教你如何灵活走动
  6. 国内手机号码归属地查询---Nusoap学习笔记(三)
  7. 如何从程序员走向技术管理岗位?
  8. 南大计算机生物信息学,机器学习与数据挖掘-南京大学计算机系.PDF
  9. docker下hitchhiker安装
  10. ORACLE +win2003 群集手记