问题
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);
}
}
来源:https://stackoverflow.com/questions/39063289/no-such-file-or-diectory-error-in-image-file-upload-using-retrofit-in-android