Lazy Loading Image

The concept in vogue, the need of present digital world, adopted by all the contemporary app developers is Lazy Loading…!           

Lazy loading is basically recommended because it resolves various issues associated in handling components, especially images in ListView orGridView.

Suppose in an app we have n number of images in a custom list or grid retrieving from server, in that case the app may not be able to handle the request of enormous-sized images and subsequently may crash.

Lazy loading overcomes this drawback by providing the images at the point of requirement. The point of requirement is determined by our scrolling action. Thus, the images are fetched from the server as we need them.

I have developed a small project that would fetch data (images) from server using Json parsing and volley library and display it in a ListView. The volley errors are handled all together that would curb app crash.

Next new concept that we would learn is retrieving Json array from within a Json object. Let’s start creating the project. The step-wise procedure is given as follows –

1. Create a new project in Android Studio:Specify an appropriate title for the project, e.g. LazyLoading and select empty activity.

2. Include the volley library in gradlefile:This can be done by either importing library from dependencies of the project structure or writing the below code inside app gradle file under dependencies –

compile 'com.mcxiaoke.volley:library:1.0.19'

3. Take internet permission in Manifest file:Since we are going to make server requests, it is mandatory to take internet permission as follows –

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

4. Note down the example Json and its url:The Json data that we would parse here is given as follows –

{
	"Status": "Success",
	"Data": [{
		"AppID": "18",
		"AppName": "Handy Audio Editor",
		"AppImage": "handy_audio.png",
		"AppURL": "https:\/\/itunes.apple.com\/us\/app\/handy-audio-editor\/id998073416?mt=8",
		"CreatedAt": "2015-10-09 17:14:34",
		"DeletedAt": "",
		"ImagePath": "http:\/\/igeniusdev.com\/igeniusapps\/application\/upload\/AppIcon\/18-handy_audio.png"
	}, {
		"AppID": "22",
		"AppName": "ISTO - Android",
		"AppImage": "isto1.png",
		"AppURL": "https:\/\/play.google.com\/store\/apps\/details?id=com.moxmind.isto",
"CreatedAt": "2015-10-30 17:03:47",
		"DeletedAt": "",
		"ImagePath": "http:\/\/igeniusdev.com\/igeniusapps\/application\/upload\/AppIcon\/22-isto1.png"
	},] 	
}

The [ ] represents Json array while { } represents Json objects. So, we have to first decode the Json Object to retrieve Json Array named “Data”, and then from this Json array, we will retrieve Json objects like appid, appname etc. In our project we are fetching only Imagepath and displaying them.

Json URL:

http://igeniusdev.com/igeniusapps/rest_api_list/get_more_apps?AppID=5

5. Design the layout of activity_main.xml file: The layout simply contains a ListView inside a relative layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns: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="com.lazyjson.MainActivity">

<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listView"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:divider="@null"
android:background="@drawable/silkbg" />
</RelativeLayout>

6.Create a Model class named ImagesModel to define all variables in Json data:

public class ImagesModel
{
private String appid, appname, appimage, appurl, createdat, imagepath;

public ImagesModel(String appid, String appname, String appimage, String appurl, String imagepath, String createdat) {
this.appid= appid;
this.appname= appname;
this.appimage= appimage;
this.appurl= appurl;
this.imagepath= imagepath;
this.createdat= createdat;
}

public ImagesModel(){}

public String getAppid() {
return appid;
}

public void setAppid(String appid) {
this.appid= appid;
}

public String getAppname() {
return appname;
}

public void setAppname(String appname) {
this.appname= appname;
}

public String getAppimage() {
return appimage;
}

public void setAppimage(String appimage) {
this.appimage= appimage;
}

public String getAppurl() {
return appurl;
}

public void setAppurl(String appurl) {
this.appurl= appurl;
}

public String getCreatedat() {
return createdat;
}

public void setCreatedat(String createdat) {
this.createdat= createdat;
}

public String getImagepath() {
return imagepath;
}

public void setImagepath(String imagepath) {
this.imagepath= imagepath;
}

}

Though we have defined all the variables, but finally we will parse only the imagepath. The above is just a demo in caseneed arises to retrieve all Json data.

7. Create a java class named “AppController.java” to initialize all the objects of volley library:

public class AppControllerextends Application
{
public static final String TAG = AppController.class.getSimpleName();

private RequestQueuemRequestQueue;
private ImageLoadermImageLoader;

private static AppControllermInstance;

@Override
public void onCreate() {
super.onCreate();
mInstance= this;
}

public static synchronized AppControllergetInstance() 
{
    return mInstance;
}

public RequestQueuegetRequestQueue() {
if (mRequestQueue== null) {
mRequestQueue= Volley.newRequestQueue(getApplicationContext());
 }
return mRequestQueue;
 }

public ImageLoadergetImageLoader()
{
    getRequestQueue();
   if (mImageLoader== null)
   {
      mImageLoader= new ImageLoader(this.mRequestQueue,
      new LruBitmapCache());
   }
    return this.mImageLoader;
}

public void addToRequestQueue(Requestreq, String tag) 
{
  // set the default tag if tag is empty
   req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
   getRequestQueue().add(req);
}

public void addToRequestQueue(Requestreq) 
{
    req.setTag(TAG);
    getRequestQueue().add(req);
}

public void cancelPendingRequests(Object tag)
{
     if (mRequestQueue!= null) 
     {
        mRequestQueue.cancelAll(tag);
     }
   }
}

