Bạn đang có ý tưởng về một ứng dụng chia sẻ ảnh với rất nhiều người. Để bắt đầu ý tưởng này có lẽ chúng ta cần bắt đầu từ việc tạo một ứng dụng upload ảnh lên server.
Có nhiều cách để upload hình ảnh hay bất kỳ một file nào từ Android lên Server. Nếu bạn mới học lập trình android thì nghĩ rằng làm ứng dụng kiểu này sẽ rất khó. Vì bạn sẽ phải lập trình cả phía server nữa?
Thực ra cũng không khó lắm đâu!
Hôm nay mình hướng dẫn các bạn tự xây dựng ứng dụng android có thể upload ảnh lên server, upload file trong PHP. Phía server sẽ được lập trình bằng ngôn ngữ PHP.
Upload ảnh lên server gồm những công đoạn:
- Chọn ảnh từ thư viện hình ảnh của điện thoại.
- Tiến hành mã hóa hình ảnh dưới dạng Base64.
- Gửi hình ảnh đã mã hóa lên server theo phương thức POST.
- Server sẽ nhận hình ảnh đã mã hóa đó.
- Giải mã hình ảnh và lưu lại trên server.
Chúng ta bắt đầu thôi!
Nội dung chính của bài viết
#Xây dựng ứng dụng android upload ảnh lên server
Nói tổng thể, chúng ta sẽ cần phải xây dựng hai ứng dụng: Ứng dụng phía client(chính là ứng dụng android), và ứng dụng trên server(viết bằng PHP).
Đầu tiên, chúng ta bắt tay vào code ứng dụng Android trước nhé.
Trong ứng dụng này, để tải hình ảnh lên server, mình sử dụng thư viện Retrofit. Các bạn thêm dependencies của Retrofit vào build.gradle
implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
Ứng dụng của chúng ta sẽ có giao diện như sau:
Tạo layout ứng dụng để upload ảnh lên server
Để tạo được layout như demo, các bạn tạo file activity_main.xml như bên dưới:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="200dp" android:contentDescription="@null" android:scaleType="centerCrop" /> <LinearLayout style="?android:attr/buttonBarStyle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" android:weightSum="2"> <Button android:id="@+id/selectImageButton" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="10dp" android:layout_weight="1" android:text="@string/select_image" tools:ignore="ButtonStyle" /> <Button android:id="@+id/uploadImageButton" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/select_image" tools:ignore="ButtonStyle" /> </LinearLayout> </RelativeLayout>
Tạo tính năng chọn ảnh
Trong MainActivity khi người dùng click chọn nút selectImage, Gallery của ứng dụng sẽ được mở ra và bạn có thể lựa chọn hình ảnh.
Dưới đây là phần code khi người dùng nhấn nút selectImage.
findViewById<Button>(R.id.selectImageButton).setOnClickListener { val intent = Intent( Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI) startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST_CODE) }
Khi người dùng chọn xong hình ảnh từ Gallery kết quả sẽ xuất hiện trong hàm onActivityResult()
.
Dưới đây là hàm onActivityResult()
của MainActivity.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_IMAGE_REQUEST_CODE && RESULT_OK == resultCode) { data?.let { try { bitmap = uiHelper.decodeUri(this, it.data) imageView.setImageBitmap(bitmap) } catch (e: Exception) { if (bitmap != null) imageView.setImageBitmap(bitmap) } } } }
Sau khi người dùng đã chọn hình ảnh, hàm onActivityResult()
sẽ được gọi. Do vậy, chúng ta phải lưu trữ hình ảnh dưới dạng Bitmap trong global bitmap object.
>> Tham khảo thêm về onActivityResult: Tìm hiểu Activity trong Android – Cách tạo và sử dụng
Trước khi tiến hành bước tiếp theo chúng ta phải decode hình ảnh bằng hàm decodeUri để nhận kết quả từ bitmap.
Dưới đây là hàm decodeUri()
@Throws(FileNotFoundException::class) fun decodeUri(context: Context, selectedImage: Uri): Bitmap { val o = BitmapFactory.Options() o.inJustDecodeBounds = true BitmapFactory.decodeStream(context.contentResolver.openInputStream(selectedImage), null, o) val REQUIRED_SIZE = 140 var width_tmp = o.outWidth var height_tmp = o.outHeight var scale = 1 while (true) { if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) { break } width_tmp /= 2 height_tmp /= 2 scale *= 2 } val o2 = BitmapFactory.Options() o2.inSampleSize = scale return BitmapFactory.decodeStream(context.contentResolver.openInputStream(selectedImage), null, o2) }
Tạo tính năng upload ảnh lên server
Vậy là, chúng ta chọn hình ảnh và lưu chúng trong bitmap object. Giờ chỉ cần upload hình ảnh khi người dùng nhấn nút “Upload Image”.
findViewById<Button>(R.id.uploadImageButton).setOnClickListener { if (bitmap != null) { val imageBytes = uiHelper.getImageBytes(bitmap!!) uploadImage(imageBytes) } else Toast.makeText(this, "No image selected", Toast.LENGTH_SHORT).show() }
Để tải hình ảnh lên, đầu tiên chúng ta phải kiểm tra xem người dùng đã chọn hình ảnh chưa.
Sau đó, chúng ta cần chuyển bitmap vào trong Base64 ByteArray.
cuối cùng là tải ảnh lên server. Dưới đây là hàm getImageBytes.
fun getImageUrl(bitmap: Bitmap): String { val byteArrayOutputStream = ByteArrayOutputStream() bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream) val bytes = byteArrayOutputStream.toByteArray() return Base64.encodeToString(bytes, Base64.DEFAULT) }
Các công đoạn chuẩn bị đã xong. Giờ là lúc tải hình ảnh lên server.
Dưới đây là hàm uploadImage.
private fun uploadImage(imageBytes: String) { ServiceApi.Factory.getInstance(this).uploadImage(imageBytes) .enqueue(object : Callback<StatusMessageResponse> { override fun onFailure(call: Call<StatusMessageResponse>?, t: Throwable?) { Toast.makeText(MainActivity.this,"Image uploaded",Toast.LENGTH_SHORT).show() // Image uploaded successfully } override fun onResponse(call: Call<StatusMessageResponse>?, response: Response<StatusMessageResponse>?) { // Error Occurred during uploading } }) }
ServerApi là một instance của interface Retrofit. Dưới đây là lớp ServerApi.
interface ServiceApi { companion object { private const val BASE_URL = "" // Base url of your hosting } @FormUrlEncoded @POST("") // end_point url fun uploadImage(@Field("image_bytes") imageBytes: String): Call<StatusMessageResponse> class Factory { companion object { private var service: ServiceApi? = null fun getInstance(context: Context): ServiceApi? { if (service == null) { val builder = OkHttpClient().newBuilder() builder.readTimeout(15, TimeUnit.SECONDS) builder.connectTimeout(15, TimeUnit.SECONDS) builder.writeTimeout(15, TimeUnit.SECONDS) if (BuildConfig.DEBUG) { val interceptor = HttpLoggingInterceptor() interceptor.level = HttpLoggingInterceptor.Level.BODY builder.addInterceptor(interceptor) } val file = File(context.cacheDir, "cache_dir") if (!file.exists()) file.mkdirs() val cacheSize: Long = 10 * 1024 * 1024 // 10 MiB val cache = okhttp3.Cache(file, cacheSize) builder.cache(cache) val retrofit: Retrofit retrofit = Retrofit.Builder() .client(builder.build()) .addConverterFactory(GsonConverterFactory.create()) .baseUrl(BASE_URL) .build() service = retrofit.create(ServiceApi::class.java) return service } else { return service } } } } }
Trong bài viết này, mình sẽ không hướng dẫn chi tiết cách sử dụng thư viện Retrofit. Bạn có thể tìm hiểu về Retrofit từ bài viết này: Kết nối rest API bằng Retrofit trong Android
Với Retrofit, mỗi request đều là HTTP bất đồng bộ, điều này giúp ứng dụng của bạn không bị “treo” khi thực hiện upload.
#Tạo ứng dụng phía server(PHP)
Phía server, mình không xử lý nhiều, chỉ đơn giản là nhận ảnh và lưu lại.
// receive image as POST Parameter $image = str_replace('data:image/png;base64,', '', $_POST['image']); $image = str_replace(' ', '+', $image); // Decode the Base64 encoded Image $data = base64_decode($image); // Create Image path with Image name and Extension $file = '../images/' . "MyImage" . '.jpg'; // Save Image in the Image Directory $success = file_put_contents($file, $data);
Mình sẽ không hướng dẫn cách triển khai một ứng dụng PHP trên server ở bài viết này. Hẹn các bạn ở bài viết sau nhé( Nếu các bạn có hứng thú!)
#Tạm kết
Như vậy, mình đã hướng dẫn chi tiết cách tạo ứng dụng upload ảnh lên server với PHP.
Mình hi vọng, qua bài viết này, các bạn có thể tự phát triển nó thành một ứng dụng hoàn chỉnh hơn, với nhiều tính năng cao cấp hơn. Tất cả đang chờ bạn.
Bạn có thể lấy source code hoàn chỉnh của ứng dụng trên từ GitHub.
Đừng quên để lại bình luận về ý kiến của bạn ở bên dưới nhé.
bài này viết bằng code java thì sướng biết mấy. Ngôn ngữ này đọc không quen !
Hi Thoa,
Làm quen dần với Kotlin đi bạn, vì sớm hay muộn thì các dự án mới sẽ dùng Kotlin thay cho Java. Có các dự án lớn cũ, đang maintance thì còn dùng Java thôi
bài viết hay quá bác Sơn Dương ơi, tiếp tục đăng bài hay nữa nhé bác
Cám ơn bạn nhiều nhé 🙂