Android上传手机图片到服务器(这篇你要是看不懂,全网没你可以看懂的了!!!)

news2025/1/18 6:51:32

Android上传手机图片到服务器

  • 1、整体流程
  • 2、页面布局
  • 3、选择图片
    • 流程
    • 实现
    • 演示结果
    • 完整代码
  • 4、路径转换
    • 路径转换
    • Utils工具类
    • 权限申请
    • 完整代码
  • 5、创建文件
  • 6、服务器端
  • 7、传输
  • 8、演示
  • 9、完整代码
    • 目录结构
    • AndroidManifest.xml
    • 布局文件activity_main.xml
    • 传输文件工具类HttpUtil
    • 路径转换工具类Utils
    • MainActivity类

在这里插入图片描述

1、整体流程

通过安卓app选取本地图片然后上传到服务器的整体流程步骤如下:
在这里插入图片描述

2、页面布局

样式

在这里插入图片描述
布局代码

<?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:gravity="center"
    android:orientation="vertical"
    >

    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:background="#555555"
        android:id="@+id/iv_image"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/xz"
        android:text="选择图片"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/sc"
        android:text="上传图片"/>
    
</LinearLayout>

id:iv_image用于呈现选择的图片
id:xz用于选择图片的按钮
id:sc用于上传的按钮

3、选择图片

流程

在这里插入图片描述
流程:点击“选择图片”在本机选取图片然后呈现到ImageView中(这个操作过程是不需要申请任何权限的)

实现

(1)获取“选择图片”按钮,并设置监听事件。

xz = (Button) findViewById(R.id.xz);//选择照片按钮
xz.setOnClickListener(this);//设置监听

(2)获取ImageView,便于之后呈现图片

iv_image = (ImageView) findViewById(R.id.iv_image);//展示图片按钮

(3)点击“选择图片”后操作,选取图片

点击事件

@Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.xz:
                xzImage();//选择图片
                break;
        }
    }

xzImage()函数进行图片选择

private void xzImage() {
        
        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent,CHOOSE_PHOTO); // 打开本地存储
        //CHOOSE_PHOTO:全局常量,标识
}

CHOOSE_PHOTO:是一个全局常量,用于标识这是选择图片的这个操作,便于在回调函数中使用。

public static final int CHOOSE_PHOTO = 1;

(4)重写选择图片后的回调函数

当在手机上选择完图片后会回调onActivityResult函数,将一下“选择的信息”返回供用户操作。

requestCode:标识码
data:选择的图片的信息
data.getData()可以获取到图片的路径,但是是虚拟路径不是真实的存储路径,虚拟路径在ImageView组件中可以使用,但是如果通过虚拟路径进行创建文件(new File(“路径”))是不可能的。

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
      //requestCode:标识码
      //data:选择的图片的信息
        switch (requestCode) {
            case CHOOSE_PHOTO:
                //显示图片
                iv_image.setImageURI(data.getData());//放在ImageView中呈现
                break;
            default:
                break;
        }
    }

以上操作全部是无需权限申请的

演示结果

在这里插入图片描述

完整代码

上述操作的完整代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


    private Button xz;
    private ImageView iv_image;
    public static final int CHOOSE_PHOTO = 1;//标识选择图片

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //按钮
        xz = (Button) findViewById(R.id.xz);//选择照片按钮
        //图片
        iv_image = (ImageView) findViewById(R.id.iv_image);//展示图片
        //设置点击事件监听
        xz.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.xz:
                xzImage();
                break;
        }
    }


    private void xzImage() {

        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent,CHOOSE_PHOTO); // 打开本地存储
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
            case CHOOSE_PHOTO://判断是不是选择照片后的操作
                //显示图片
                iv_image.setImageURI(data.getData());
                break;
            default:
                break;
        }
    }

}

4、路径转换

在这里插入图片描述

由于data.getData()获取到的是图片的虚拟路径,所以我们需要对路径进行路径转换,从虚拟路径真实路径的转换。(通过Utils.getRealPath(this, data)方法进行转换)

