×
Community Blog PhotoSharing Part III: PhotoSharing with OSS Image Processing

PhotoSharing Part III: PhotoSharing with OSS Image Processing

We build a photo sharing Android app with real-time image uploading and downloading function using Alibaba Cloud OSS, and create the corresponding Jav.

PrincipleofSearchingForSimilarImages_part1

By Sai Sarath Chandra, Alibaba Cloud Tech Share Author and Alibaba Cloud MVP

This is the last section of the photo sharing Android application tutorial. We will create the corresponding Java code and complete the whole application after changing some of the configuration values. We will then run the application and see the results correspondingly.

Updating strings.xml

Open your strings.xml file and update the file with the below values make sure you update the Access key ID, access key secret, end point, bucket name, bucket endpoint and STS token.

<resources>
    <string name="app_name">Photo Sharing</string>

    <!-- Alibaba KMS Service details-->
    <!-- Please replace this details with your own -->
    <!--Public Endpoint-->
    <string name="Endpoint">PLEASE REPLACE WITH YOUR REGION ENDPOINT</string>
    <!-- STS Access ID -->
    <string name="AccessKey">PLEASE REPLACE WITH YOUR STS ACCESS KEY</string>
    <!-- STS Access key Secret -->
    <string name="AccessKeySecret">PLEASE REPLACE WITH YOUR STS SECRET ACCESS KEY</string>
    <string name="Bucket_Endpoint">REPLACE FULLY QUALIFIED ENDPOINT OF BUCKET WITH REGION</string>
    <string name="Bucket_Name">PLEASE REPLACE WITH YOUR BUCKET NAME</string>
    <string name="stsToken">PLEASE REPLACE WITH YOUR STS TOKEN</string>


    <string name="bungee_regular">fonts/Bungee-Regular.ttf</string>
    <string name="breeserif">fonts/BreeSerif-Regular.ttf</string>

</resources>

Downloading Fonts

I used two types of fonts for this application. You can download the font from https://fonts.google.com or from anywhere else. All the fonts used are open source and we can use them in our projects. The fonts used in this application are:

• BreeSerif-Regular.ttf
• Bungee-Regular.ttf

Creating Java Code

Util:

Create a util package under the existing package and create the below mentioned Java files.

Let's create some utility classes for the application that is common for all the functionalities, such as providing customised font and application level constants.

CustomFont.java

This class contains provides the functionality of providing the typeface for the customized font.

Creating an object of this class requires the context parameter to be passed after initialization. Create the Java file as mentioned and update the code with the below provided:

package sample.alibabacloud.photosharing.util;

import android.content.Context;
import android.graphics.Typeface;

import sample.alibabacloud.photosharing.R;

/**
 * Created by saisarathchandra on 25/12/17.
 */

public class CustomFont {

    private Context mContext;

    public CustomFont(Context mContext) {
        this.mContext = mContext;
    }

    public Typeface getBungeeRegular(){
        return Typeface.createFromAsset(mContext.getAssets(),mContext.getString(R.string.bungee_regular));
    }

    public Typeface getBreeSerifRegular(){
        return Typeface.createFromAsset(mContext.getAssets(),mContext.getString(R.string.breeserif));
    }
}

Constants.java

This class contains all the static field members. These are the style definitions for various image processing functionalities in an application and their corresponding names. Create the file and update the code with the below provided:

package sample.alibabacloud.photosharing.util;

/**
 * Created by saisarathchandra on 25/12/17.
 */

public class Constants {

    public final static String RESIZE_STYLE_DEF = "image/resize,m_fixed,w_100,h_100";
    public final static String RESIZE_STYLE_NAME = "resized";
    public final static String CROP_STYLE_DEF = "image/crop,w_100,h_100,x_100,y_100,r_1";
    public final static String CROP_STYLE_NAME = "cropped";
    public final static String ROTATE_STYLE_DEF = "image/rotate,90";
    public final static String ROTATE_STYLE_NAME = "rotated";
    public final static String SHARPEN_STYLE_DEF = "image/sharpen,100";
    public final static String SHARPEN_STYLE_NAME = "sharpened";
    public final static String WATERMARK_STYLE_DEF = "image/watermark,text_QWxpYmFiYUNsb3Vk";
    public final static String WATERMARK_STYLE_NAME = "watermarked";
}

