【问题标题】:Android can't display some of the images transferred over socketAndroid 无法显示通过套接字传输的某些图像
【发布时间】:2017-09-12 16:03:47
【问题描述】:

我的应用程序向局域网中的其他设备发送了一些文本和图像。看起来图像已成功传输和接收(我根本没有任何异常),但不知何故,某些图像在 CardViewAdapter 的 imageView 中显示不好或根本没有显示。

当我收到图像时,我创建文件并使用 createFile 方法保存它。我还传输图像类型并使用此扩展名保存它。我不知道它取决于什么,但我无法解决它。

通过 tcp 发送图像的类:

    public class ImageTransferHandler implements Runnable{
        private static final String TAG = "ImageTransferHandler";
        private static final int SERVER_PORT = 8700;
        private Socket socket;
        private Context context;
        private String hostIpAddress;
        private Bar bar;

        public ClientThreadProcessor(String hostIpAddress, Context context, Bar bar){
            this.context = context;
            this.hostIpAddress = hostIpAddress;
            this.Bar = bar;
        }

        private Socket getSocket(String hostIpAddress) {
                InetAddress serverAddr = InetAddress.getByName(hostIpAddress);
                socket = new Socket(serverAddr, SERVER_PORT);
            return socket;
        }

        private void closeSocket(Socket socket) {
                    socket.close();
        }

        @Override
        public void run() {

            socket = getSocket(hostIpAddress);

            OutputStream outputStream = socket.getOutputStream();


            PrintWriter output = new PrintWriter(new BufferedWriter(
                                            new OutputStreamWriter(outputStream)), true);

            output.println(bar.getImageInfo().isCamera());
            Uri imageUri = Uri.parse(bar.getImageInfo().getPath());
            String mimeType = ImagePicker.getMimeType(context, imageUri);
            String ext = mimeType.substring(mimeType.lastIndexOf("/") + 1);
            if(ext == null) ext = "bmp";
            output.println(ext);
            BufferedOutputStream bout = new BufferedOutputStream(outputStream);
            String realPath = ImagePicker.getRealPathFromUri(context, imageUri);

            InputStream input = new FileInputStream(realPath);

            byte[] buffer = new byte[1024];
            int len;
            while ((len = input.read(buffer)) != -1) {
                bout.write(buffer);
            }
            input.close();
            bout.close();
            Log.d(TAG, "Image sent over network and stream is closed.");                                        

            output.close();

            closeSocket(socket);

        }

    }

通过 tcp 接收图像的类

public class ImageReceiveHandler implements Runnable{
        private static String TAG = "ImageReceiveHandler";
        private Socket socket;
        private Context context;
        private BufferedReader inputBufferedReader;
        private PrintWriter outputPrintWriter;
        private Bar Bar;


        public ClientHandler(Socket socket, Context context){
            this.socket = socket;
            this.context = context;
        }

        @Override
        public void run() {

                InputStream input = socket.getInputStream();
                inputBufferedReader = new BufferedReader(
                                        new InputStreamReader(input));

                outputPrintWriter = new PrintWriter(new BufferedWriter(
                        new OutputStreamWriter(socket.getOutputStream())), true);

                boolean isCamera = Boolean.valueOf(inputBufferedReader.readLine());
                String ext = inputBufferedReader.readLine();

                File imageFile = ImagePicker.createFile(context, ImagePicker.isExternalStorageWritable(), ext);

                if (imageFile != null) {
                    Uri imageUri = Uri.fromFile(imageFile);
                    Log.d(TAG, "imageUri for received image: " + imageUri.toString());

                    BufferedInputStream bufin = null;
                    FileOutputStream output = null;

                    bufin = new BufferedInputStream(input);
                    output = new FileOutputStream(imageFile);

                    byte[] buffer = new byte[1024];
                    int len;
                    while((len = bufin.read(buffer)) != -1){
                       output.write(buffer);
                       output.flush();
                    }

                    output.close();
                    bufin.close();

                    Log.d(TAG, "Image is received and saved. File length: " + imageFile.length());

                    ImageInfo info = new ImageInfo(imageUri.toString(), isCamera);
                    Bar = new Bar(info);

                    addNotification(Bar, hostAddress);
                }
                else
                    Log.d(TAG, "ImagePicker.createFile returns NULL");


                inputBufferedReader.close();
                outputPrintWriter.close();
        }


        public File createFile(Context context, boolean external, String ext) {
            File direct;

            if(external)
                direct = new File(Environment.getExternalStorageDirectory() + "/myo_images");
            else
                direct = new File(context.getFilesDir() + "/myo_images");


            if (!direct.exists()) {
                File imagesDir;
                if(external)
                    imagesDir = new File("/sdcard/myo_images/");
                else
                    imagesDir = new File("/myo_images");

                imagesDir.mkdirs();
            }

            String timestamp =  new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

            File file = null;

            if(external) 
                 file = File.createTempFile("myo_" + timestamp, "." + ext, direct);
            else 
                 file = File.createTempFile("myo_" + timestamp, "." + ext, direct);

            return file;
        }
    }