Utils.getRealPath(this, data)方法是封装的工具类

路径转换

在这里插入图片描述

Utils工具类

public class Utils {

    public static String getRealPath(Context context,Intent data){
        // 判断手机系统版本号
        if (Build.VERSION.SDK_INT >= 19) {
            // 4.4及以上系统使用这个方法处理图片
            return handleImageOnKitKat(context,data);
        } else {
            // 4.4以下系统使用这个方法处理图片
            return handleImageBeforeKitKat(context,data);
        }
    }


    @TargetApi(19)
    private static String handleImageOnKitKat(Context context,Intent data) {
        String imagePath = null;
        Uri uri = data.getData();
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // 如果是document类型的Uri,则通过document id处理
            String docId = DocumentsContract.getDocumentId(uri);
            if("com.android.providers.media.documents".equals(uri.getAuthority())) {
                String id = docId.split(":")[1]; // 解析出数字格式的id
                String selection = MediaStore.Images.Media._ID + "=" + id;
                imagePath = getImagePath(context,MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
            } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public downloads"), Long.valueOf(docId));
                imagePath = getImagePath(context,contentUri, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            // 如果是content类型的Uri,则使用普通方式处理
            imagePath = getImagePath(context,uri, null);
        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
            // 如果是file类型的Uri,直接获取图片路径即可
            imagePath = uri.getPath();
        }
        //displayImage(imagePath); // 根据图片路径显示图片
        return imagePath;
    }


    private static String handleImageBeforeKitKat(Context context,Intent data) {
        Uri uri = data.getData();
        String imagePath = getImagePath(context,uri, null);
        return imagePath;
    }


    @SuppressLint("Range")
    private static String getImagePath(Context context,Uri uri, String selection) {
        String path = null;
        // 通过Uri和selection来获取真实的图片路径
        Cursor cursor = context.getContentResolver().query(uri, null, selection, null, null);
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            }
            cursor.close();
        }
        return path;
    }

}

权限申请

由于在工具类中进行路径转换时候需要用到存储权限,所以我们在之前代码的基础上加上动态权限申请
在这里插入图片描述

注意:是在点击“选择图片”后进行权限申请,申请完后再去选择图片
顺序是这样子的:点击“选择图片按钮” == > 权限申请 ==》选择图片·

(1)在Manifest.xml中加入权限声明

<!--写-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--读-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

(2)在onclick处加上权限检测、申请步骤

@Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.xz:
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION);
                } else {
                    xzImage();
                }
                break;
        }
    }

Manifest.permission.WRITE_EXTERNAL_STORAGE既包括读权限又包括写权限,所以在Manifest.xml中才声明了两个
STORAGE_PERMISSION:是一个全局常量,用于标识申请的是什么权限,方便在权限的回调函数中使用。

public static final int STORAGE_PERMISSION = 1;

(3)添加权限的回调函数

//选择权限后的回调函数
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case STORAGE_PERMISSION:
            //检查是否有读取存储卡的权限,如果有则选择图片,如果没有则提示
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    xzImage();
                } else {
                    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }

STORAGE_PERMISSION:标识申请的是存储权限,是全局常量。
(4)测试
我们在onActivityResult中输出虚拟路径和真实路径看一下(如果不做上述的权限申请,则在调用Utils.getRealPath(this, data)方法进行路径转换时会报错)

//选择图片后的回调函数
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
            case CHOOSE_PHOTO:
                //显示图片
                iv_image.setImageURI(data.getData());
                System.out.println("图片在手机上的虚拟路径为:"+data.getData());
                String realPath = Utils.getRealPath(this, data);
                System.out.println("图片在手机上的真实路径为:"+realPath);

                break;
            default:
                break;
        }
    }

申请权限
在这里插入图片描述

输出
在这里插入图片描述

