Thursday, 11 June 2015

Android Retrofit Images Tutorial

http://themakeinfo.com/2015/04/android-retrofit-images-tutorial/

android+retrofit+picasso
MakeInfo
In this tutorial,we are using Retrofit (networking) and Picasso (image loading) library for loading images into a listView .This is an intermediate tutorial.
After introducing Retrofit and why we chose it for Android Rest Calls in my previous article.Now ,we are going to next level,using retrofit and another library ‘Picasso‘ fromsquare to load images.I also hinted about this library in basic tutorial.
Retrofit individually cannot load images so here came this library,but Picasso not only load the image,it will take care of the cache and memory.There is only few lines of code required to load images from external sources in Picasso.
The example project  is added to Github.

Why Picasso ?

There are many image loading libraries available on internet. But Picasso (Square) ,Glide(Bump),Universal-Image-Loader (nostra13) are my favorites. Each has its own advantages and limits.UIL has many features in my experience compared to other,but its not beginner friendly.
I use Picasso in this tutorial because its easy to manage and both libraries(Retrofit) used in this project is from same company (Square) .
Glide is from bumptech and Google also used this for their projects (ioshed).Its really like Picasso esp. the coding style.It will save the images to cache and will load up fast.If your are need to store the images for further uses,then you can definetely use this library.
picvsglide
http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
There is a good comparison i got when googling, Introduction to Glide 
But Glide has bigger size compared to Picasso : 430KB  vs 118 KB .
As i already said Picasso has limited features esp. the transformations compared to UIL. So to add more transformation features,you can use Picasso Transformation He also had a Glide Transformation library.Try this.
Note : Wisely choose the library for your project.

1) Introduction

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
This is the only introduction i need to give for Picasso. Here,we give the ContextURLand ImageView ,then we successfully loaded the image.Read this introduction part fromSquare.After reading the introduction part,also read the http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso–cms-22149,they will give a project idea like Introduction,Installation with a simple project,I recommend this to you.
In today’s project , we are using Api from http://services.hanselandpetal.com/feeds/flowers.json
For images,we use : http://services.hanselandpetal.com/photos/   + Flower name (from json)
In this Project, We will retrieve list of Flower Name and Images into a listView .
For getting best Json View,Use
for Chrome Users : https://github.com/gildas-lormeau/JSONView-for-Chrome (Also in Store)

Download APK

Untitled (1)


2) Requirements

For this project we need :
  1. Andriod Studio
  2. Retrofit
  3. Picasso
  4. You must read the Previous Retrofit Basic Tutorial.

3 ) Adding Libraries in Android Studio

 1) Retrofit  :
     compile 'com.squareup.retrofit:retrofit:1.9.0'
2) Picasso  :
compile 'com.squareup.picasso:picasso:2.5.2'

4) Create Project

1) Create new Android Project by : File => New Project and fill description and click Next.
2) Fill the minimum SDK for the project, i use 4.0+ (Retrofit  requires Android 2.3+or Java 6)
3) Select Blank Activity and then fill out the details Activity Name and Layout Name then click Finish.
4) For Gradle : You can add Retrofit and Picasso library by adding it on app=>build.gradle (in project view).
buildgradle file
For Jar : Add jar to app => libs folder and right click on the jar file and click on Add as Library.
5) Also create two packages as network and model.
6) Right Click on network and Click New => Java Class ,then  Name it as api and Kind asInterface.
7) Right Click on Package model and Click New => Java Class,then Name it as Flower and Kind as Class.
8) Right Click on Package and Click New => Java Class,then name it as adapter (this will use for list view adapter).
file structure

5) Android Manifest.xml

1) Add  INTERNET PERMISSION
<uses-permission android:name="android.permission.INTERNET"/>

6) Model Class

Before coding Model Class ,take a look at the json here, http://services.hanselandpetal.com/feeds/flowers.json
The result  is JSON Array starting with ‘[‘ and ending with ‘]’ in between we can see theJSON Objects.
If you don’t  know the difference between Json Array and Json Object,i will recommend this.
In order to create model class or pojo , i find that jsonschema2pojo (which i explain in previous tutorial) is not working for me.So, the next method is by using http://jsongen.byingtondesign.com/ which has more features.Click Generate with your link.
jsongen
http://jsongen.byingtondesign.com/
package com.makeinfo.retroflower.model;

import android.graphics.Bitmap;

public class Flower {
	
	private int productId;
	private String name;
	private String category;
	private String instructions;
	private double price;
	private String photo;
	private Bitmap bitmap;
	