model

Here we create the model classes for the application, which represents the information in a particular object

Create model package under the existing package at the same level of util package and create the below mentioned files:

ImageProcessDataModel.java

This class represents the information required for the image processing feature of Alibaba Cloud. Our application will not be using all the attributes mentioned in this Bean class, but in other applications, we may use all the attributes. Create the corresponding file by copying the below code:

package sample.alibabacloud.photosharing.model;

/**
 * Created by saisarathchandra on 25/12/17.
 */

public class ImageProcessDataModel {

    private String style;
    private String styleName;
    private String imageName;
    private String imageStyle;

    public String getStyle() {
        return style;
    }

    public void setStyle(String style) {
        this.style = style;
    }

    public String getStyleName() {
        return styleName;
    }

    public void setStyleName(String styleName) {
        this.styleName = styleName;
    }

    public String getImageName() {
        return imageName;
    }

    public void setImageName(String imageName) {
        this.imageName = imageName;
    }

    public String getImageStyle() {
        return imageStyle;
    }

    public void setImageStyle(String imageStyle) {
        this.imageStyle = imageStyle;
    }
}

ImageData.java

This class is created to transfer the file related information provided by camera, gallery, and documents to the OSS. Create the corresponding file and copy the code below

package sample.alibabacloud.photosharing.model;

/**
 * Created by saisarathchandra on 25/12/17.
 */

public class ImageData {
    private String imageURL;
    private String imageName;

    public String getImageURL() {
        return imageURL;
    }

    public void setImageURL(String imageURL) {
        this.imageURL = imageURL;
    }

    public String getImageName() {
        return imageName;
    }

    public void setImageName(String imageName) {
        this.imageName = imageName;
    }
}

Now, we create multiple Java files which interacts with the XML files created in the previous section and provides the functionality for the same.

WelcomeActivity.java

This Java file load the "welcome activity" XML and bootstrap the upload files and view images to the corresponding screens. You can even see that the fonts are being applied here. Create the file as named and copy the below code:

package sample.alibabacloud.photosharing;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.Button;

import sample.alibabacloud.photosharing.util.CustomFont;

/**
 * Created by saisarathchandra on 25/12/17.
 */

public class WelcomeActivity extends Activity implements View.OnClickListener{

    Button uploadFiles,viewImages;

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

        CustomFont customFont = new CustomFont(this);

        uploadFiles = findViewById(R.id.uploadFiles);
        viewImages = findViewById(R.id.viewImages);

        uploadFiles.setTypeface(customFont.getBungeeRegular());
        viewImages.setTypeface(customFont.getBungeeRegular());
        uploadFiles.setOnClickListener(this);
        viewImages.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if(id == R.id.uploadFiles){
            Intent i = new Intent(this,MainActivity.class);
            startActivity(i);
        }else if(id == R.id.viewImages){
            Intent i = new Intent(this,ImageRecyclerList.class);
            startActivity(i);
        }
    }
}

ImageDataAdapter.java

This is the adapter class for the recyclerview. This class functionality is to provide the input for the recyclerview and render the items in the recyclerview as requested by the Android system. Create the corresponding file and copy the below code:

package sample.alibabacloud.photosharing;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;

import java.util.List;

import sample.alibabacloud.photosharing.model.ImageData;

/**
 * Created by saisarathchandra on 25/12/17.
 */

public class ImageDataAdapter extends RecyclerView.Adapter<ImageDataAdapter.MyViewHolder> {

    private List<ImageData> imageDataList;
    private Context mContext;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView imageName;
        public ImageView imageView;


        public MyViewHolder(View view) {
            super(view);
           imageView = view.findViewById(R.id.imageView);
           imageName = view.findViewById(R.id.imageName);
        }
    }


    public ImageDataAdapter(List<ImageData> imageDataList,Context mContext) {
        this.imageDataList = imageDataList;
        this.mContext = mContext;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.recyclerview_row, parent, false);

        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        ImageData imageData = imageDataList.get(position);
        Glide.with(mContext).load(imageData.getImageURL()).into(holder.imageView);
        holder.imageName.setText(imageData.getImageName());
    }

    @Override
    public int getItemCount() {
        return imageDataList.size();
    }
}

ImageRecyclerList.java

