You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java Socket从Android向PC传图片时filePath返回null如何解决?

问题根源

你遇到的两个核心报错原因如下:

  • 高版本Android系统中,ACTION_GET_CONTENT返回的content://类型Uri无法通过查询MediaStore.Images.Media.DATA字段拿到本地文件路径,所以你的getPath方法返回null,后续new File(selectedImagePath)触发空指针导致崩溃
  • 网络操作直接写在主线程中,Android 4.0及以上版本禁止主线程执行网络请求,会直接抛出NetworkOnMainThreadException
  • 清单文件缺少存储读取权限,无法访问设备上的图片文件

修复方案

1. 修改AndroidManifest.xml添加权限

在manifest节点下添加对应存储权限:

<!-- 安卓13及以上版本图片读取权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- 安卓12及以下版本存储读取权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

注意安卓6.0及以上版本需要在应用启动时动态申请上述权限,仅在清单文件声明无效。

2. 修改MainActivity逻辑

删除原有getPath方法,直接通过ContentResolver读取Uri的输入流,同时将网络请求放到子线程执行,修改后的完整代码如下:

package com.example.floweridentifier;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class MainActivity extends Activity {
    private static final int SELECT_PICTURE = 1;
    private static final int PERMISSION_REQUEST_CODE = 100;

    private Uri selectedImageUri; // 替换原有路径字段,直接存Uri
    private ImageView img;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        img = findViewById(R.id.ivPic);

        // 启动时先申请权限
        checkPermission();

        findViewById(R.id.bBrowse).setOnClickListener(new View.OnClickListener() {
            public void onClick(View arg0) {
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(
                        Intent.createChooser(intent, "Select Picture"),
                        SELECT_PICTURE);
            }
        });

        Button send = findViewById(R.id.bSend);
        final TextView status = findViewById(R.id.tvStatus);

        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (selectedImageUri == null) {
                    Toast.makeText(MainActivity.this, "请先选择图片", Toast.LENGTH_SHORT).show();
                    return;
                }
                // 网络操作放到子线程执行
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Socket sock = null;
                        try {
                            // 测试阶段优先用PC的内网IP,不要直接用公网IP,需要确保PC和模拟器在同一局域网
                            sock = new Socket("你的PC内网IP", 800);
                            // 直接从Uri读输入流,不需要转文件路径
                            InputStream is = getContentResolver().openInputStream(selectedImageUri);
                            BufferedInputStream bis = new BufferedInputStream(is);
                            OutputStream os = sock.getOutputStream();

                            byte[] buffer = new byte[1024];
                            int len;
                            while ((len = bis.read(buffer)) != -1) {
                                os.write(buffer, 0, len);
                            }
                            os.flush();
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    status.setText("发送成功");
                                }
                            });
                        } catch (UnknownHostException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                if (sock != null) sock.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start();
            }
        });
    }

    private void checkPermission() {
        String permission;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
            permission = Manifest.permission.READ_MEDIA_IMAGES;
        } else {
            permission = Manifest.permission.READ_EXTERNAL_STORAGE;
        }
        if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{permission}, PERMISSION_REQUEST_CODE);
        }
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            if (requestCode == SELECT_PICTURE) {
                selectedImageUri = data.getData();
                TextView path = findViewById(R.id.tvPath);
                path.setText("Image Uri : " + selectedImageUri);
                img.setImageURI(selectedImageUri);
            }
        }
    }
}

3. 测试注意事项

  • 优先使用PC的内网IP测试,确保模拟器和PC连接在同一个WiFi/局域网下
  • 确认PC端的接收服务已启动,且800端口已放开防火墙限制
  • 如果一定要用公网IP测试,需要在路由器上配置800端口的端口映射,指向你PC的内网IP

内容的提问来源于stack exchange,提问作者user11964310

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 22:09:00