1.CÁC BÀI VIẾT TRƯỚC
Trước khi bắt đầu bài viết các bạn chưa xem các bài viết trước có thể quay lại xem để hiểu hơn:
- Tìm Hiểu về Retrofit
- Sử dụng retrofit getdata
- Sử dụng retrofit post data
- Sử dụng retrofit upload image 1
Ở bài viết trước mình đã hướng dẫn cho các bạn một cách upload file sử dụng retrofit 2 tuy nhiên đó không phải cách theo document.
Hôm nay mình sẽ sử dụng cách chính thức đó là sử dụng Multipart để upload file.
2. Các thư viện sử dụng:
compile 'com.squareup.retrofit2:retrofit:2.0.2' compile 'com.squareup.retrofit2:converter-gson:2.0.2' compile 'com.jakewharton:butterknife:8.4.0' apt 'com.jakewharton:butterknife-compiler:8.4.0' compile 'com.github.bumptech.glide:glide:3.7.0'
3.Cấu trúc project:
4.Tạo giao diện upload:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:weightSum="1"> <Button android:text="@string/btnChoose" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnChoose" /> <TextView android:text="@string/title_multipart" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="24sp" android:layout_marginBottom="20dp" android:id="@+id/textView" /> <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" app:srcCompat="@mipmap/ic_launcher" android:id="@+id/imgMultipart" android:layout_weight="0.87" /> <Button android:text="@string/btnUpload" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnUpload" /> </LinearLayout>
5.Viết trang PHP để xử lý:
<?php require_once('dbConnect.php'); mysqli_set_charset($con,'utf8'); $response = array(); if($_SERVER['REQUEST_METHOD']=='POST') { $file_path = "upload/"; $file_path = $file_path . basename( $_FILES['uploaded_file']['name']); if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $file_path)) { $response["message"] = "Success"; } else{ $response["message"] = "Failed"; } echo json_encode($result); } ?>
6.Viết API
public interface FileUploadService { @Multipart @POST("upload.php") Call<Message> uploadImage(@Part MultipartBody.Part file); }
7.Tạo model nhận kết quả
public class Message { @SerializedName("message") private String message; //getter setter }
8.Tại Activity chính viết các hàm sau:
CheckPermistion
//Check permistion android 6.0 private void checkPermistion() { if (ContextCompat.checkSelfPermission(MultipartUpload.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale(MultipartUpload.this, Manifest.permission.READ_EXTERNAL_STORAGE)) { } else { ActivityCompat.requestPermissions(MultipartUpload.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1); } } }
9.Hàm lấy ảnh trong thư viện:
Khai báo biến:
String IMAGE_PATH; private String UPLOAD_URL ="http://dev.androidcoban.com/blog/";
Code gọi Intent nhận dữ liệu:
@OnClick(R.id.btnChoose) public void chooseImage(){ checkPermistion(); Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivityForResult(intent, 0); }
Nhận dữ liệu intent
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 0 && resultCode == MultipartUpload.this.RESULT_OK) { IMAGE_PATH = ReadPathUtil.getPath(MultipartUpload.this, data.getData()); Uri uri = Uri.fromFile(new File(IMAGE_PATH)); // Load image Glide.with(MultipartUpload.this).load(uri).override(420, 594).centerCrop().into(imageView); Toast.makeText(this, IMAGE_PATH, Toast.LENGTH_LONG).show(); } }
10.Lớp util ReadPathUtil.java
public class ReadPathUtil { /// get path API >19 KITKAT public static String getPath(final Context context, final Uri uri) { // DocumentProvider if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + "/" + split[1]; } // TODO handle non-primary volumes } // DownloadsProvider else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); } // MediaProvider else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final String selection = "_id=?"; final String[] selectionArgs = new String[] { split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme())) { return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } /** * Get the value of the data column for this Uri. This is useful for * MediaStore Uris, and other file-based ContentProviders. * * @param context The context. * @param uri The Uri to query. * @param selection (Optional) Filter used in the query. * @param selectionArgs (Optional) Selection arguments used in the query. * @return The value of the _data column, which is typically a file path. */ public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { Cursor cursor = null; final String column = "_data"; final String[] projection = { column }; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { final int column_index = cursor.getColumnIndexOrThrow(column); return cursor.getString(column_index); } } finally { if (cursor != null) cursor.close(); } return null; } /** * @param uri The Uri to check. * @return Whether the Uri authority is ExternalStorageProvider. */ public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } /** * @param uri The Uri to check. * @return Whether the Uri authority is DownloadsProvider. */ public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } /** * @param uri The Uri to check. * @return Whether the Uri authority is MediaProvider. */ public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } }
11.Viết hàm upload dữ liệu:
@OnClick(R.id.btnUpload) public void UploadImage(){ final ProgressDialog progressDialog; progressDialog = new ProgressDialog(MultipartUpload.this); progressDialog.setMessage(getString(R.string.string_title_upload_progressbar_)); progressDialog.show(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(UPLOAD_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); FileUploadService service = retrofit.create(FileUploadService.class); File file = new File(IMAGE_PATH); // create RequestBody instance from file RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); // MultipartBody.Part is used to send also the actual file name MultipartBody.Part body = MultipartBody.Part.createFormData("uploaded_file", file.getName(), requestFile); Call<Message> call = service.uploadImage(body); call.enqueue(new Callback<Message>() { @Override public void onResponse(Call<Message> call, Response<Message> response) { progressDialog.dismiss(); Message message = response.body(); if (message.getMessage().equals("Success")) { Toast.makeText(MultipartUpload.this, R.string.string_upload_success, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MultipartUpload.this, R.string.string_upload_fail, Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(Call<Message> call, Throwable t) { progressDialog.dismiss(); Log.e(TAG, t.toString()); } }); }
Công đoạn cuối cùng là, tiến hành upload file php lên server. build app.
Chúc các bạn thành công!