应该可视化图像的适配器类

public class BarsCardViewAdapter extends RecyclerView.Adapter<BarsCardViewAdapter.CardViewHolder> {

        private List<BarData> activeBars;
        private final static String TAG = "CARDVIEW_ADAPTER";


        public BarsCardViewAdapter(List<BarData> Bars){
            activeBars = Bars;
        }

        public static class CardViewHolder extends RecyclerView.ViewHolder {
            private ActiveBarsListItemBinding listItemBinding;

            public CardViewHolder(View v) {
                super(v);
                listItemBinding = DataBindingUtil.bind(v);
            }

            public ActiveBarsListItemBinding getBinding(){
                return listItemBinding;
            }

        }

        @Override
        public BarsCardViewAdapter.CardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.bars_list_item, parent, false);

            CardViewHolder holder = new CardViewHolder(v);
            return holder;
        }



        @Override
        public void onBindViewHolder(final BarsCardViewAdapter.CardViewHolder holder, final int position) {
            holder.getBinding().imageView.setVisibility(View.GONE);
            final Bar bar  = activeBars.get(position);
            final ImageInfo imageInfo = bar.getImageInfo();
            final LinearLayout rLayout = holder.getBinding().listItemLayout;


            ImageInfo imageInfo = BarData.getImageInfo();
            Log.d(TAG, "imagePath: " + Uri.parse(imageInfo.getPath()));
            holder.getBinding().imageView.setVisibility(View.VISIBLE);
            Picasso.with(rLayout.getContext()).
                        load(imageInfo.getPath()).
                        transform(new CropSquareTransformation()).
                        into(holder.getBinding().imageView);


            holder.getBinding().setVariable(BR.Bar, bar);
            holder.getBinding().executePendingBindings();
        }

        @Override
        public int getItemCount() {
            return activeBars.size();
        }



    }

【问题讨论】:

  • 您只能从 inputBufferedReader 中读取一行。只有一个分机。但是那个缓冲的阅读器将缓冲比那条线更多的东西。它也会缓冲很多图像。但是您将缓冲区扔掉并尝试从新输入中读取图像。那不行。
  • 我删除了不必要的部分,但事实上我还在“ext”之前发送了一些其他文本。我应该如何使用流来正确发送文本和后图像?如何避免在 BufferedReader 中缓冲图像数据?谢谢
  • 不要使用阅读器是你发送文本和图像。只需使用 DataInputStream.@
  • 请阅读Under what circumstances may I add “urgent” or other similar phrases to my question, in order to obtain faster answers? - 总结是这不是解决志愿者的理想方式,并且可能会适得其反。请不要将此添加到您的问题中。
  • @greenapps 谢谢,请看下面我的回答。

标签: java android image imageview


【解决方案1】:

您正在尝试读取二进制数据,但正在使用读取器,该读取器使用某种依赖于指定字符集的转换将字节转换为字符:

inputBufferedReader = new BufferedReader(
                          new InputStreamReader(input));

这会使用系统的字符集(例如 UTF8cp1252)打开阅读器

不使用 Reader 和 Writer,而是使用流,在本例中为 BufferedInputStream 和 BufferedOutputStream 以及 bytes 的读/写块。

【讨论】:

  • BufferedReader 用于接收文本。因为在图像之前我发送了一些文本信息。但后来我使用BufferedInputStream bufin 将 InputStream 输入作为参数来接收图像。实际上有些图像显示得很好,但有些则不然。
  • @user3717434 InputStreamReader 和 BufferedReader 都将数据缓冲到本地缓冲区中,因此稍后传递给 BufferedInputStream 的输入流可能会丢失图像的初始字节,因为它们已被读取器读取。您可以使用 DataOutputStream 并使用 writeUTF(value) 来发送一些文本,而不是读取器/写入器。在客户端,您相应地使用 DataInputStream
【解决方案2】:

这里我用 DataInput/OutputStream 实现了数据传输。数据传输似乎没问题,但现在它不显示任何图像。你能告诉我我的代码有什么问题吗?(其余的都是一样的) 我收到此错误消息,我想我关闭了所有内容。为什么它会出现这个“命中文件结束”错误?:

09-12 20:25:00.005 13426-14473/mattoncino.pollo E/JHEAD:命中文件结束!!

09-12 20:25:00.032 13426-14473/mattoncino.pollo W/BitmapFactory:解码器 JPEG 解码失败!

