Android Open Source - Android-CleanArchitecture Auto Load Image View






From Project

Back to project page Android-CleanArchitecture.

License

The source code is released under:

Apache License

If you think the Android project Android-CleanArchitecture listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * Copyright (C) 2014 android10.org. All rights reserved.
 * @author Fernando Cejas (the android10 coder)
 *///from ww  w  .j  a  v  a  2s.  co  m
package com.fernandocejas.android10.sample.presentation.view.component;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

/**
 * Simple implementation of {@link android.widget.ImageView} with extended features like setting an
 * image from an url and an internal file cache using the application cache directory.
 */
public class AutoLoadImageView extends ImageView {

  private static final String BASE_IMAGE_NAME_CACHED = "image_";

  private int imagePlaceHolderResourceId = -1;
  private DiskCache cache = new DiskCache(getContext().getCacheDir());

  public AutoLoadImageView(Context context) {
    super(context);
  }

  public AutoLoadImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public AutoLoadImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  /**
   * Set an image from a remote url.
   *
   * @param imageUrl The url of the resource to load.
   */
  public void setImageUrl(final String imageUrl) {
    AutoLoadImageView.this.loadImagePlaceHolder();
    if (imageUrl != null) {
      this.loadImageFromUrl(imageUrl);
    } else {
      this.loadImagePlaceHolder();
    }
  }

  /**
   * Set a place holder used for loading when an image is being downloaded from the internet.
   *
   * @param resourceId The resource id to use as a place holder.
   */
  public void setImagePlaceHolder(int resourceId) {
    this.imagePlaceHolderResourceId = resourceId;
    this.loadImagePlaceHolder();
  }

  /**
   * Invalidate the internal cache by evicting all cached elements.
   */
  public void invalidateImageCache() {
    if (this.cache != null) {
      this.cache.evictAll();
    }
  }

  /**
   * Loads and image from the internet (and cache it) or from the internal cache.
   *
   * @param imageUrl The remote image url to load.
   */
  private void loadImageFromUrl(final String imageUrl) {
    new Thread() {
      @Override public void run() {
        final Bitmap bitmap = AutoLoadImageView.this.getFromCache(getFileNameFromUrl(imageUrl));
        if (bitmap != null) {
          AutoLoadImageView.this.loadBitmap(bitmap);
        } else {
          if (isThereInternetConnection()) {
            final ImageDownloader imageDownloader = new ImageDownloader();
            imageDownloader.download(imageUrl, new ImageDownloader.Callback() {
              @Override public void onImageDownloaded(Bitmap bitmap) {
                AutoLoadImageView.this.cacheBitmap(bitmap, getFileNameFromUrl(imageUrl));
                AutoLoadImageView.this.loadBitmap(bitmap);
              }

              @Override public void onError() {
                AutoLoadImageView.this.loadImagePlaceHolder();
              }
            });
          } else {
            AutoLoadImageView.this.loadImagePlaceHolder();
          }
        }
      }
    }.start();
  }

  /**
   * Run the operation of loading a bitmap on the UI thread.
   *
   * @param bitmap The image to load.
   */
  private void loadBitmap(final Bitmap bitmap) {
    ((Activity) getContext()).runOnUiThread(new Runnable() {
      @Override public void run() {
        AutoLoadImageView.this.setImageBitmap(bitmap);
      }
    });
  }

  /**
   * Loads the image place holder if any has been assigned.
   */
  private void loadImagePlaceHolder() {
    if (this.imagePlaceHolderResourceId != -1) {
      ((Activity) getContext()).runOnUiThread(new Runnable() {
        @Override public void run() {
          AutoLoadImageView.this.setImageResource(
              AutoLoadImageView.this.imagePlaceHolderResourceId);
        }
      });
    }
  }

  /**
   * Get a {@link android.graphics.Bitmap} from the internal cache or null if it does not exist.
   *
   * @param fileName The name of the file to look for in the cache.
   * @return A valid cached bitmap, otherwise null.
   */
  private Bitmap getFromCache(String fileName) {
    Bitmap bitmap = null;
    if (this.cache != null) {
      bitmap = this.cache.get(fileName);
    }
    return bitmap;
  }