This class is responsible for showing the list of images retrieved from Alibaba Cloud and updates the list when there is a change on the Alibaba Cloud OSS. This information will be shown when the user selects view images in the welcome activity. Create the file as mentioned and copy the code from below:

package sample.alibabacloud.photosharing;

import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;

import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSS;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider;
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask;
import com.alibaba.sdk.android.oss.model.ListObjectsRequest;
import com.alibaba.sdk.android.oss.model.ListObjectsResult;

import java.util.ArrayList;
import java.util.List;

import sample.alibabacloud.photosharing.model.ImageData;

/**
 * Created by saisarathchandra on 25/12/17.
 */

public class ImageRecyclerList extends Activity {

    private List<ImageData> imageDataList = new ArrayList<>();
    private RecyclerView recyclerView;
    private ImageDataAdapter mAdapter;
    OSS oss;

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

        recyclerView = findViewById(R.id.recycler_view);
        mAdapter = new ImageDataAdapter(imageDataList,this);
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(mAdapter);

        OSSCredentialProvider credentialProvider = new OSSStsTokenCredentialProvider(getString(R.string.AccessKey),getString(R.string.AccessKeySecret),getString(R.string.stsToken));
        oss = new OSSClient(getApplicationContext(), getString(R.string.Endpoint), credentialProvider);

        getFiles();

    }

    public void getFiles(){
        ListObjectsRequest listObjects = new ListObjectsRequest(getString(R.string.Bucket_Name));

        OSSAsyncTask task = oss.asyncListObjects(listObjects, new OSSCompletedCallback<ListObjectsRequest, ListObjectsResult>() {
            @Override
            public void onSuccess(ListObjectsRequest request, ListObjectsResult result) {
                Log.d("AyncListObjects", "Success!");
                imageDataList.clear();
                for (int i = 0; i < result.getObjectSummaries().size(); i++) {
                    Log.d("AyncListObjects", "object: " + result.getObjectSummaries().get(i).getKey() + " "
                            + result.getObjectSummaries().get(i).getETag() + " "
                            + result.getObjectSummaries().get(i).getLastModified());

                    ImageData imageData = new ImageData();
                    imageData.setImageName(result.getObjectSummaries().get(i).getKey());
                    imageData.setImageURL(getString(R.string.Bucket_Endpoint)+result.getObjectSummaries().get(i).getKey());
                    imageDataList.add(imageData);
                }
                mAdapter.notifyDataSetChanged();
            }
            @Override
            public void onFailure(ListObjectsRequest request, ClientException clientExcepion, ServiceException serviceException) {
                // Request exception
                if (clientExcepion != null) {
                    // Local exception, such as a network exception
                    clientExcepion.printStackTrace();
                }
                if (serviceException != null) {
                    // Service exception
                    Log.e("ErrorCode", serviceException.getErrorCode());
                    Log.e("RequestId", serviceException.getRequestId());
                    Log.e("HostId", serviceException.getHostId());
                    Log.e("RawMessage", serviceException.getRawMessage());
                }
            }
        });
        task.waitUntilFinished();
    }

}

MainActivity.java

This class contains the complete functionality of the image processing feature. This class also invokes the camera, gallery, and documents folder. We will be using a third-party library called EasyImage. We will discuss more about main activity once we complete creating the files.

Copy below code into the activity:

package sample.alibabacloud.photosharing;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.Toast;

import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSS;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback;
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider;
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask;
import com.alibaba.sdk.android.oss.model.GetObjectRequest;
import com.alibaba.sdk.android.oss.model.GetObjectResult;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import pl.aprilapps.easyphotopicker.DefaultCallback;
import pl.aprilapps.easyphotopicker.EasyImage;
import sample.alibabacloud.photosharing.model.ImageProcessDataModel;
import sample.alibabacloud.photosharing.util.Constants;
import sample.alibabacloud.photosharing.util.CustomFont;