8. To execute this class as the app runs, add it inside the Manifest file under tag as follows:

<application
android:name=".AppController"/>

9. Create java class named “LruBitmapCache” to handle image sizes and its action:This class is indispensable because it plays a major role in lazy loading concept by freeing up the loaded bitmaps and recycling the child views when we do not require them.

public class LruBitmapCacheextends LruCacheimplements ImageLoader.ImageCache{
   public static intgetDefaultLruCacheSize(){
     final intmaxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
     final intcacheSize = maxMemory / 8;
     return cacheSize;
     }
   public LruBitmapCache(){
     this(getDefaultLruCacheSize());
   }
  public LruBitmapCache(intsizeInKiloBytes){
    super(sizeInKiloBytes);
   }
  @Override
  protected intsizeOf(String key, Bitmap value){
  return value.getRowBytes() * value.getHeight() / 1024;
  }
 @Override
 public Bitmap getBitmap(String url){
  return get(url);
 }
 @Override
 public void putBitmap(String url, Bitmap bitmap){
        put(url, bitmap);
 }
}

10. Create an xml file named list_row.xml to represent custom list design:Here instead of ImageView, we will use another tool namedNetworkImageView, which is a component of Volley library as follows

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">

<com.android.volley.toolbox.NetworkImageView
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="@+id/imageView1"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />

</RelativeLayout>

Remember to always use NetworkImageView only when fetching images from server and displaying for lazy loading.

11. Create Adapter class “CustomListAdapter” to pull out the contents from ListView:

public class CustomListAdapterextends BaseAdapter
{
  private Activity activity;
  private LayoutInflaterinflater;
  private Listmylist;
  ImageLoaderimageLoader= AppController.getInstance().getImageLoader();

  public CustomListAdapter(Activity activity, Listmylist)
  {
    this.activity= activity;
    this.mylist= mylist;
  }
  @Override
  public intgetCount() {
    return mylist.size();
  }

 @Override
 public Object getItem(intlocation) {
   return mylist.get(location);
 }

 @Override
 public long getItemId(intposition) {
  return position;
 }

 @Override
 public View getView(intposition, View convertView, ViewGroup parent) {
 if (inflater== null) {
 inflater= (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 }

 if (convertView == null) {
  convertView = inflater.inflate(R.layout.list_row, null);
  }
if (imageLoader== null) {
  imageLoader= AppController.getInstance().getImageLoader();
}
 NetworkImageViewimg = (NetworkImageView) convertView.findViewById(R.id.imageView1);

        // getting data for the row, here we will get only the image and nothing else
 ImagesModel m = mylist.get(position);
 img.setImageUrl(m.getImagepath(),imageLoader);
 return convertView;
    }
}

12. Finally, code in the MainActivity.java class:This class would contain code to retrieve data from Json object and Json array, catch all exceptions and display data in List –

public class MainActivityextends AppCompatActivity {

  private static final String TAG = MainActivity.class.getSimpleName();
  private static final String url= "http://igeniusdev.com/igeniusapps/rest_api_list/get_more_apps?AppID=5";
  private ProgressDialogpDialog;
  private Listmylist= new ArrayList();
  private ListViewlistView;
  private CustomListAdapteradapter;

  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    listView= (ListView) findViewById(R.id.listView);
    adapter = new CustomListAdapter(MainActivity.this, mylist);
    listView.setAdapter(adapter);

    pDialog= new ProgressDialog(this);
    // Showing progress dialog before making http request
    pDialog.setMessage("Loading Apps...");
    pDialog.show();

   JsonObjectRequestjsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, new Response.Listener()
   {
    @Override
    public void onResponse(JSONObject response)
    {
      hidePDialog();
       try
       {
           JSONArrayjsonArray = response.getJSONArray("Data");

           for (inti = 0; i parent, View view, intposition, long id)
           {
                 Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                 startActivity(browserIntent); 
           }
        }
       catch (Exception e)
            {
                    e.printStackTrace();
            }
       adapter.notifyDataSetChanged();
            }
        },
    new Response.ErrorListener()
    {
     @Override
     public void onErrorResponse(VolleyError error)
     {
      //Toast.makeText(MainActivity.this,"Volley error",Toast.LENGTH_LONG).show();
      VolleyLog.d(TAG, "Error: " + error.getMessage());

      if (error instanceofTimeoutError || error instanceofNoConnectionError) {
        Toast.makeText(MainActivity.this, "Time out or No connection", Toast.LENGTH_LONG).show();
        }
      else if (error instanceofAuthFailureError){
          Toast.makeText(MainActivity.this, "Auth fail error", Toast.LENGTH_LONG).show();
        }
      else if (error instanceofServerError){
          Toast.makeText(MainActivity.this, "Server error", Toast.LENGTH_LONG).show();
        }

     else if (error instanceofNetworkError) {
        Toast.makeText(MainActivity.this, "Network error", Toast.LENGTH_LONG).show();
        }
     else if (error instanceofParseError){
        Toast.makeText(MainActivity.this, "Parse error", Toast.LENGTH_LONG).show();
        }
         hidePDialog();
        }
    });

AppController.getInstance().addToRequestQueue(jsonObjectRequest);
  }

@Override
public void onDestroy() {
super.onDestroy();
hidePDialog();
}

private void hidePDialog(){
 if (pDialog!= null){
   pDialog.dismiss();
   pDialog= null;
  }
 }
}

Now run the project and witness the most exciting and modern means of loading images from server.

The screen-shot of final output is given as follows –

Let's Think together, Say Something !