将图像上传到服务器:卡在 FileInputStream

Uploading an image to a server: stuck at FileInputStream

我正在尝试将图像上传到服务器,但不知为何代码停在了 FileInputStream 行。不知道为什么,我不知道如何调试或检查它。这是我的源代码:

 public class CreateSetcardStep1Activity extends AppCompatActivity {

    @Override
    protected void onCreate(final Bundle savedInstanceState) {


        String filename = appHelper.dateToString(new Date(), "yyyyMMdd-hhmmss");
        destination = new File(Environment.getExternalStorageDirectory(), filename + ".jpg");

        buttonTakePhoto.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(destination));
                startActivityForResult(intent, REQUEST_IMAGE);
            }
        });

        buttonSubmitPhoto.setVisibility(View.GONE);
        buttonSubmitPhoto.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                dialog = ProgressDialog.show(CreateSetcardStep1Activity.this, "", "Uploading file...", true);

                new Thread(new Runnable() {
                    public void run() {
                        uploadFile(imagePath);
                    }
                }).start();
            }
        });


    }

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

        if (requestCode == REQUEST_IMAGE && resultCode == Activity.RESULT_OK) {
            try {
                buttonSubmitPhoto.setVisibility(View.VISIBLE);
                Log.e(LOG, "breakpoint 1");
                setcardPic.setVisibility(View.VISIBLE); Log.e(LOG, "breakpoint 2 destination: "+destination);
                FileInputStream in = new FileInputStream(destination); Log.e(LOG, "breakpoint 3");
                BitmapFactory.Options options = new BitmapFactory.Options(); Log.e(LOG, "breakpoint 4");
                options.inSampleSize = 10; Log.e(LOG, "breakpoint 5");
                imagePath = destination.getAbsolutePath(); Log.e(LOG, "breakpoint 6 imagePath: "+imagePath);
                Log.e(LOG, "PATH === " + imagePath);
                //tvPath.setText(imagePath);
                Bitmap bmp = BitmapFactory.decodeStream(in, null, options);
                setcardPic.setImageBitmap(bmp);
                showUploadButton = true;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }

        } else {
            showUploadButton = false;
            Toast.makeText(getApplicationContext(),
                    R.string.request_cancelled,
                    Toast.LENGTH_LONG).show();
        }
    }

    public int uploadFile(String sourceFileUri) {

        String fileName = sourceFileUri;
        showUploadButton = false; //revert upload button to hidden
        HttpURLConnection conn = null;
        DataOutputStream dos = null;
        String lineEnd = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";
        int bytesRead, bytesAvailable, bufferSize;
        byte[] buffer;
        int maxBufferSize = 1024 * 1024;
        File sourceFile = new File(sourceFileUri);

        if (!sourceFile.isFile()) {
            dialog.dismiss();
            Log.e(LOG, "Source File not exist :" +imagePath);
            return 0;
        }
        else
        {
            try {

                // open a URL connection to the Servlet
                FileInputStream fileInputStream = new FileInputStream(sourceFile);
                URL url = new URL(upLoadServerUri);

                // Open a HTTP  connection to  the URL
                conn = (HttpURLConnection) url.openConnection();
                conn.setDoInput(true); // Allow Inputs
                conn.setDoOutput(true); // Allow Outputs
                conn.setUseCaches(false); // Don't use a Cached Copy
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Connection", "Keep-Alive");
                conn.setRequestProperty("ENCTYPE", "multipart/form-data");
                conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
                conn.setRequestProperty("Filedata", fileName);

                dos = new DataOutputStream(conn.getOutputStream());

                dos.writeBytes(twoHyphens + boundary + lineEnd);
                dos.writeBytes("Content-Disposition: form-data; name=\"uploaded_file\";filename="+ fileName + "" + lineEnd);
                dos.writeBytes(lineEnd);

                // create a buffer of  maximum size
                bytesAvailable = fileInputStream.available();

                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                buffer = new byte[bufferSize];

                // read file and write it into form...
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);

                while (bytesRead > 0) {

                    dos.write(buffer, 0, bufferSize);
                    bytesAvailable = fileInputStream.available();
                    bufferSize = Math.min(bytesAvailable, maxBufferSize);
                    bytesRead = fileInputStream.read(buffer, 0, bufferSize);

                }

                // send multipart form data necesssary after file data...
                dos.writeBytes(lineEnd);
                dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

                // Responses from the server (code and message)
                serverResponseCode = conn.getResponseCode();
                String serverResponseMessage = conn.getResponseMessage();

                Log.i(LOG, "HTTP Response is : "+ serverResponseMessage + ": " + serverResponseCode);

                if(serverResponseCode == 200){

                    runOnUiThread(new Runnable() {
                        public void run() {

                            Toast.makeText(CreateSetcardStep1Activity.this, "File Upload Complete.",
                                    Toast.LENGTH_SHORT).show();
                        }
                    });
                }

                //close the streams //
                fileInputStream.close();
                dos.flush();
                dos.close();

            } catch (MalformedURLException ex) {

                dialog.dismiss();
                ex.printStackTrace();

                runOnUiThread(new Runnable() {
                    public void run() {

                        Toast.makeText(CreateSetcardStep1Activity.this, "MalformedURLException",
                                Toast.LENGTH_SHORT).show();
                    }
                });

                Log.e(LOG, "error: " + ex.getMessage(), ex);
            } catch (Exception e) {

                dialog.dismiss();
                e.printStackTrace();

                runOnUiThread(new Runnable() {
                    public void run() {

                        Toast.makeText(CreateSetcardStep1Activity.this, "Got Exception : see logcat ",
                                Toast.LENGTH_SHORT).show();
                    }
                });
                Log.e(LOG, "Exception : "
                        + e.getMessage(), e);
            }
            dialog.dismiss();
            return serverResponseCode;

        }
    }
}