public class  MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final int REQUEST_CODE_CHOOSE = 800;
    private final static String TAG = "MainActivity";
    ImageButton cameraBtn, galleryBtn, documentsBtn;
    Button resizeImg, cropImg, rotateImg, sharpenImg, watermarkImg;
    List<Uri> mSelected;
    OSS oss;

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

        CustomFont customFont = new CustomFont(this);

        cameraBtn = findViewById(R.id.cameraBtn);
        galleryBtn = findViewById(R.id.galleryBtn);
        documentsBtn = findViewById(R.id.documentsBtn);

        resizeImg = findViewById(R.id.resizeImg);
        cropImg = findViewById(R.id.cropImg);
        rotateImg = findViewById(R.id.rotateImg);
        sharpenImg = findViewById(R.id.sharpenImg);
        watermarkImg = findViewById(R.id.watermarkImg);

        resizeImg.setTypeface(customFont.getBreeSerifRegular());
        cropImg.setTypeface(customFont.getBreeSerifRegular());
        rotateImg.setTypeface(customFont.getBreeSerifRegular());
        sharpenImg.setTypeface(customFont.getBreeSerifRegular());
        watermarkImg.setTypeface(customFont.getBreeSerifRegular());

        mSelected = new ArrayList<>();

        cameraBtn.setOnClickListener(this);
        galleryBtn.setOnClickListener(this);
        documentsBtn.setOnClickListener(this);
        resizeImg.setOnClickListener(this);
        cropImg.setOnClickListener(this);
        rotateImg.setOnClickListener(this);
        sharpenImg.setOnClickListener(this);
        watermarkImg.setOnClickListener(this);