  /**
   * Cache an image using the internal cache.
   *
   * @param bitmap The bitmap to cache.
   * @param fileName The file name used for caching the bitmap.
   */
  private void cacheBitmap(Bitmap bitmap, String fileName) {
    if (this.cache != null) {
      this.cache.put(bitmap, fileName);
    }
  }

  /**
   * Checks if the device has any active internet connection.
   *
   * @return true device with internet connection, otherwise false.
   */
  private boolean isThereInternetConnection() {
    boolean isConnected;

    ConnectivityManager connectivityManager =
        (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    isConnected = (networkInfo != null && networkInfo.isConnectedOrConnecting());

    return isConnected;
  }

  /**
   * Creates a file name from an image url
   *
   * @param imageUrl The image url used to build the file name.
   * @return An String representing a unique file name.
   */
  private String getFileNameFromUrl(String imageUrl) {
    //we could generate an unique MD5/SHA-1 here
    String hash = String.valueOf(imageUrl.hashCode());
    if (hash.startsWith("-")) {
      hash = hash.substring(1);
    }
    return BASE_IMAGE_NAME_CACHED + hash;
  }

  /**
   * Class used to download images from the internet
   */
  private static class ImageDownloader {
    interface Callback {
      void onImageDownloaded(Bitmap bitmap);

      void onError();
    }

    ImageDownloader() {}

    /**
     * Download an image from an url.
     *
     * @param imageUrl The url of the image to download.
     * @param callback A callback used to be reported when the task is finished.
     */
    void download(String imageUrl, Callback callback) {
      try {
        URLConnection conn = new URL(imageUrl).openConnection();
        conn.connect();
        Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream());
        if (callback != null) {
          callback.onImageDownloaded(bitmap);
        }
      } catch (MalformedURLException e) {
        reportError(callback);
      } catch (IOException e) {
        reportError(callback);
      }
    }

    /**
     * Report an error to the caller
     *
     * @param callback Caller implementing {@link Callback}
     */
    private void reportError(Callback callback) {
      if (callback != null) {
        callback.onError();
      }
    }
  }

  /**
   * A simple disk cache implementation
   */
  private static class DiskCache {

    private static final String TAG = "DiskCache";

    private final File cacheDir;

    DiskCache(File cacheDir) {
      this.cacheDir = cacheDir;
    }

    /**
     * Get an element from the cache.
     *
     * @param fileName The name of the file to look for.
     * @return A valid element, otherwise false.
     */
    synchronized Bitmap get(String fileName) {
      Bitmap bitmap = null;
      File file = buildFileFromFilename(fileName);
      if (file.exists()) {
        bitmap = BitmapFactory.decodeFile(file.getPath());
      }
      return bitmap;
    }

    /**
     * Cache an element.
     *
     * @param bitmap The bitmap to be put in the cache.
     * @param fileName A string representing the name of the file to be cached.
     */
    synchronized void put(Bitmap bitmap, String fileName) {
      File file = buildFileFromFilename(fileName);
      if (!file.exists()) {
        try {
          FileOutputStream fileOutputStream = new FileOutputStream(file);
          bitmap.compress(Bitmap.CompressFormat.PNG, 90, fileOutputStream);
          fileOutputStream.flush();
          fileOutputStream.close();
        } catch (FileNotFoundException e) {
          Log.e(TAG, e.getMessage());
        } catch (IOException e) {
          Log.e(TAG, e.getMessage());
        }
      }
    }

    /**
     * Invalidate and expire the cache.
     */
    void evictAll() {
      if (cacheDir.exists()) {
        for (File file : cacheDir.listFiles()) {
          file.delete();
        }
      }
    }

    /**
     * Creates a file name from an image url
     *
     * @param fileName The image url used to build the file name.
     * @return A {@link java.io.File} representing a unique element.
     */
    private File buildFileFromFilename(String fileName) {
      String fullPath = this.cacheDir.getPath() + File.separator + fileName;
      return new File(fullPath);
    }
  }
}