完整代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


    private Button xz;
    private ImageView iv_image;
    public static final int CHOOSE_PHOTO = 1;//标识选择图片
    public static final int STORAGE_PERMISSION = 1;//标识权限申请

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //按钮
        xz = (Button) findViewById(R.id.xz);//选择照片按钮
        //图片
        iv_image = (ImageView) findViewById(R.id.iv_image);//展示图片
        //设置点击事件监听
        xz.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.xz:
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION);
                } else {
                    xzImage();
                }
                break;
        }
    }


    private void xzImage() {

        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent,CHOOSE_PHOTO); // 打开本地存储
    }

    //选择图片后的回调函数
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
            case CHOOSE_PHOTO:
                //显示图片
                iv_image.setImageURI(data.getData());
                System.out.println("图片在手机上的虚拟路径为:"+data.getData());
                String realPath = Utils.getRealPath(this, data);
                System.out.println("图片在手机上的真实路径为:"+realPath);
                break;
            default:
                break;
        }
    }


    //选择权限后的回调函数
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case STORAGE_PERMISSION:
               //检查是否有读取存储卡的权限,如果有则选择图片,如果没有则提示
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    xzImage();
                } else {
                    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }

}

5、创建文件

在这里插入图片描述
当我们通过Utils.getRealPath(this, data)方法获取到真实的图片路径后就可以通过new File(路径的方式将图片封装成File对象了)

String realPath = Utils.getRealPath(this, data);
file = new File(realPath);

这里的file是全局变量,便于后续上传的时候使用

private File file=null;

所以此时选择图片后的回调函数变为如下:

//选择图片后的回调函数
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case CHOOSE_PHOTO:
                //显示图片
                iv_image.setImageURI(data.getData());
                //System.out.println("图片在手机上的虚拟路径为:"+data.getData());
                String realPath = Utils.getRealPath(this, data);
                file = new File(realPath);
                //System.out.println("图片在手机上的真实路径为:"+realPath);
                break;
            default:
                break;
        }
    }

至此从相册选择图片到将图片创建成file对象已经全部完成。
这半部分全部完成
在这里插入图片描述

6、服务器端

为便于测试,该项目的服务器代码比较简单,通过一个接口接收文件(uploadfile),以及传过来的其余参数(name)。输出其余参数,并将图片存储到项目的当前目录下命名为a.jpg

@RestController
@RequestMapping("/test")
@CrossOrigin
public class TestController {

    /**
     * 
     * @param uploadfile 接收文件
     * @param name 接收其余参数
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public String upload(MultipartFile uploadfile,String name) throws IOException {

        //1、输出测试
        System.out.println("==============");
        System.out.println(uploadfile);
        System.out.println(name);
        System.out.println(uploadfile.getName());
        System.out.println(uploadfile.getSize());
        //2、将上传的图片存储到硬盘
        InputStream inputStream = uploadfile.getInputStream();
        FileChannel inChannel = (FileChannel) Channels.newChannel(inputStream);
        FileChannel outChannel = new FileOutputStream("./a.jpg").getChannel();//当前目录下,命名为a.jpg
        inChannel.transferTo(0,inChannel.size(),outChannel);

        //3、关闭流
        inChannel.close();
        outChannel.close();
        inputStream.close();
        
        //4、返回成功信息
        return "success";
    }

}

(springboot项目)
目前为止服务器端的代码也以及全部搞定
在这里插入图片描述

7、传输

Android端的东西全部搞定,服务器端的东西也全部搞定,接下来就是通信了,也就是将文件从Android端传输到服务器端。
传输文件采用okhttp进行数据的传输
(1)权限申请
由于传输的时候使用到网络,所以在Manifest.xml中声明网络权限

<!--    网络-->
    <uses-permission android:name="android.permission.INTERNET" />

并在Manifest.xml中加入这个,我们不采用https进行传输
在这里插入图片描述

(2)引入okhttp的依赖

//okhttp
    implementation 'com.squareup.okhttp3:okhttp:3.14.9'

在这里插入图片描述
刷新后便可以将okhttp的依赖加载到本地
(3)传输文件的工具类
通过okhttp封装成上传文件的工具类

public class HttpUtil {

    /**
     *
     * @param address  服务器地址
     * @param requestBody  请求体数据
     * @param callback  回调接口
     */
    public static void uploadFile(String address,RequestBody requestBody ,okhttp3.Callback callback){

        //发送请求
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)//设置连接超时时间
                .readTimeout(60, TimeUnit.SECONDS)//设置读取超时时间
                .build();
        Request request = new Request.Builder()
                .url(address)
                .post(requestBody)
                .build();
        client.newCall(request).enqueue(callback);

    }

}