//         Create the Client

        OSSCredentialProvider credentialProvider = new OSSStsTokenCredentialProvider(getString(R.string.AccessKey),getString(R.string.AccessKeySecret),getString(R.string.stsToken));
        oss = new OSSClient(getApplicationContext(), getString(R.string.Endpoint), credentialProvider);


    }


    @Override
    public void onClick(View view) {
        int id = view.getId();

        if(id == R.id.cameraBtn){
            Toast.makeText(this,"Opening Camera",Toast.LENGTH_SHORT).show();
            EasyImage.openCamera(this,0);
        }else if(id == R.id.galleryBtn){
            Toast.makeText(this,"Opening Gallery",Toast.LENGTH_SHORT).show();
            EasyImage.openGallery(this,0);
        }else if(id == R.id.documentsBtn){
            Toast.makeText(this,"Opening Documents",Toast.LENGTH_SHORT).show();
            EasyImage.openDocuments(this,0);
        }else if(id == R.id.resizeImg){
            Toast.makeText(this,"Image Resize Requested",Toast.LENGTH_SHORT).show();
            ProcessImg processImg = new ProcessImg(this);
            ImageProcessDataModel imgProcess = new ImageProcessDataModel();
            imgProcess.setStyle(Constants.RESIZE_STYLE_DEF);
            imgProcess.setStyleName(Constants.RESIZE_STYLE_NAME);
            processImg.execute(imgProcess);
        }else if(id == R.id.cropImg){
            Toast.makeText(this,"Image Crop Requested",Toast.LENGTH_SHORT).show();
            ProcessImg processImg = new ProcessImg(this);
            ImageProcessDataModel imgProcess = new ImageProcessDataModel();
            imgProcess.setStyle(Constants.CROP_STYLE_DEF);
            imgProcess.setStyleName(Constants.CROP_STYLE_NAME);
            processImg.execute(imgProcess);
        }else if(id == R.id.rotateImg){
            Toast.makeText(this,"Image Rotate Requested",Toast.LENGTH_SHORT).show();
            ProcessImg processImg = new ProcessImg(this);
            ImageProcessDataModel imgProcess = new ImageProcessDataModel();
            imgProcess.setStyle(Constants.ROTATE_STYLE_DEF);
            imgProcess.setStyleName(Constants.ROTATE_STYLE_NAME);
            processImg.execute(imgProcess);
        }else if(id == R.id.sharpenImg){
            Toast.makeText(this,"Image Sharpening Requested",Toast.LENGTH_SHORT).show();
            ProcessImg processImg = new ProcessImg(this);
            ImageProcessDataModel imgProcess = new ImageProcessDataModel();
            imgProcess.setStyle(Constants.SHARPEN_STYLE_DEF);
            imgProcess.setStyleName(Constants.SHARPEN_STYLE_NAME);
            processImg.execute(imgProcess);
        }else if(id == R.id.watermarkImg){
            Toast.makeText(this,"Image Watermarking Requested",Toast.LENGTH_SHORT).show();
            ProcessImg processImg = new ProcessImg(this);
            ImageProcessDataModel imgProcess = new ImageProcessDataModel();
            imgProcess.setStyle(Constants.WATERMARK_STYLE_DEF);
            imgProcess.setStyleName(Constants.WATERMARK_STYLE_NAME);
            processImg.execute(imgProcess);
        }

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        EasyImage.handleActivityResult(requestCode, resultCode, data, this, new DefaultCallback() {
            @Override
            public void onImagePickerError(Exception e, EasyImage.ImageSource source, int type) {
                Log.d(TAG, "onImagePickerError: Error in Image handling");
            }

            @Override
            public void onImagePicked(File imageFile, EasyImage.ImageSource source, int type) {
                Log.d(TAG, "onImagePicked:"+imageFile.getAbsolutePath());
                putFileOSS(imageFile.getAbsolutePath());

            }

            @Override
            public void onCanceled(EasyImage.ImageSource source, int type) {
                //Cancel handling, you might wanna remove taken photo if it was canceled
                if (source == EasyImage.ImageSource.CAMERA) {
                    File photoFile = EasyImage.lastlyTakenButCanceledPhoto(MainActivity.this);
                    if (photoFile != null)
                        photoFile.delete();
                }
            }
        });
    }

    public void putFileOSS(String filePath){
        PutObjectRequest put = new PutObjectRequest(getString(R.string.Bucket_Name), "Demo_Picture_1.png", filePath);
        put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
            @Override
            public void onProgress(PutObjectRequest request, long currentSize, long totalSize) {
                Log.d("PutObject", "currentSize: " + currentSize + " totalSize: " + totalSize);
            }
        });
        OSSAsyncTask task = oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
            @Override
            public void onSuccess(PutObjectRequest request, PutObjectResult result) {
                Log.d("PutObject", "UploadSuccess");
                Log.d("ETag", result.getETag());
                Log.d("RequestId", result.getRequestId());
            }
            @Override
            public void onFailure(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
                // Request exception
                if (clientExcepion != null) {
                    // Local exception, such as a network exception
                    clientExcepion.printStackTrace();
                }
                if (serviceException != null) {
                    // Service exception
                    Log.e("ErrorCode", serviceException.getErrorCode());
                    Log.e("RequestId", serviceException.getRequestId());
                    Log.e("HostId", serviceException.getHostId());
                    Log.e("RawMessage", serviceException.getRawMessage());
                }
            }
        });

    }

    class ProcessImg extends AsyncTask<ImageProcessDataModel, Void, Void> {
        private ProgressDialog dialog;

        public ProcessImg(Activity activity) {
            dialog = new ProgressDialog(activity);
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            dialog.setMessage("Processing Image");
            dialog.show();
            dialog.setCancelable(false);
        }

        @Override
        protected Void doInBackground(ImageProcessDataModel... dataModel) {

                ImageProcessDataModel data = dataModel[0];
                String fileName = "Demo_Picture_1";
                String transformedFileName = fileName+"_"+data.getStyleName()+".jpg";

                try {
//                    String style = "image/resize,m_fixed,w_100,h_100";
                    GetObjectRequest request = new GetObjectRequest(getString(R.string.Bucket_Name), fileName+".png");
                    TestGetCallback getCallback = new TestGetCallback();

                    request.setxOssProcess(data.getStyle());

                    request.setProgressListener(new OSSProgressCallback<GetObjectRequest>() {
                        @Override
                        public void onProgress(GetObjectRequest request, long currentSize, long totalSize) {
                            Log.d(TAG, "getobj_progress: " + currentSize+"  total_size: " + totalSize);
                            final long percent= currentSize/totalSize;
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    dialog.setMessage("Processed : "+(percent*100));
                                }
                            });
                        }
                    });

                    OSSAsyncTask task = oss.asyncGetObject(request, getCallback);
                    task.waitUntilFinished();

                    Log.d(TAG, "resizeImg: "+getCallback.result.getMetadata().toString());
                    Log.d(TAG, "resizeImg: "+getCallback.request.getObjectKey());


                    PutObjectRequest put = new PutObjectRequest(getString(R.string.Bucket_Name), transformedFileName, org.apache.commons.io.IOUtils.toByteArray(getCallback.result.getObjectContent()));
                    put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
                        @Override
                        public void onProgress(PutObjectRequest request, long currentSize, long totalSize) {
                            Log.d("PutObject", "currentSize: " + currentSize + " totalSize: " + totalSize);
                        }
                    });

                    OSSAsyncTask task2 = oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
                        @Override
                        public void onSuccess(PutObjectRequest request, PutObjectResult result) {
                            Log.d("PutObject", "UploadSuccess");
                            Log.d("ETag", result.getETag());
                            Log.d("RequestId", result.getRequestId());
                        }
                        @Override
                        public void onFailure(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
                            // Request exception
                            if (clientExcepion != null) {
                                // Local exception, such as a network exception
                                clientExcepion.printStackTrace();
                            }
                            if (serviceException != null) {
                                // Service exception
                                Log.e("ErrorCode", serviceException.getErrorCode());
                                Log.e("RequestId", serviceException.getRequestId());
                                Log.e("HostId", serviceException.getHostId());
                                Log.e("RawMessage", serviceException.getRawMessage());
                            }
                        }
                    });
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            if(dialog.isShowing()){
                dialog.dismiss();
            }

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, "Operation Completed", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    public final static class TestGetCallback implements OSSCompletedCallback<GetObjectRequest, GetObjectResult> {

        private GetObjectRequest request;
        private GetObjectResult result;
        private ClientException clientException;
        private ServiceException serviceException;


        @Override
        public void onSuccess(GetObjectRequest request, GetObjectResult result) {
            this.request = request;
            this.result = result;

            Log.d(TAG, "onSuccess: "+result);
        }

        @Override
        public void onFailure(GetObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
            this.request = request;
            this.clientException = clientExcepion;
            this.serviceException = serviceException;
        }
    }
}