Java Source Code List

com.fernandocejas.android10.sample.data.cache.FileManager.java
com.fernandocejas.android10.sample.data.cache.UserCacheImpl.java
com.fernandocejas.android10.sample.data.cache.UserCache.java
com.fernandocejas.android10.sample.data.cache.serializer.JsonSerializer.java
com.fernandocejas.android10.sample.data.entity.UserEntity.java
com.fernandocejas.android10.sample.data.entity.mapper.UserEntityDataMapper.java
com.fernandocejas.android10.sample.data.entity.mapper.UserEntityJsonMapper.java
com.fernandocejas.android10.sample.data.exception.NetworkConnectionException.java
com.fernandocejas.android10.sample.data.exception.RepositoryErrorBundle.java
com.fernandocejas.android10.sample.data.exception.UserNotFoundException.java
com.fernandocejas.android10.sample.data.executor.JobExecutor.java
com.fernandocejas.android10.sample.data.net.ApiConnection.java
com.fernandocejas.android10.sample.data.net.RestApiImpl.java
com.fernandocejas.android10.sample.data.net.RestApi.java
com.fernandocejas.android10.sample.data.repository.UserDataRepository.java
com.fernandocejas.android10.sample.data.repository.datasource.CloudUserDataStore.java
com.fernandocejas.android10.sample.data.repository.datasource.DiskUserDataStore.java
com.fernandocejas.android10.sample.data.repository.datasource.UserDataStoreFactory.java
com.fernandocejas.android10.sample.data.repository.datasource.UserDataStore.java
com.fernandocejas.android10.sample.domain.User.java
com.fernandocejas.android10.sample.domain.exception.ErrorBundle.java
com.fernandocejas.android10.sample.domain.executor.PostExecutionThread.java
com.fernandocejas.android10.sample.domain.executor.ThreadExecutor.java
com.fernandocejas.android10.sample.domain.interactor.GetUserDetailsUseCaseImpl.java
com.fernandocejas.android10.sample.domain.interactor.GetUserDetailsUseCase.java
com.fernandocejas.android10.sample.domain.interactor.GetUserListUseCaseImpl.java
com.fernandocejas.android10.sample.domain.interactor.GetUserListUseCase.java
com.fernandocejas.android10.sample.domain.interactor.Interactor.java
com.fernandocejas.android10.sample.domain.repository.UserRepository.java
com.fernandocejas.android10.sample.presentation.UIThread.java
com.fernandocejas.android10.sample.presentation.exception.ErrorMessageFactory.java
com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper.java
com.fernandocejas.android10.sample.presentation.model.UserModel.java
com.fernandocejas.android10.sample.presentation.navigation.Navigator.java
com.fernandocejas.android10.sample.presentation.presenter.Presenter.java
com.fernandocejas.android10.sample.presentation.presenter.UserDetailsPresenter.java
com.fernandocejas.android10.sample.presentation.presenter.UserListPresenter.java
com.fernandocejas.android10.sample.presentation.view.LoadDataView.java
com.fernandocejas.android10.sample.presentation.view.UserDetailsView.java
com.fernandocejas.android10.sample.presentation.view.UserListView.java
com.fernandocejas.android10.sample.presentation.view.activity.BaseActivity.java
com.fernandocejas.android10.sample.presentation.view.activity.MainActivity.java
com.fernandocejas.android10.sample.presentation.view.activity.UserDetailsActivity.java
com.fernandocejas.android10.sample.presentation.view.activity.UserListActivity.java
com.fernandocejas.android10.sample.presentation.view.adapter.UsersAdapter.java
com.fernandocejas.android10.sample.presentation.view.adapter.UsersLayoutManager.java
com.fernandocejas.android10.sample.presentation.view.component.AutoLoadImageView.java
com.fernandocejas.android10.sample.presentation.view.fragment.BaseFragment.java
com.fernandocejas.android10.sample.presentation.view.fragment.UserDetailsFragment.java
com.fernandocejas.android10.sample.presentation.view.fragment.UserListFragment.java