	public int getProductId() {
		return productId;
	}
	public void setProductId(int productId) {
		this.productId = productId;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
	public String getInstructions() {
		return instructions;
	}
	public void setInstructions(String instructions) {
		this.instructions = instructions;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public String getPhoto() {
		return photo;
	}
	public void setPhoto(String photo) {
		this.photo = photo;
	}
	public Bitmap getBitmap() {
		return bitmap;
	}
	public void setBitmap(Bitmap bitmap) {
		this.bitmap = bitmap;
	}
	
}

7) api.java

This is Interface we created for network calling. Here,we just need to use @GET annotation.         @GET(“/feeds/flowers.json”) where, “/feeds/flowers.json” is the link after the Base URL. The Code will be :
package com.makeinfo.retroflower.network;

import android.test.suitebuilder.annotation.LargeTest;

import com.makeinfo.retroflower.model.Flower;

import java.util.List;

import retrofit.Callback;
import retrofit.http.GET;

/**
 * Created by Gokul Balakrishnan on 4/4/2015.
 */
public interface api {

    @GET("/feeds/flowers.json")
    public void getData(Callback<List<Flower>> response);


}

8) Layout

Before jumping into java code,now we need to design our app layout. In this project, we are loading the images and text in a listview element using ArrayAdapter .
a) activity_main.xml
Our main layout look like this.
<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">

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@android:id/list"></ListView>
</RelativeLayout>
Note : android:id=”@android:id/list” 
b) item_file.xml
Next,we need to create a item file which we will inflate into listview element.Here, we need a ImageView for loading images  and TextView for preview the Flower Names.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:id="@+id/img"
        android:layout_weight="2" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:id="@+id/name"
        android:layout_weight="3"
        android:textColor="#ff010101" />
</LinearLayout>

9) adapter.java

After designing the listview layout  and item layout,now we are using array adapter.If you are new to listview and arrayadapter, please read this articlehttps://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView.
 Note that, getView() will be called for each item to display.We also created a listwith model Flower.
What happend in getView() :
1) Layoutinflater will inflate the item_file layout.
2) Then, we get position from the list.
3) Initialize the textView and we print the flower name.
4) Initialize the ImageView .
5) Now, we use Picasso for loading the image from the url. we also re-size the image .
package com.makeinfo.retroflower;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;


import com.aucupa.retroflower.R;
import com.makeinfo.retroflower.model.Flower;
import com.squareup.picasso.Picasso;

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

public class adapter extends ArrayAdapter<Flower> {

    String url="http://services.hanselandpetal.com/photos/";
    private Context context;
    private List<Flower> flowerList;
    public adapter(Context context, int resource, List<Flower> objects) {
        super(context, resource, objects);
        this.context = context;
        this.flowerList = objects;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.item_file,parent,false);
        Flower flower = flowerList.get(position);
        TextView tv = (TextView) view.findViewById(R.id.name);
        tv.setText(flower.getName());
        ImageView img = (ImageView) view.findViewById(R.id.img);
        Picasso.with(getContext()).load(url+flower.getPhoto()).resize(100,100).into(img);
        return view;
    }
}

10)  RestAdapter Code

I already discuss that ,json array is the result here.So, we need to store the each elements(jsonObject) into a list with model Flower .The Base URL is : http://services.hanselandpetal.com
After calling the getData function from rest adapter,
1) On Success (), we get the result into flowerList  and then, we create  new adapterobject which will display the list into item_file.xml
2) On failure(), Toast action with “failed” message.
package com.makeinfo.retroflower;

import android.app.ListActivity;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.Toast;

import com.aucupa.retroflower.R;
import com.makeinfo.retroflower.model.Flower;
import com.makeinfo.retroflower.network.api;

import java.util.List;

import retrofit.Callback;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.Response;


public class MainActivity extends ListActivity {

    List<Flower> flowerList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final RestAdapter restadapter = new RestAdapter.Builder().setEndpoint("http://services.hanselandpetal.com").build();

        api flowerapi = restadapter.create(api.class);

        flowerapi.getData(new Callback<List<Flower>>() {
            @Override
            public void success(List<Flower> flowers, Response response) {
                flowerList = flowers;
                adapter adapt = new adapter(getApplicationContext(),R.layout.item_file,flowerList);
                //ListView listView = (ListView) findViewById(R.id.list);
                setListAdapter(adapt);
            }

            @Override
            public void failure(RetrofitError error) {
                Toast.makeText(getApplicationContext(),"Failed",Toast.LENGTH_SHORT).show();
            }
        });


    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

No comments:

Post a Comment