(4)上传函数

获取“上传按钮”并设置监听事件

sc = (Button) findViewById(R.id.sc);//上传按钮
sc.setOnClickListener(this);//上传

在点击事件中添加scImage()函数,在点击"上传图片"按钮后触发
onclick中
在这里插入图片描述

@Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.xz:
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION);
                } else {
                    xzImage();
                }
                break;
            case R.id.sc:
                scImage();
                break;
        }
    }

scImage()函数

private void scImage() {
        //1、创建请求体
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)//请求类型
                .addFormDataPart("name", "lisi")//参数1
                .addFormDataPart("uploadfile", "uploadfile", RequestBody.create(MediaType.parse("*/*"), file)) // 第一个参数传到服务器的字段名,第二个你自己的文件名,第三个MediaType.parse("*/*")数据类型,这个是所有类型的意思,file就是我们之前创建的全局file,里面是创建的图片
                .build();
         //2、调用工具类上传图片以及参数
        HttpUtil.uploadFile("http://你的服务器IP:8080/test/upload", requestBody, new Callback() {
        
            //请求失败回调函数
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println("=============");
                System.out.println("异常::");
                e.printStackTrace();
            }
            
            //请求成功响应函数
            @Override
            public void onResponse(Call call, Response response) throws IOException {

                showResponse(response.body().string());//在主线程中显示提示框
            }
        });
    }

注意:安卓端的字段名要与服务器端接收的字段名字一样
在这里插入图片描述
在这里插入图片描述

由于在子线程不能操作ui,所以这里调用showResponse在主线程中提示,响应结果。

showResponse()

//ui操作,提示框
    private void showResponse(final String response) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // 在这里进行UI操作,将结果显示到界面上
                Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
            }
        });
    }

8、演示

至此已经完成了所有步骤“Android端”、“服务器端”、“传输数据”的代码编写。
我们将服务器端代码在服务器部署好,然后在Android端输入对应的ip,进行测试。

服务的“当前文件夹目录”
在这里插入图片描述
传输
在这里插入图片描述

传输完后
在这里插入图片描述
可以拉到本地打开看一下
在这里插入图片描述

9、完整代码

目录结构

在这里插入图片描述

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!--    网络-->
    <uses-permission android:name="android.permission.INTERNET" />
    
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication"
        android:usesCleartextTraffic="true"
        >
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>

布局文件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:gravity="center"
    android:orientation="vertical"
    >

    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:background="#555555"
        android:id="@+id/iv_image"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/xz"
        android:text="选择图片"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/sc"
        android:text="上传图片"/>

</LinearLayout>

传输文件工具类HttpUtil

public class HttpUtil {

    /**
     *
     * @param address  服务器地址
     * @param requestBody  请求体数据
     * @param callback  回调接口
     */
    public static void uploadFile(String address,RequestBody requestBody ,okhttp3.Callback callback){

        //发送请求
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)//设置连接超时时间
                .readTimeout(60, TimeUnit.SECONDS)//设置读取超时时间
                .build();
        Request request = new Request.Builder()
                .url(address)
                .post(requestBody)
                .build();
        client.newCall(request).enqueue(callback);

    }

}

路径转换工具类Utils

public class Utils {