发件人线程

     public class ImageTransferHandler implements Runnable{
        private static final String TAG = "ImageTransferHandler";
        private static final int SERVER_PORT = 8700;
        private Socket socket;
        private Context context;
        private String hostIpAddress;
        private Bar bar;


        @Override
        public void run() {
      
            socket = getSocket(hostIpAddress);
                
            DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
                                                            
            dataOutputStream.writeBoolean(bar.getImageInfo().isCamera());
            Uri imageUri = Uri.parse(bar.getImageInfo().getPath());
            String mimeType = ImagePicker.getMimeType(context, imageUri);
            String ext = mimeType.substring(mimeType.lastIndexOf("/") + 1);
            if(ext == null) ext = "bmp";
            dataOutputStream.writeUTF(ext);
            
            
            String realPath = ImagePicker.getRealPathFromUri(context, imageUri);
            File imageFile = new File(realPath);
            byte[] byteArray = new byte[(int) imageFile.length()];

            FileInputStream fis = new FileInputStream(imageFile);
            fis.read(byteArray);
            fis.close();

            dataOutputStream.writeInt(byteArray.length);
            dataOutputStream.write(byteArray, 0, byteArray.length);

            dataOutputStream.flush();                                  
            dataOutputStream.close();

            closeSocket(socket);
        }
    }

接收线程

    public class ImageReceiveHandler implements Runnable{
        private static String TAG = "ImageReceiveHandler";
        private Socket socket;
        private Context context;
        private DataOutputStream dataOutputStream;
        private DataInputStream dataInputStream;
        private Bar Bar;


        @Override
        public void run() {

                dataInputStream = new DataInputStream(socket.getInputStream());

                boolean isCamera = dataInputStream.readBoolean();
                String ext = dataInputStream.readUTF();
                
                File imageFile = ImagePicker.createFile(context, ImagePicker.isExternalStorageWritable(), ext);
                
                if (imageFile != null) {
                    Uri imageUri = Uri.fromFile(imageFile);
                    Log.d(TAG, "imageUri for received image: " + imageUri.toString());

                    int len = dataInputStream.readInt();
                    byte[] buffer = new byte[len];
                    dataInputStream.read(buffer, 0, len);

                    FileOutputStream fileOut = new FileOutputStream(imageFile);
                    fileOut.write(buffer);
                    fileOut.close();
                
                    Log.d(TAG, "Image is received and saved. File length: " + imageFile.length());

                    ImageInfo info = new ImageInfo(imageUri.toString(), isCamera);
                    Bar = new Bar(info);

                    addNotification(Bar, hostAddress);
                }
                else
                    Log.d(TAG, "ImagePicker.createFile returns NULL");
                    
                dataInputStream.close();
        }

已编辑


Bar 是一个类,它代表我的主要对象,其中还包含图像信息。有一些除 imageInfo 以外的文本。但我认为这个类或其用法没有问题。

addNotification 只是一个创建通知的方法,它有一个将图像信息传递给包含适配器的 Activity 的 Intent。

ImageInfo 是一个保存图像信息的类:一个字符串路径和一个布尔值,用于标记是否从相机获取图像(此信息在调整图像大小时被另一种方法使用,但对于我们的问题无关紧要)

我认为文件传输没问题。发送方和接收方的文件大小相同。 ext 是图片的扩展名。

发件人日志:

图像长度:23262 Mime 类型:图像/jpeg 分机:jpeg

接收者日志:

图像被接收并保存。图片长度:23262 分机:jpeg

 final class ImageInfo implements Parcelable, Serializable {
        private String path;
        private final boolean isCamera;

        public ImageInfo(String path, boolean isCamera) {
             this.path = path;
            this.isCamera = isCamera;
        }

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }

        public boolean isCamera() {
            return isCamera;
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int i) {
            parcel.writeString(path);
            parcel.writeByte((byte) (isCamera ? 1 : 0));
        }

        public static final Parcelable.Creator<ImageInfo> CREATOR
                = new Parcelable.Creator<ImageInfo>() {
            public ImageInfo createFromParcel(Parcel in) { return new ImageInfo(in); }

            public ImageInfo[] newArray(int size) { return new ImageInfo[size]; }
        };

        public ImageInfo(Parcel parcel) {
            path = parcel.readString();
            isCamera = parcel.readByte() != 0;
        }
    }

【讨论】:

  • 您不应该将此作为答案发布。您的代码中不涉及 BitmapFactory。那么为什么要发布这样的错误呢?您的代码中的 ImageInfo、Bar 和 addNotification 是什么?请坚持使用您的转移代码。您甚至没有记录并告诉我们 'ext'、len 和文件长度的值是否正确。
  • @greenapps 我在回答中回答了你的问题,请看。
  • 在谈论 ImageInfo、Bar 和 addNotification 时,我仍然没有看到任何相关性。在您的设备上安装一个文件资源管理器应用程序。浏览到保存图像的目录。然后让 Explorer 应用程序打开或共享图片。您在资源管理器中看到缩略图了吗?文件可以被外部应用程序显示吗?先检查isf图片是否保存好。
  • 文件存在,但我也看不到缩略图。我看到的总是一个黑色/空文件。
  • 所以传输是错误的。 ImageInfo、Bar 和 addNotification 不用多说
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-25
  • 2014-08-26
  • 1970-01-01
  • 2012-09-07
  • 1970-01-01
  • 2023-03-05
  • 2012-07-12
相关资源
最近更新 更多