No such file or diectory error in image file uploa

2019-09-10 12:53发布

问题:

I am developing an Android app. In my app, I am using Retrofit to upload image and pdf files to server in multipart/form-data request. I am new to Retrofit.

I uploaded pdf file and other string data successfully. But when I upload Image file, it is giving me "No such file or directory" exception even I did the same thing as PDF file that is successfully uploaded.

This is my activity upload pdf file and image file

public class ContributeActivity extends AppCompatActivity {

    public static final int SELECT_PICTURE = 2334;
    public static final int SELECT_BOOK  = 123;

    //other properties
    private File bookFile;
    private File imageFile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        app = (AppSingleton)getApplication();
        app.initialize();
        setContentView(R.layout.activity_contribute);
        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        //do other steps
    }

    private void saveBtnClick()
    {
        contributeBook();
    }

    private void openImagePicker()
    {
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURE);
    }

    private void setUpFilePickerImage()
    {
        ivBookFile.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                openBookFilePicker();
            }
        });
    }

    private void openBookFilePicker()
    {
        Intent intent = new Intent();
        intent.setType("*/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(intent, "Select file"), SELECT_BOOK);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            if (requestCode == SELECT_PICTURE) {
                Uri selectedImageUri = data.getData();
                if(selectedImageUri!=null)
                {
                    try{
                        bmpCoverImage = MediaStore.Images.Media.getBitmap(getContentResolver(), selectedImageUri);
                        imageFile = new File(selectedImageUri.getPath());
                        if(bmpCoverImage!=null)
                        {
                            ivCoverImage.setImageBitmap(bmpCoverImage);
                        }
                    }
                    catch (IOException e)
                    {
                        Toast.makeText(getBaseContext(),"An error occurred with the file selected",Toast.LENGTH_SHORT).show();
                    }
                }
            }
            else if(requestCode==SELECT_BOOK)
            {
                Uri bookUri = data.getData();
                if(bookUri!=null)
                {
                    String filePath = bookUri.toString();//bookUri.toString()
                    String mime = app.getMimeType(filePath);
                    if(mime!=null && !mime.isEmpty() && (mime.toLowerCase()=="application/pdf" || mime.toLowerCase()=="application/txt" || mime.toLowerCase()=="application/text"))
                    {
                        bookFile = new File(bookUri.getPath());
                        ivBookFile.setImageResource(R.drawable.book_selected);
                    }
                    else{
                        Toast.makeText(getBaseContext(),"Unable to process file you have chosen.",Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    }

    private Boolean validateForm()
    {

        // do validation
        return true;
    }

    private void contributeBook()
    {
        RetrofitService service = RetrofitClient.retrofit.create(RetrofitService.class);
        MultipartBody.Part bodyBookFile = null;
        if(bookFile!=null)
        {
            RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), bookFile);
            bodyBookFile = MultipartBody.Part.createFormData("book_file", bookFile.getName(), requestFile);
        }

        MultipartBody.Part bodyImageFile = null;
        if(imageFile!=null)
        {
            RequestBody requestImageFile = RequestBody.create(MediaType.parse("multipart/form-data"), imageFile);
            bodyImageFile = MultipartBody.Part.createFormData("image_file",imageFile.getName(),requestImageFile);
        }

        RequestBody title = RequestBody.create(MediaType.parse("multipart/form-data"), tfTitle.getText().toString());
        RequestBody mmTitle = RequestBody.create(MediaType.parse("multipart/form-data"), tfMmTitle.getText().toString());
        RequestBody parentId = RequestBody.create(MediaType.parse("multipart/form-data"),String.valueOf(selectedParentId));
        RequestBody childId = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(selectedChildId));
        RequestBody authorName = RequestBody.create(MediaType.parse("multipart/form-data"), tfAuthorName.getText().toString());
        RequestBody authorMmName = RequestBody.create(MediaType.parse("multipart/form-data"), tfAuthorMmName.getText().toString());
        RequestBody authToken = RequestBody.create(MediaType.parse("multipart/form-data"),app.getAuthToken());

        Call<ResponseBody> call = service.contributeBook(bodyImageFile,bodyBookFile,title,mmTitle,parentId,childId,authorName,authorMmName,authToken);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if(response!=null && response.isSuccessful())
                {
                    Toast.makeText(getBaseContext(),"Book successfully contributed. Thank you.",Toast.LENGTH_SHORT).show();
                }
                else if(response!=null && !response.isSuccessful() && response.errorBody()!=null)
                {
                    //server error
                    Toast.makeText(getBaseContext(),"Validation errors",Toast.LENGTH_SHORT).show();
                }
                else{
                    Toast.makeText(getBaseContext(),"An error occurred in server",Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Toast.makeText(getBaseContext(),t.getMessage(),Toast.LENGTH_SHORT).show();
            }
        });
    }
}

This is my retrofit service interface

public interface RetrofitService {
    @Multipart
    @POST("book/contribute")
    Call<ResponseBody> contributeBook(@Part MultipartBody.Part imageFile,@Part MultipartBody.Part bookFile,@Part("title") RequestBody title
    ,@Part("mm_title") RequestBody mmTitle,@Part("parent_category_id") RequestBody parentId,@Part("child_category_id") RequestBody childId
    ,@Part("author_name") RequestBody authorName,@Part("author_mm_name") RequestBody authorMmName,@Part("auth_token") RequestBody authToken);
}

This is my retrofit client class

public class RetrofitClient {
    //implementation starts - should be in different class
    public static final Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(LinkConfig.API_END_POINT)
            .client(RetrofitClient.httpClient())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    public static OkHttpClient httpClient()
    {
        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Interceptor.Chain chain) throws IOException {
                Request original = chain.request();

                Request request = original.newBuilder()
                        .header(AppSingleton.API_KEY_FIELD, AppSingleton.API_KEY)
                        .method(original.method(), original.body())
                        .build();

                return chain.proceed(request);
            }
        });
        return httpClient.build();
    }
}

With the above code, I send pdf file with other string fields but without image file field. Everything worked fine. PDF file successfully uploaded to server and data are saved in the database. But when I chose the image file and submit data to server, it gives me following error in error listener of retrofit.

I got that error before when I first upload pdf file. I have to change as in activity result after choosing file.

From

uri.toString()

To

uri.getPath()

But as you can see, I did the same thing to both PDF file and Image file in activity result. But PDF file is working well and image file is giving me error.

These are permissions set in manifest file

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

回答1:

If your device Version Is more then Api Level  22, then ask for permission at runtime, i also face the same problem, try to check permission at run time

  private static final int REQUEST_EXTERNAL_STORAGE = 3;
    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };


public  void checkStoragePermissions(Activity activity,Intent intent) {
        // Check if we have write permission
        int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

        if (permission != PackageManager.PERMISSION_GRANTED) {
            // We don't have permission so prompt the user
            ActivityCompat.requestPermissions(
                    activity,
                    PERMISSIONS_STORAGE,
                    REQUEST_EXTERNAL_STORAGE
            );
        }else{
            activity.startActivity(intent);
        }
    }