├── Android-File-Upload-Tutorial ├── .gitignore ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── hellohasan │ │ │ └── android_file_upload_tutorial │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── hellohasan │ │ │ │ └── android_file_upload_tutorial │ │ │ │ ├── MainActivity.java │ │ │ │ ├── ModelClass │ │ │ │ ├── EventModel.java │ │ │ │ ├── ImageSenderInfo.java │ │ │ │ └── ResponseModel.java │ │ │ │ └── NetworkRelatedClass │ │ │ │ ├── ApiInterface.java │ │ │ │ ├── NetworkCall.java │ │ │ │ └── RetrofitApiClient.java │ │ └── res │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── hellohasan │ │ └── android_file_upload_tutorial │ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── Data └── image-upload-to-server-android-retrofit.gif ├── README.md └── file_upload_api ├── files └── images (1).jpeg └── upload.php /Android-File-Upload-Tutorial/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.hellohasan.android_file_upload_tutorial" 7 | minSdkVersion 15 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | compileOptions { 20 | sourceCompatibility JavaVersion.VERSION_1_8 21 | targetCompatibility JavaVersion.VERSION_1_8 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation fileTree(dir: 'libs', include: ['*.jar']) 27 | androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | implementation 'androidx.appcompat:appcompat:1.1.0' 31 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 32 | testImplementation 'junit:junit:4.12' 33 | 34 | // networking library 35 | implementation 'com.squareup.okhttp3:okhttp:3.14.2' 36 | implementation 'com.squareup.retrofit2:retrofit:2.5.0' 37 | implementation 'com.squareup.retrofit2:converter-gson:2.5.0' 38 | 39 | // JSON parsing, serialize-deserialize 40 | implementation 'com.google.code.gson:gson:2.8.6' 41 | 42 | // pretty logger 43 | implementation 'com.orhanobut:logger:2.2.0' 44 | 45 | // image loading and caching 46 | implementation 'com.squareup.picasso:picasso:2.71828' 47 | 48 | // event publish/subscribe 49 | implementation 'org.greenrobot:eventbus:3.1.1' 50 | } 51 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/hasan/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/androidTest/java/com/hellohasan/android_file_upload_tutorial/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.hellohasan.android_file_upload_tutorial; 2 | 3 | import android.content.Context; 4 | import androidx.test.platform.app.InstrumentationRegistry; 5 | import androidx.test.ext.junit.runners.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.hellohasan.android_file_upload_tutorial", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/main/java/com/hellohasan/android_file_upload_tutorial/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.hellohasan.android_file_upload_tutorial; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.content.Intent; 6 | import android.content.pm.PackageManager; 7 | import android.database.Cursor; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.provider.MediaStore; 11 | import androidx.core.app.ActivityCompat; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | import android.view.View; 14 | import android.widget.Button; 15 | import android.widget.EditText; 16 | import android.widget.ImageView; 17 | import android.widget.TextView; 18 | 19 | import com.hellohasan.android_file_upload_tutorial.ModelClass.EventModel; 20 | import com.hellohasan.android_file_upload_tutorial.ModelClass.ImageSenderInfo; 21 | import com.hellohasan.android_file_upload_tutorial.NetworkRelatedClass.NetworkCall; 22 | 23 | import org.greenrobot.eventbus.EventBus; 24 | import org.greenrobot.eventbus.Subscribe; 25 | import org.greenrobot.eventbus.ThreadMode; 26 | 27 | public class MainActivity extends AppCompatActivity { 28 | 29 | // if you want to upload only image, make it true. Otherwise to allow any file- false 30 | boolean isOnlyImageAllowed = true; 31 | 32 | private EditText nameEditText; 33 | private EditText ageEditText; 34 | private ImageView imageView; 35 | private Button uploadButton; 36 | private TextView responseTextView; 37 | 38 | private String filePath; 39 | private static final int PICK_PHOTO = 1958; 40 | private static final int REQUEST_EXTERNAL_STORAGE = 1; 41 | private static String[] PERMISSIONS_STORAGE = { 42 | Manifest.permission.WRITE_EXTERNAL_STORAGE 43 | }; 44 | 45 | @Subscribe(threadMode = ThreadMode.MAIN) 46 | public void onEvent(EventModel event) throws ClassNotFoundException { 47 | if (event.isTagMatchWith("response")) { 48 | String responseMessage = "Response from Server:\n" + event.getMessage(); 49 | responseTextView.setText(responseMessage); 50 | } 51 | } 52 | 53 | @Override 54 | protected void onCreate(Bundle savedInstanceState) { 55 | super.onCreate(savedInstanceState); 56 | setContentView(R.layout.activity_main); 57 | 58 | nameEditText = findViewById(R.id.nameEditText); 59 | ageEditText = findViewById(R.id.ageEditText); 60 | imageView = findViewById(R.id.imageView); 61 | uploadButton = findViewById(R.id.uploadButton); 62 | responseTextView = findViewById(R.id.responseTextView); 63 | 64 | verifyStoragePermissions(this); 65 | } 66 | 67 | public void addPhoto(View view) { 68 | 69 | Intent intent; 70 | 71 | if (isOnlyImageAllowed) { 72 | // only image can be selected 73 | intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 74 | } else { 75 | // any type of files including image can be selected 76 | intent = new Intent(Intent.ACTION_GET_CONTENT); 77 | intent.setType("file/*"); 78 | } 79 | 80 | startActivityForResult(intent, PICK_PHOTO); 81 | } 82 | 83 | @Override 84 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 85 | super.onActivityResult(requestCode, resultCode, data); 86 | if (resultCode == RESULT_OK && requestCode == PICK_PHOTO) { 87 | Uri imageUri = data.getData(); 88 | filePath = getPath(imageUri); 89 | imageView.setImageURI(imageUri); 90 | uploadButton.setVisibility(View.VISIBLE); 91 | } 92 | } 93 | 94 | public void uploadButtonClicked(View view) { 95 | String name = nameEditText.getText().toString(); 96 | int age = Integer.parseInt(ageEditText.getText().toString()); 97 | NetworkCall.fileUpload(filePath, new ImageSenderInfo(name, age)); 98 | } 99 | 100 | private String getPath(Uri uri) { 101 | String[] projection = { MediaStore.Images.Media.DATA }; 102 | Cursor cursor = managedQuery(uri, projection, null, null, null); 103 | int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 104 | cursor.moveToFirst(); 105 | return cursor.getString(column_index); 106 | } 107 | 108 | @Override 109 | public void onStart() { 110 | super.onStart(); 111 | EventBus.getDefault().register(this); 112 | } 113 | 114 | @Override 115 | public void onStop() { 116 | EventBus.getDefault().unregister(this); 117 | super.onStop(); 118 | } 119 | 120 | /** 121 | * Checks if the app has permission to write to device storage 122 | * 123 | * If the app does not has permission then the user will be prompted to grant permissions 124 | */ 125 | public static void verifyStoragePermissions(Activity activity) { 126 | // Check if we have write permission 127 | int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); 128 | 129 | if (permission != PackageManager.PERMISSION_GRANTED) { 130 | // We don't have permission so prompt the user 131 | ActivityCompat.requestPermissions( 132 | activity, 133 | PERMISSIONS_STORAGE, 134 | REQUEST_EXTERNAL_STORAGE 135 | ); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/main/java/com/hellohasan/android_file_upload_tutorial/ModelClass/EventModel.java: -------------------------------------------------------------------------------- 1 | package com.hellohasan.android_file_upload_tutorial.ModelClass; 2 | 3 | public class EventModel { 4 | private String eventTag; 5 | private String message; 6 | 7 | public EventModel(String eventTag, String message) { 8 | this.eventTag = eventTag; 9 | this.message = message; 10 | } 11 | 12 | public boolean isTagMatchWith(String tag){ 13 | return eventTag.equals(tag); 14 | } 15 | 16 | public String getMessage() { 17 | return message; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/main/java/com/hellohasan/android_file_upload_tutorial/ModelClass/ImageSenderInfo.java: -------------------------------------------------------------------------------- 1 | 2 | package com.hellohasan.android_file_upload_tutorial.ModelClass; 3 | 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | 7 | import com.google.gson.annotations.SerializedName; 8 | 9 | public class ImageSenderInfo implements Parcelable { 10 | 11 | @SerializedName("sender_name") 12 | private String sender; 13 | @SerializedName("sender_age") 14 | private int age; 15 | 16 | public ImageSenderInfo() { 17 | } 18 | 19 | public ImageSenderInfo(String sender, int age) { 20 | this.sender = sender; 21 | this.age = age; 22 | } 23 | 24 | public final static Parcelable.Creator CREATOR = new Creator() { 25 | 26 | @SuppressWarnings({ 27 | "unchecked" 28 | }) 29 | public ImageSenderInfo createFromParcel(Parcel in) { 30 | ImageSenderInfo instance = new ImageSenderInfo(); 31 | instance.sender = ((String) in.readValue((String.class.getClassLoader()))); 32 | instance.age = ((int) in.readValue((int.class.getClassLoader()))); 33 | return instance; 34 | } 35 | 36 | public ImageSenderInfo[] newArray(int size) { 37 | return (new ImageSenderInfo[size]); 38 | } 39 | 40 | }; 41 | 42 | 43 | public void writeToParcel(Parcel dest, int flags) { 44 | dest.writeValue(sender); 45 | dest.writeValue(age); 46 | } 47 | 48 | public int describeContents() { 49 | return 0; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/main/java/com/hellohasan/android_file_upload_tutorial/ModelClass/ResponseModel.java: -------------------------------------------------------------------------------- 1 | 2 | package com.hellohasan.android_file_upload_tutorial.ModelClass; 3 | 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | 7 | import com.google.gson.annotations.SerializedName; 8 | 9 | public class ResponseModel implements Parcelable 10 | { 11 | 12 | @SerializedName("success") 13 | private boolean success; 14 | @SerializedName("message") 15 | private String message; 16 | public final static Parcelable.Creator CREATOR = new Creator() { 17 | 18 | 19 | @SuppressWarnings({ 20 | "unchecked" 21 | }) 22 | public ResponseModel createFromParcel(Parcel in) { 23 | ResponseModel instance = new ResponseModel(); 24 | instance.success = ((boolean) in.readValue((boolean.class.getClassLoader()))); 25 | instance.message = ((String) in.readValue((String.class.getClassLoader()))); 26 | return instance; 27 | } 28 | 29 | public ResponseModel[] newArray(int size) { 30 | return (new ResponseModel[size]); 31 | } 32 | 33 | }; 34 | 35 | /** 36 | * 37 | * @return 38 | * The success 39 | */ 40 | public boolean isSuccess() { 41 | return success; 42 | } 43 | 44 | /** 45 | * 46 | * @return 47 | * The message 48 | */ 49 | public String getMessage() { 50 | return message; 51 | } 52 | 53 | 54 | public void writeToParcel(Parcel dest, int flags) { 55 | dest.writeValue(success); 56 | dest.writeValue(message); 57 | } 58 | 59 | public int describeContents() { 60 | return 0; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/main/java/com/hellohasan/android_file_upload_tutorial/NetworkRelatedClass/ApiInterface.java: -------------------------------------------------------------------------------- 1 | package com.hellohasan.android_file_upload_tutorial.NetworkRelatedClass; 2 | 3 | import com.hellohasan.android_file_upload_tutorial.ModelClass.ResponseModel; 4 | 5 | import okhttp3.MultipartBody; 6 | import okhttp3.RequestBody; 7 | import retrofit2.Call; 8 | import retrofit2.http.Multipart; 9 | import retrofit2.http.POST; 10 | import retrofit2.http.Part; 11 | 12 | 13 | public interface ApiInterface { 14 | 15 | @Multipart 16 | @POST("file_upload_api/upload.php") 17 | Call fileUpload( 18 | @Part("sender_information") RequestBody description, 19 | @Part MultipartBody.Part file); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/main/java/com/hellohasan/android_file_upload_tutorial/NetworkRelatedClass/NetworkCall.java: -------------------------------------------------------------------------------- 1 | package com.hellohasan.android_file_upload_tutorial.NetworkRelatedClass; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.google.gson.Gson; 6 | import com.hellohasan.android_file_upload_tutorial.ModelClass.EventModel; 7 | import com.hellohasan.android_file_upload_tutorial.ModelClass.ImageSenderInfo; 8 | import com.hellohasan.android_file_upload_tutorial.ModelClass.ResponseModel; 9 | import com.orhanobut.logger.AndroidLogAdapter; 10 | import com.orhanobut.logger.Logger; 11 | 12 | import org.greenrobot.eventbus.EventBus; 13 | 14 | import java.io.File; 15 | 16 | import okhttp3.MediaType; 17 | import okhttp3.MultipartBody; 18 | import okhttp3.RequestBody; 19 | import retrofit2.Call; 20 | import retrofit2.Callback; 21 | import retrofit2.Response; 22 | 23 | public class NetworkCall { 24 | 25 | public static void fileUpload(String filePath, ImageSenderInfo imageSenderInfo) { 26 | 27 | ApiInterface apiInterface = RetrofitApiClient.getClient().create(ApiInterface.class); 28 | Logger.addLogAdapter(new AndroidLogAdapter()); 29 | 30 | File file = new File(filePath); 31 | //create RequestBody instance from file 32 | RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); //allow image and any other file 33 | 34 | // MultipartBody.Part is used to send also the actual file name 35 | MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile); 36 | 37 | Gson gson = new Gson(); 38 | String patientData = gson.toJson(imageSenderInfo); 39 | 40 | RequestBody description = RequestBody.create(okhttp3.MultipartBody.FORM, patientData); 41 | 42 | // finally, execute the request 43 | Call call = apiInterface.fileUpload(description, body); 44 | call.enqueue(new Callback() { 45 | @Override 46 | public void onResponse(@NonNull Call call, @NonNull Response response) { 47 | Logger.d("Response: " + response); 48 | 49 | ResponseModel responseModel = response.body(); 50 | 51 | if(responseModel != null){ 52 | EventBus.getDefault().post(new EventModel("response", responseModel.getMessage())); 53 | Logger.d("Response code " + response.code() + 54 | " Response Message: " + responseModel.getMessage()); 55 | } else 56 | EventBus.getDefault().post(new EventModel("response", "ResponseModel is NULL")); 57 | } 58 | 59 | @Override 60 | public void onFailure(@NonNull Call call, @NonNull Throwable t) { 61 | Logger.d("Exception: " + t); 62 | EventBus.getDefault().post(new EventModel("response", t.getMessage())); 63 | } 64 | }); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/main/java/com/hellohasan/android_file_upload_tutorial/NetworkRelatedClass/RetrofitApiClient.java: -------------------------------------------------------------------------------- 1 | package com.hellohasan.android_file_upload_tutorial.NetworkRelatedClass; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import okhttp3.OkHttpClient; 9 | import retrofit2.Retrofit; 10 | import retrofit2.converter.gson.GsonConverterFactory; 11 | 12 | public class RetrofitApiClient { 13 | 14 | private static final String BASE_URL = "http://192.168.43.55/"; //IP of your localhost or live server 15 | 16 | private static Retrofit retrofit = null; 17 | 18 | private static Gson gson = new GsonBuilder() 19 | .setLenient() 20 | .create(); 21 | 22 | private RetrofitApiClient() {} // So that nobody can create an object with constructor 23 | 24 | public static synchronized Retrofit getClient() { 25 | if (retrofit==null) { 26 | 27 | int timeOut = 5 * 60; 28 | OkHttpClient client = new OkHttpClient.Builder() 29 | .connectTimeout(timeOut, TimeUnit.SECONDS) 30 | .writeTimeout(timeOut, TimeUnit.SECONDS) 31 | .readTimeout(timeOut, TimeUnit.SECONDS) 32 | .build(); 33 | 34 | retrofit = new Retrofit.Builder() 35 | .baseUrl(BASE_URL) 36 | .addConverterFactory(GsonConverterFactory.create(gson)) 37 | .client(client) 38 | .build(); 39 | } 40 | return retrofit; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Android-File-Upload-Tutorial/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |