Android Retrofit 2 Upload file to Server Tutotial

In previous tutorial, I had been tell you how to use retrofit 2 to retrieve data from the REST API. Able to let the user upload file to the server such as image is also a necessary requirement to create a mobile application. Multipart form-data is built for uploading the file to the server transmit by name/value pair, each pair represents by part. The difference with x-www-form-unlencoded send giant string query to the server, so its unable to upload the file. In a current tutorial, I will let you know how to use android retrofit 2 upload file to the server so you can get the image from the server.

Creating a New Project

1. Open Android Studio IDE in your computer.
2. Create a new project and Edit the Application name to “RetrofitUploadFileExample”.
(Optional) You can edit the company domain or select the suitable location for current project tutorial. Then click next button to proceed.
3. Select Minimum SDK (API 15:Android 4.0.3 (IceCreamSandwich). I choose the API 15 because many android devices currently are support more than API 15. Click Next button.
4. Choose “Empty Activity” and Click Next button
5. Lastly, press finish button.

Add new dependencies

Add dependencies for picasso and retrofit library. Picasso is to load the image in the application, so you don’t need to write huge code to load the image.

compile 'com.android.support:design:24.2.0'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'

Add new permissions access

Go to your manifest file and Add the internet, access network and read external storage permissions in your application so it able to use them in your app.

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

Create a new xml layout for content

This layout is the content of your main layout, i add two button which is upload and pick image.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.questdot.retrofituploadfileexample.MainActivity"
    tools:showIn="@layout/activity_main">


    <ImageView
        android:id="@+id/imageView"

        android:adjustViewBounds="true"

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/fab"
        android:layout_above="@+id/btnPick" />

    <Button
        android:text="Upload"
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />

    <Button
        android:text="Pick Image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:onClick="showImagePopup"
        android:layout_centerHorizontal="true"
        android:id="@+id/btnPick" />
</RelativeLayout>

Edit mainactivity.xml layout

Go to your mainactivity layout and edit to the following source code.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:id="@+id/parentView"
    tools:context=".MainActivity"
   >

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />



</android.support.design.widget.CoordinatorLayout>

Create a new Interface

Right click your package name and create a new class. After that, change your class to interface and edit to the source code below.

public interface FileApi {


    @Multipart
    @POST("upload.php")
    Call<Respond> uploadImage(@Part MultipartBody.Part file);
}

Create a new Modal Class

Add a new class in your package and this class is get the respond of the url.

public class Respond {

    private String message;
    private Boolean error;

    public String getMessage() {
        return message;
    }


    public void setMessage(String message) {
        this.message = message;
    }

    public Boolean getError() {
        return error;
    }

    public void setError(Boolean error) {
        this.error = error;
    }

}

Create a PHP file to upload

Add a new php file in your PHP IDE and it will perform upload file to the path you specify in the php code such as /image for the example below.

<?php
$file_path = "image/";

if (isset($_FILES['uploaded_file']['name'])) {

    $file_path = $file_path . basename( $_FILES['uploaded_file']['name']);
    if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $file_path)) {
        $response['message'] = 'File uploaded successfully';
        $response['error'] = false;
    } else{
        $response['error'] = true;
        $response['message'] = 'Could not move the file';
    }
} else {

    $response['error'] = true;
    $response['message'] = 'Not received any file';
}
echo json_encode($response);
?>

Create a new RetroClient class

You need to enter your server URL in the ROOT_URL field so it will able to work later. The Upload file process is performed by the server.

public class RetroClient {

    private static final String ROOT_URL = "http://192.168.0.111/upload-file/";


    public RetroClient() {

    }