    public static String getRealPath(Context context,Intent data){
        // 判断手机系统版本号
        if (Build.VERSION.SDK_INT >= 19) {
            // 4.4及以上系统使用这个方法处理图片
            return handleImageOnKitKat(context,data);
        } else {
            // 4.4以下系统使用这个方法处理图片
            return handleImageBeforeKitKat(context,data);
        }
    }


    @TargetApi(19)
    private static String handleImageOnKitKat(Context context,Intent data) {
        String imagePath = null;
        Uri uri = data.getData();
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // 如果是document类型的Uri,则通过document id处理
            String docId = DocumentsContract.getDocumentId(uri);
            if("com.android.providers.media.documents".equals(uri.getAuthority())) {
                String id = docId.split(":")[1]; // 解析出数字格式的id
                String selection = MediaStore.Images.Media._ID + "=" + id;
                imagePath = getImagePath(context,MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
            } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public downloads"), Long.valueOf(docId));
                imagePath = getImagePath(context,contentUri, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            // 如果是content类型的Uri,则使用普通方式处理
            imagePath = getImagePath(context,uri, null);
        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
            // 如果是file类型的Uri,直接获取图片路径即可
            imagePath = uri.getPath();
        }
        //displayImage(imagePath); // 根据图片路径显示图片
        return imagePath;
    }


    private static String handleImageBeforeKitKat(Context context,Intent data) {
        Uri uri = data.getData();
        String imagePath = getImagePath(context,uri, null);
        return imagePath;
    }


    @SuppressLint("Range")
    private static String getImagePath(Context context,Uri uri, String selection) {
        String path = null;
        // 通过Uri和selection来获取真实的图片路径
        Cursor cursor = context.getContentResolver().query(uri, null, selection, null, null);
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            }
            cursor.close();
        }
        return path;
    }

}

MainActivity类

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


    private Button xz;
    private Button sc;
    private ImageView iv_image;
    public static final int CHOOSE_PHOTO = 1;
    public static final int STORAGE_PERMISSION = 1;
    private File file=null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //按钮
        xz = (Button) findViewById(R.id.xz);//选择照片按钮
        sc = (Button) findViewById(R.id.sc);//上传按钮
        //图片
        iv_image = (ImageView) findViewById(R.id.iv_image);//展示图片
        //设置点击事件监听
        xz.setOnClickListener(this);//选择
        sc.setOnClickListener(this);//上传

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.xz:
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION);
                } else {
                    xzImage();
                }
                break;
            case R.id.sc:
                scImage();
                break;
        }
    }




    private void xzImage() {

        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent,CHOOSE_PHOTO); // 打开本地存储
    }

    private void scImage() {
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("name", "lisi")
                .addFormDataPart("uploadfile", "uploadfile", RequestBody.create(MediaType.parse("*/*"), file)) // 第一个参数传到服务器的字段名,第二个你自己的文件名,第三个MediaType.parse("*/*")数据类型,这个是所有类型的意思,file就是我们之前创建的全局file,里面是创建的图片
                .build();
                
        HttpUtil.uploadFile("http://你自己的ip:8080/test/upload", requestBody, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println("=============");
                System.out.println("异常::");
                e.printStackTrace();
                //Toast.makeText(MainActivity.this, "上传异常", Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {

                showResponse(response.body().string());
                //Toast.makeText(MainActivity.this, "上传成功", Toast.LENGTH_SHORT).show();
            }
        });
    }

    //选择图片后的回调函数
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case CHOOSE_PHOTO:
                //显示图片
                iv_image.setImageURI(data.getData());
                //System.out.println("图片在手机上的虚拟路径为:"+data.getData());
                String realPath = Utils.getRealPath(this, data);
                file = new File(realPath);
                //System.out.println("图片在手机上的真实路径为:"+realPath);
                break;
            default:
                break;
        }
    }


    //选择权限后的回调函数
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case STORAGE_PERMISSION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    xzImage();
                } else {
                    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }


    //ui操作,提示框
    private void showResponse(final String response) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // 在这里进行UI操作,将结果显示到界面上
                Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
            }
        });
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/387155.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯-质因数个数

