引入:在前几篇文章中,分别讲解了如何调用摄像头、如何拍摄视频并上传到阿里云,本篇文章将分享如何通过相册选择图片并上传到阿里云。
文章一:Android开发:调用摄像头拍摄照片后上传到阿里云OSS(对象存储)
文章二:Android开发:Camera2+MediaRecorder录制视频后上传到阿里云VOD
本篇文章:Android开发:打开相册选择照片后上传到阿里云OSS(对象存储)
上述三篇文章可以实现如图所示的功能即通过拍照、相册、录制视频上传到服务器
文章目录
前言:startActivityForResult与onActivityResult详解
提示:startActivityForResult 和 onActivityResult 这两个方法在 Android 开发中已经被标记为过时(deprecated)。
对于 startActivityForResult 的过时,官方推荐的替代方案是使用 registerForActivityResult。这个方法提供了一种更现代、更灵活的方式来处理从其他活动返回的结果。registerForActivityResult 允许你注册一个 ActivityResultLauncher,并通过它启动活动并处理返回的结果。这种方式的好处是减少了代码的嵌套和耦合,使得代码更加清晰和易于维护。
目前本文中使用的仍然是startActivityForResult与onActivityResult,下面对其进行详细的解释:
startActivityForResult 和 onActivityResult 是 Android 开发中用于从一个活动(Activity)启动另一个活动,并期望从第二个活动返回一些结果到第一个活动的机制。这在多种场景下都非常有用,比如启动一个相机应用来拍照并返回图片,或者启动一个选择器来选择文件等。
startActivityForResult
startActivityForResult 方法用于启动一个新的活动,并期望该活动结束时返回结果。这个方法接受两个参数:
Intent:一个 Intent 对象,描述了要启动的活动的详细信息。
Request Code:一个整数,用于标识这次启动活动的请求。当结果返回时,这个请求码用于区分不同的启动请求。
示例:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUEST_CODE_CAPTURE_IMAGE);
在这个示例中,我们启动了一个相机应用来拍照。REQUEST_CODE_CAPTURE_IMAGE 是一个常量,用于标识这个特定的启动请求。
onActivityResult
onActivityResult 方法是一个回调方法,当启动的活动结束时,系统会调用这个方法,并将结果传递回来。这个方法接受三个参数:
1.Request Code:与 startActivityForResult 中的请求码相对应,用于区分不同的启动请求。
2.Result Code:一个整数,表示启动的活动结束时的状态。通常是 RESULT_OK 或RESULT_CANCELED。
3.Data:一个 Intent 对象,包含了从启动的活动返回的数据。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_CAPTURE_IMAGE && resultCode == RESULT_OK) {
// 处理返回的数据
}
}
在这个示例中,我们检查请求码和结果码来确定是否是我们期望的相机应用返回的结果,并处理返回的数据。
注意点
请求码:确保为每个 startActivityForResult 调用使用唯一的请求码,以便在 onActivityResult 中正确识别它们。
结果码:除了系统定义的 RESULT_OK 和 RESULT_CANCELED,你也可以定义自己的结果码来表示特定的状态。
安全性:由于 onActivityResult 可以从其他应用接收数据,因此应该谨慎处理返回的数据,以避免潜在的安全风险。
通过 startActivityForResult 和 onActivityResult,你可以实现从一个活动启动另一个活动,并在第二个活动完成后获取结果的功能,从而构建出更加丰富和交互性的 Android 应用。
一、实现打开相册并选择图片的功能
1.打开Android Studio新建一个Android 空项目 命名为Album
2.XML的编写,一个用来打开相册的按钮 一个可以放置图片的ImageView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="300dp"
android:src="@mipmap/ic_launcher"
tools:ignore="MissingConstraints" />
<Button
android:layout_gravity="center"
android:id="@+id/open_album"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="打开相册"
tools:ignore="MissingConstraints" />
</LinearLayout>
效果:
MainActivity中的代码:
package com.example.album;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Uri imageUri;
private Button button;
private ImageView imageView;
private static int key=1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.open_album);
imageView=findViewById(R.id.image_view);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.open_album:
Intent intent=new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent,key);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==key){
imageUri = data.getData();
imageView.setImageURI(imageUri);
}
}
}
效果:
打开相册:
2.点击选中照片:
二、上传到阿里云对象存储(OSS)
提示:此处与其他两篇文章不同的是:这里最终获得的对象是一个Uri、而另外两篇文章有文件的准确路径,那么怎么处理Uri是第一个要考虑的问题:这里是将这个Uri转化成了Byte数组后进行上传。
1.测试阿里云官方文档的方法:
测试通过后
改写这段代码在SpringBoot工程上:
Controller层:
//处理字节数组的API
@PostMapping("/uploadByte")
public Map<String,Object> uploadByteImage(@RequestBody byte[] data){
String url=ossService.uploadByteFile(data);
HashMap<String, Object> map = new HashMap<>();
map.put("code",0);
map.put("data",url);
map.put("messsage","成功");
return map;
}
Service层:
public interface OssFileService {
String uploadByteFile(byte[] data);
}
Impl层:
@Override
public String uploadByteFile(byte[] data) {
String endpoint= "你的endpoint";
String accessKeyId="你的accessKeyId";
String accessKeySecret="你的accessKeySecret";
String bucketName= "你的bucketName";
OSS ossClient = new OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret);
String s1 = new DateTime().toString("yyyy/MM/dd");
String filename="example.png";
String objectname=s1+"/"+filename;
try {
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectname, new ByteArrayInputStream(data));
PutObjectResult result = ossClient.putObject(putObjectRequest);
}
catch(Exception e)
{
e.printStackTrace();
}
String url = "https://" + bucketName + "." + endpoint + "/" + filename;
return url;
}
上述代码中的四个常量都可以在官网中相应的获取 前文Android开发:调用摄像头拍摄照片后上传到阿里云OSS(对象存储)里面详细解释这里不做赘述(依赖的引入、Bucket的创建等等都涵盖)
三、在Android中用第三方库Okhttp请求服务端API
1.添加Okhttp依赖:
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
implementation 'org.conscrypt:conscrypt-android:2.2.1'
2.添加网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
3.更改MainActivity中的代码:
package com.example.album;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final MediaType MEDIA_TYPE_OCTET_STREAM = MediaType.parse("application/octet-stream");
Uri imageUri;
private Button button;
private ImageView imageView;
private static int key=1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.open_album);
imageView=findViewById(R.id.image_view);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.open_album:
Intent intent=new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent,key);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==key){
imageUri = data.getData();
try {
ContentResolver contentResolver = getContentResolver();
InputStream inputStream = contentResolver.openInputStream(imageUri);
// 读取输入流内容到字节数组
byte[] fileBytes = readFullyToByteArray(inputStream);
OkHttpClient client=new OkHttpClient();
RequestBody requestBody = RequestBody.create(MEDIA_TYPE_OCTET_STREAM, fileBytes);
Request request = new Request.Builder()
.url("你的Ip地址:你的端口号/oss/files/uploadByte")
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getBaseContext(),"图片上传成功",Toast.LENGTH_SHORT).show();
imageView.setImageURI(imageUri);
}
});
}
});
// 现在你可以使用inputStream来读取文件内容
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private byte[] readFullyToByteArray(InputStream inputStream)
{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try
{
byte[] buffer = new byte[4096];
// 缓冲区大小,可以根据需要调整
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
return outputStream.toByteArray();
}
}
效果: