Android Photo App
This example will guide you through the code to build a simple Android Photo app. In this app, you will learn how an Android client can use the Photo API Service and load a random image. Full code is available here : https://github.com/minio/android-photo-app, released under Apache 2.0 License.
1. Dependencies
We will be building this app using Android Studio. This app will also consume the Photo API Service we built to get presigned urls that are randomly loaded on click of a button.
Android Studio
JDK 1.8
2. SetUp
Step 1 - Launch Android Studio -> New Project -> Create a new Android Project. Name your project AndroidPhotoApp.
Step 2 - Select Phone & Tablet. In this example we choose the latest stable Marshmallow Android 6.0 SDK to compile and build this app.
Step 3 - Pick a Blank or a Basic Activity template and then click on Next.
Step 4 - Leave the defaults as is for the Activity & Layout Names. Click Finish.
Step 5 - You should see that gradle builds and generates a project where we can now begin to code up our AndroidPhotoApp.
3. App Layout
Next let's remove the default Hello World TextView.
Drag and drop a Button widget onto the phone's screen presented on content_main.xml.
Drag and drop a FrameLayout from Layouts (under palette).
Let's also drag and drop an imageView from the widgets inside the FrameLayout.
Below is also the full XML version of our design from content_main.xml.
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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="examples.minio.com.androidphotoapp.MainActivity"
tools:showIn="@layout/activity_main">
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="16dp"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:layout_width="0dp"
android:layout_height="308dp"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
android:layout_marginStart="36dp"
android:layout_marginEnd="36dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="parent">
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@android:color/background_light" />
4. MainActivity.java
We will use the Photo API Service we built earlier to service our AndroidPhotoApp. For the sake of simplicity, we will not use a ListView or a GridView to display a collection of photos. Instead we will randomly load one of the photos from the presigned URLs we receive from the PhotoAPI Service.
package examples.minio.com.androidphotoapp;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
Button refreshButton;
ProgressDialog pDialog;
private static final String PHOTOSERVICE_URL = "http://play.minio.io:8080/PhotoAPIService-0.0.1-SNAPSHOT/minio/photoservice/list";
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//For the sake of simplicity we use an array of images. We recommend using ListViews or GridViews in your real applications.
imageView = (ImageView) findViewById(R.id.imageView);
refreshButton = (Button) findViewById(R.id.button);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
refreshButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// An async task fetches all the latest photo URLs from the PhotoAPIService.
new LoadImage().execute(PHOTOSERVICE_URL);
}
});
}
As is customary in fetching content for Android clients, we will employ an AsyncTask to fetch and process the urls in the background thread off from the main UI thread.
private class LoadImage extends AsyncTask {
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setMessage("Fetching Image from Minio Server....");
pDialog.show();
}
protected Bitmap doInBackground(String... args) {
InputStream inputStream = null;
String result = "";
try {
URL url = new URL(args[0]);
HttpURLConnection httpCon =
(HttpURLConnection) url.openConnection();
if (httpCon.getResponseCode() != 200)
throw new Exception("Failed to connect");
// Fetch the content as an inputStream.
inputStream = httpCon.getInputStream();
// Convert the fetched inputstream to string.
if (inputStream != null)
result = convertInputStreamToString(inputStream);
else
result = "Did not work!";
if (result != null) System.out.println(result);
// convert String to JSONObject.
JSONObject json = new JSONObject(result);
// get the array of photos.
JSONArray imageJSON = json.getJSONArray("Album");
int index = imageJSON.length()-1;
Random rand = new Random();
// Let's get a randomly pic a picture to load.
int rindex = rand.nextInt((index - 0) + 1) + 0;
// Return the image.
return BitmapFactory.decodeStream(new URL(imageJSON.getJSONObject(rindex).getString("url")).openStream());
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
protected void onPostExecute(Bitmap image) {
System.out.println("In Post Execute");
if (image != null) {
pDialog.dismiss();
// Place the image on the ImageView.
imageView.setImageBitmap(image);
} else
{
pDialog.dismiss();
Toast.makeText(MainActivity.this, "Image Does Not exist or Network Error", Toast.LENGTH_SHORT).show();
}
}
}
We use a small helper function to convert the InputStream to String.
private static String convertInputStreamToString(InputStream inputStream) throws IOException{
BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream));
String line = "";
String result = "";
// Loop through the stream line by line and convert to a String.
while((line = bufferedReader.readLine()) != null)
result += line;
inputStream.close();
return result;
}
5. AndroidManifest.xml
We need to add the so that the app can fetch the images over the internet.
package="examples.minio.com.androidphotoapp">
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">
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
6. Run the App
Launch the Android Emulator or connect an Android device to your computer.
Please ensure the emulator/device runs Android 6.0 Marshmallow or above so that we can deploy our app to this emulator. This is because when we created this project, we picked Android 6.0 for the minimum SDK settings. See step 2 in the Setup section.
Press the green play button to run & deploy the app onto the emulator or a connected Android device.
Click on the Load Random Image Button to load a different image.
7. Explore Further