蓝桥杯-质因数个数1、问题描述2、解题思路2.1 质数判断2.2 求取因子3、完整代码实现1、问题描述 给定正整数 n, 请问有多少个质数是 n 的约数。 输入格式 输入的第一行包含一个整数 n。 输出格式 输出一个整数, 表示 n 的质数约数个数。 样例输入 396样例输出 3样例说明 3…

【教学典型案例】13.学情页面逻辑问题

目录一&#xff1a;背景介绍二&#xff1a;LocalStorage缓存①localStorage是什么&#xff1f;②如何使用localStorage缓存三&#xff1a;学情页面逻辑分析过程四&#xff1a;总结五&#xff1a;升华一&#xff1a;背景介绍 使用的前端技术是Vue2&#xff0c;前端逻辑&#xf…

SpringCloud:Eureka

目录 一、eureka的作用 二、搭建Eureka服务端 三、添加客户端 四、服务发现 提供者与消费者 服务提供者&#xff1a;一次业务中&#xff0c;被其它微服务调用的服务。&#xff08;提供接口给其它微服务) 服务消费者&#xff1a;一次业务中&#xff0c;调用其它微服务的服…

[1.1_2]计算机系统概述——操作系统的四个特征

文章目录第一章 计算机系统概述操作系统的特征&#xff08;一&#xff09;并发&#xff08;二&#xff09;共享并发和共享的关系&#xff08;三&#xff09;虚拟&#xff08;四&#xff09;异步小结第一章 计算机系统概述 操作系统的特征 操作系统的四个特征 并发共享 并发和共…

Linux学习第七节-SUID、SGID、SBIT特殊权限

1.SetUID特殊权限 setUID (SUID): 对于一个可执行的文件使用SUID权限后&#xff0c;普通用户在执行改文件后&#xff0c;临时拥有文件所有者的身份&#xff0c;该权限只在程序执行过程中有效&#xff0c;程序执行完毕后用户恢复原有身份。 SetUID权限会附加在所有者的x权限位上…

每日分享(2023最新文件快递柜系统网站源码 匿名口令分享临时文件分享)

​demo软件园每日更新资源,请看到最后就能获取你想要的: 1.UML参考手册(第二版) 中文 中文名: UML参考手册&#xff08;第二版&#xff09;原名: The Unified Modeling Language Reference Manual(2nd Edition) 作者: James Rumbaugh Ivar Jacobson Grady Booch译者: UML Ch…

汇编语言程序设计(二)之寄存器

系列文章 汇编语言程序设计&#xff08;一&#xff09; 寄存器 在学习汇编的过程中&#xff0c;我们经常需要操作寄存器&#xff0c;那么寄存器又是什么呢&#xff1f;它是用来干什么的&#xff1f; 它有什么分类&#xff1f;又该如何操作&#xff1f;… 你可能会有许多的…

基于PySide6的MySql数据库快照备份与恢复软件

db-camera 软件介绍 db-camera是一款MySql数据库备份&#xff08;快照保存&#xff09;与恢复软件。功能上与dump类似&#xff0c;但是提供了相对有好的交互界面&#xff0c;能够有效地管理导出的sql文件。 使用场景 开发阶段、测试阶段&#xff0c;尤其适合单人开发的小项目…

降低物联网开发门槛的神器大更新!TuyaOS 3.7.0版本新增matter等开发框架

作为降低物联网开发门槛的TuyaOS &#xff0c;此次迎来了重大更新&#xff08;点击查看TuyaOS 往期介绍&#xff09;&#xff01;TuyaOS 3.7.0 新版本不仅支持多款 Matter 开发框架&#xff0c;帮助开发者轻松奔赴万物互联时代&#xff0c;还覆盖多种协议连接&#xff0c;能快速…

【Simulink】单相电压型全桥逆变电路仿真基础实验

版本&#xff1a;matlab2019b 1 单相电压型全桥逆变电路简介 1.1 逆变 逆变&#xff0c;即直流变换成交流。 在全桥逆变电路中&#xff1a;V1、V2、V3、V4 为 IGBT&#xff0c;VD1、VD2、VD3、VD4为二极管 当V1、V4导通&#xff0c;V2、V3截止时&#xff0c;负载电压uo为正&a…

【CV学习笔记】之ncnnFastDet多线程c++部署

1、前言 ncnn是一款非常高效易用的深度学习推理框架&#xff0c;支持各种神经网络模型&#xff0c;如pytorch、tensorflow、onnx等&#xff0c;以及多种硬件后端&#xff0c;如x86、arm、riscv、mips、vulkan等。 ncnn项目地址:https://github.com/Tencent/ncnn FastDet是设计…

English Learning - L2 第2次小组纠音 [iː] [ɜː] [æ] 2023.3.1 周三

English Learning - L2 第2次小组纠音 [iː] [ɜː] [] 2023.3.1 周三共性问题分析前元音 [iː]中元音 [ɜː]前元音 []我的发音问题舌位找的不准纠音过程共性问题分析 前元音 [iː] 嘴角左右拉伸没有到位 解决方法&#xff1a; 嘴角是往耳后根的方向&#xff0c;微微上扬的角…

指针和数组面试题(逐题分析,完善你可能遗漏的知识)

人生不是一种享乐&#xff0c;而是一桩十分沉重的工作。 —— 列夫托尔斯泰 前言&#xff1a;之前我们就学习了数组和指针的知识。 数组&#xff1a;数组就是能够存放一组相同类型的元素&#xff0c;数组的大小取决于数组的元素个数和元素类型。 指针&#xff1a;…

Linux操作系统学习(进程等待)

文章目录进程等待进程等待的必要性如何进程等待waiwaitpid验证进程等待 ​ 我们知道fork函数可以创建一个子进程&#xff0c;而子进程通常是替父进程完成一些任务&#xff0c;而父进程在fork之后需要通过wait/waitpid等待子进程退出。这就是进程等待 进程等待的必要性 通过获…

Allegro如何导入第三方网表操作指导

Allegro如何导入第三方网表操作指导 在用Allegro做PCB设计的时候,除了支持第一方网表的导入,同样也是可以导入第三方网表的,第三方网表如下图 如何导入,具体操作如下 点击Setup点击User Preference

【抽水蓄能电站】基于粒子群优化算法的抽水蓄能电站的最佳调度方案研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

Linux操作系统学习(进程替换)

文章目录进程替换进程替换是什么&#xff1f;替换的方法进程替换简易shell模拟进程替换 进程替换是什么&#xff1f; 如下图所示&#xff1a; ​ 进程替换就是&#xff0c;把进程B的代码和数据&#xff0c;替换正在执行的进程A的代码和数据在内存中的位置&#xff08;若代码…

etcd集群通过 Leader 写入数据,为什么K8s HA集群中讲每个 kube-apiserver 只和本机的 ETCD 通信

写在前面 对这个我不太明白&#xff0c;所有在 stackOverflow 的请教了大佬这里分享给小伙伴理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都是不完整…

spark sql(二)sql解析流程扩展

1、前言 通过前面的文章我们了解到&#xff0c;spark sql通过catalyst框架解析sql&#xff0c;而在将sql语句转变为可执行的任务过程中会将大的sql解析流程划分为未解析的逻辑计划、解析后的逻辑计划、优化后的逻辑计划、物理计划、可执行物理计划等阶段。大概的解析流程如下所…

Handler与线程

简介 Handler提供的种异步消息处理机制是&#xff1a;当它发出一个消息进入消息队列后&#xff0c;发送消息的函数立刻返回&#xff0c;接着主线程会逐个地从消息队列中把消息取出&#xff0c;然后对消息进行处理。明显&#xff0c;Handler发送消息和接收消息是异步进行的&…