Updating Manifest:

The last and most important step after we creating the file is to register them in the AndroidManifest.xml. Update your manifest with the below code:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="sample.alibabacloud.photosharing">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".WelcomeActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".MainActivity"/>
        <activity android:name=".ImageRecyclerList" />

    </application>

</manifest>

As you can see we require multiple permissions in the Android manifest, which includes internet, network state, Wi-Fi state, external storage, and camera. These permissions are required by the application for it to function normally.

Using the Application:

Let's discuss about the logic involved in using the application. When a user clicks on upload images, a screen is launched. The welcome activity code is invoked, which then invokes the main activity code.

The top 3 image buttons, which display the camera gallery and document icon, provide the functionality of launching the default corresponding applications. After a user selects a file, the corresponding file will be uploaded on to the Alibaba Cloud. The user can see the same file by opening the Alibaba Cloud Object Storage Service (OSS) console.

We can use the image processing feature of OSS to perform image editing functionalities like resize, crop, rotate, and watermarking. The application uses a constant file to fit the image style definition and the corresponding image names. The application then invokes the image process task and make a request to the OSS service to transform the image. OSS returns the transformed image as a response to this request.

The processed image needs to be uploaded back onto the server from the client to be saved as an new image. You can also rewrite the existing image with the updated image, but personally, I prefer to keep all the transformed images separated. To do this, I send the original filename with the style we applied during the processing, and the application will save it as a new file using the putobjectrequest in the image process task.

Once all the images are processed, you can navigate to the welcome page to view the images. Recyclerview helps to display and provide the corresponding file names on the app.

1

2

3

Conclusion:

Alibaba Cloud Object Storage Service (OSS) provides excellent response times upon uploading and downloading the images. I really like the asynchronous API provided by them, not many tools out there provide the same feature. It reduces the development time and the number of bugs we face when performing post development activities. There is a gentle learning curve for the beginners or developers working on it but in long-term it is very useful.

If everything is done correctly all your compilation issues will go away and the application starts installing in by clicking the small play (run) button in the status bar of the Android studio.

4

I tried not to modularize the application too much so that it is very easy to understand and clear. You can get the source code on my GitHub repository, which contains the working version of code. I recommend cloning the repository to reduce errors and get started immediately. If you have any issues or clarifications, please raise it as an issue or question here: https://github.com/saichandu415/OSS-Android-Sample/issues

0 0 0
Share on

Alibaba Clouder

2,605 posts | 747 followers

You may also like

Comments

Alibaba Clouder

2,605 posts | 747 followers

Related Products