有什么方法可以检查问题出在哪里? logcat 在断点 2 处停止:断点 2 目的地:/storage/emulated/0/20171215-051851.jpg 所以如果我检查资源管理器,文件就在那里

您好,请先检查清单文件中的权限(如读取外部、写入外部和摄像头,如果使用),然后将运行时权限代码放入 Greater then Marshmallow devices.And 使用文件提供程序从 SD 卡获取图像 URI .

并将以下代码放入 onActivityResult()。

                 if (mPhotouri != null) {
                    try {
                        mBitmap = MediaStore.Images.Media.getBitmap(
                                getContentResolver(), mPhotouri);
                        Uri tempUri = getImageUri(this, mBitmap);
                        finalFile = new File(getRealPathFromURI(tempUri, this));
                        mSelectedImagePath = finalFile.getAbsolutePath();

                        if (mSelectedImagePath != null)
                            mFileSelectedImage = new File(mSelectedImagePath);

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

public static Uri getImageUri(Activity inContext, Bitmap inImage) {

        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
        String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
        return Uri.parse(path);
    }

public static String getRealPathFromURI(Uri uri, Activity signupActivity) {
    Cursor cursor = signupActivity.getContentResolver().query(uri, null, null, null, null);
    cursor.moveToFirst();
    int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
    return cursor.getString(idx);
}

希望对您有所帮助。

将此添加到您的 AndroidManifest.xml:

<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" />

对于 api 23+,请阅读本教程:

Runtime Permissions

发生这种情况是因为您没有请求 EXTERNAL_STORAGE 许可。

从 android API 23 级(棉花糖)开始,android 权限框架(我不知道这是否是正确的术语)已经改变。

在使用 marshmallow 之前,您只需在清单文件中声明权限即可。但是在 marshmallow 之上,android 权限被归类为 Normal permissions and Dangerous permissions。如果您使用的是普通权限,那么所有 android 版本都是一样的。但是如果你使用了危险的权限,你必须请求用户在运行时授予该权限

在您的情况下,您正在上传一张图片,这需要 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限。这些被归类为危险权限。因此,您必须在执行任何需要这些权限的操作之前请求这些权限。

但是您不必分别请求这两个权限,因为这些权限属于一个 permission group

来自官方文档,

If an app requests a dangerous permission listed in its manifest, and the app already has another dangerous permission in the same permission group, the system immediately grants the permission without any interaction with the user..

即,如果您已经声明了对单个权限组的几个权限,则您只需请求其中一个权限。如果用户授予该权限组的权限,则系统将授予您声明的所有在同一权限组中的权限。

这是请求存储权限的代码

private static final int STORAGE_REQ_ID=3465;

if (ContextCompat.checkSelfPermission(CreateSetcardStep1Activity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
            {

                if (ActivityCompat.shouldShowRequestPermissionRationale(CreateSetcardStep1Activity.this,
                        Manifest.permission.READ_EXTERNAL_STORAGE)) {

                    //THIS CONDITION WORKS WHEN WE ARE REQUSETING PERMISSION AGAIN SINCE USER DENIED PERMISSION ON PREVIOUS REQUEST(S)

                    ActivityCompat.requestPermissions(CreateSetcardStep1Activity.this,
                                new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                                STORAGE_REQ_ID);

                } else {

                    //REQUESTING PERMISSION FOR FIRST TIME, EXPLAIN WHY THE APPLICATION NEED PERMISSION

                    AlertDialog.Builder builder = new AlertDialog.Builder(CreateSetcardStep1Activity.this);
                    builder.setTitle("Permission Request");
                    builder.setMessage("To upload image, Application need External storage permission");
                    builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            ActivityCompat.requestPermissions(CreateSetcardStep1Activity.this,
                                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                                    STORAGE_REQ_ID);
                        }
                    });
                    builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                        }
                    });
                    AlertDialog dialog = builder.create();
                    dialog.show();
                    ActivityCompat.requestPermissions(CreateSetcardStep1Activity.this,
                            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                           STORAGE_REQ_ID);
                }
            }
            else startImageCapture();
        }

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {

//HERE YOU HANDLE PERMISSION REQUEST RESULTS
    switch (requestCode) {
        case STORAGE_REQ_ID: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                //PERMISSION GRANTED!!
                startImageCapture();

            } else {

                //USER DENIED PERMISSION, NOTIFY THE USER THAT PERMISSION IS DENIED, MAY BE A TOAST?

            }
            return;
        }

    }
}


private void startImageCapture(){
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(destination));
    startActivityForResult(intent, REQUEST_IMAGE);
}

其他的都差不多。 (抱歉我的英语不好)

有关权限请求的更多信息here