    private static Retrofit getRetroClient() {
        return new Retrofit.Builder()
                .baseUrl(ROOT_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    public static FileApi getApiService() {
        return getRetroClient().create(FileApi.class);
    }
}

Edit MainActivity.class

Edit your mainactivity class, this class to perform retrofit call from the URL. Copy and paste it to your own file. Android 6.0 and above required Read External and Write External Storage permission to access.

public class MainActivity extends AppCompatActivity {
    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static String[] PERMISSIONS_STORAGE = {
                            Manifest.permission.READ_EXTERNAL_STORAGE,
                            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    ImageView imageView;
    String imagePath;
    Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        verifyStoragePermissions(MainActivity.this);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);


        imageView = (ImageView) findViewById(R.id.imageView);

        Button button = (Button) findViewById(R.id.fab);


        button.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {

                                if(imagePath!=null)
                                    uploadImage();
                                else
                                    Toast.makeText(getApplicationContext(),"Please select image", Toast.LENGTH_LONG).show();

                            }
                        });
                    }

    private void uploadImage() {

                        final ProgressDialog progressDialog;
                        progressDialog = new ProgressDialog(MainActivity.this);
                        progressDialog.setMessage("loading...");
                        progressDialog.show();

                        FileApi service = RetroClient.getApiService();

                        File file = new File(imagePath);

                        RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);

                        MultipartBody.Part body =
                                MultipartBody.Part.createFormData("uploaded_file", file.getName(), requestFile);

                        Call<Respond> resultCall = service.uploadImage(body);

                        resultCall.enqueue(new Callback<Respond>() {
                            @Override
                            public void onResponse(Call<Respond> call, Response<Respond> response) {

                                progressDialog.dismiss();

                                // Response Success or Fail
                                if (response.isSuccessful()) {
                                    if (response.body().getError()==true)

                                        Toast.makeText(getApplicationContext(),response.body().getMessage(),Toast.LENGTH_LONG).show();

                                    else
                                        Toast.makeText(getApplicationContext(),response.body().getMessage(),Toast.LENGTH_LONG).show();

                                } else {
                                    Toast.makeText(getApplicationContext(),response.body().getMessage(),Toast.LENGTH_LONG).show();
                                }

                                imageView.setImageDrawable(null);
                                imagePath = null;

            }

            @Override
            public void onFailure(Call<Respond> call, Throwable t) {
                progressDialog.dismiss();
            }
        });
    }


    public void showImagePopup(View view) {
            final Intent galleryIntent = new Intent();
            galleryIntent.setType("image/*");
            galleryIntent.setAction(Intent.ACTION_PICK);

            final Intent chooserIntent = Intent.createChooser(galleryIntent, "Choose image");
            startActivityForResult(chooserIntent, 100);

    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK && requestCode == 100) {
            if (data == null) {
                Toast.makeText(getApplicationContext(),"Unable to pick image",Toast.LENGTH_LONG).show();
                return;
            }

            Uri imageUri = data.getData();
            imageView.setImageURI(imageUri);
         /*
            Uri selectedImageUri = data.getData();
            String[] filePathColumn = {MediaStore.Images.Media.DATA};

            Cursor cursor = getContentResolver().query(selectedImageUri, filePathColumn, null, null, null);

            if (cursor != null) {
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);*/
                imagePath = getRealPathFromURI(imageUri);

            //    Picasso.with(getApplicationContext()).load(new File(imagePath))
            //            .into(imageView);

             //   Toast.makeText(getApplicationContext(),"Please reselect your image",Toast.LENGTH_LONG).show();
           /*     cursor.close();

            } else {

                Toast.makeText(getApplicationContext(),"Unable to load image",Toast.LENGTH_LONG).show();
            }*/
        }
    }

    private String getRealPathFromURI(Uri contentUri) {
        String[] proj = { MediaStore.Images.Media.DATA };
        CursorLoader loader = new CursorLoader(getApplicationContext(), contentUri, proj, null, null, null);
        Cursor cursor = loader.loadInBackground();
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String result = cursor.getString(column_index);
        cursor.close();
        return result;
    }

    public static void verifyStoragePermissions(Activity activity) {
                        // 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
                            );
                        }
                    }




}

Run Your Project

Finally, you can try the form data call in your android project, if success, it will automatically add the image in your server.

 

(Android Retrofit 2 Upload file to Server)

Source Code

 

Android

PHP

 

(Visited 8,897 times, 1 visits today)
Advertisements

Yong Loon Ng

Ng Yong Loon, better known as Kristofer is a software engineer and computer scientist who doubles up as an entrepreneur.

You may also like...

8 Responses

  1. Ronney Ismael says:

    Hi Kristofer, I am not able to download your code. Is this app available on github

  2. Lester says:

    I’ve been exploring for a little bit for any high quality articles or weblog posts on this kind
    of house . Exploring in Yahoo I finally stumbled upon this website.
    Reading tjis info So i’m satisfied to show that I have an incredibly
    just right uncanny feeling I discovered just what I needed.

    I most undoubtedly will make sure to don?t omit this web site and provides it a look regularly.

  3. Thanks for finally talkig about >Android Retrofit 2 Upload file to
    Server Tutotial – QuestDot <Liked it!

  4. Alycia says:

    Thank you forr any other excellent post. The place else could anybody get that kind of injformation iin such a perfect means of writing?
    I have a presentation nex week, and I’m at the look ffor such information.

  5. Chastity says:

    I was recommended this web site via my cousin. I’m not sure whether or not this put up is wriotten via him as nobody else know such specified approximatly my trouble.
    You’re amazing! Thanks!

  6. Carl says:

    Wonderful gkods from you, man. I’ve undersstand ylur stuff previous too and you’re just too magnificent.
    I actually like what you’veacquired here, certainly like what you are
    stating andd the way in which you say it. You make
    it entertaining and you still take care of to keep it sensible.
    I can not wait to read much more from you. This is really a tremendous webb site.

  7. Lolita says:

    It’s iin reality a nice and useful piece of information. I am happy that yyou simply shared this helpful info with us.
    Please stay us informed like this. Thajk you for sharing.

Leave a Reply

Your email address will not be published. Required fields are marked *