androidandroid-studioandroid-cameramanifestuniversal-image-loader

ImageLoader must be init with configuration before using


I get this error when i try to capture image or upload image from gallery to firebase. I know this question has been asked before however I tried all the possible solutions.

This is the Manifest file :

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

The following is the logcat report :

ImageLoader must be init with configuration before using
    at com.nostra13.universalimageloader.core.ImageLoader.checkConfiguration(ImageLoader.java:613)
    at com.nostra13.universalimageloader.core.ImageLoader.displayImage(ImageLoader.java:236)
    at com.nostra13.universalimageloader.core.ImageLoader.displayImage(ImageLoader.java:209)
    at com.nostra13.universalimageloader.core.ImageLoader.displayImage(ImageLoader.java:316)
    at com.example.sahil.ignite.util.UniversalImageLoader.setImage(UniversalImageLoader.java:55)
    at com.example.sahil.ignite.fragments.PostFragment.getImagePath(PostFragment.java:48)
    at com.example.sahil.ignite.SelectPhotoDialog.onActivityResult(SelectPhotoDialog.java:72)
    at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:156)
    at android.app.Activity.dispatchActivityResult(Activity.java:6317)

PostFragment.java

    public class PostFragment extends Fragment implements SelectPhotoDialog.OnPhotoSelectedListener {

private static final String TAG = "PostFragment";

@Override
public void getImagePath(Uri imagePath) {
    Log.d(TAG, "getImagePath: setting the image to imageview");
    UniversalImageLoader.setImage(imagePath.toString(), mPostImage);
    //assign to global variable
    mSelectedBitmap = null;
    mSelectedUri = imagePath;
}

@Override
public void getImageBitmap(Bitmap bitmap) {
    Log.d(TAG, "getImageBitmap: setting the image to imageview");
    mPostImage.setImageBitmap(bitmap);
    //assign to a global variable
    mSelectedUri = null;
    mSelectedBitmap = bitmap;
}

//widgets
private ImageView mPostImage;
private EditText mTitle, mDescription, mPrice, mCountry, mStateProvince, mCity, mContactEmail;
private Button mPost;
private ProgressBar mProgressBar;

//vars
private Bitmap mSelectedBitmap;
private Uri mSelectedUri;
private byte[] mUploadBytes;
private double mProgress = 0;


@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_post, container, false);
    mPostImage = view.findViewById(R.id.post_image);
    mTitle = view.findViewById(R.id.input_title);
    mDescription = view.findViewById(R.id.input_description);
    mPrice = view.findViewById(R.id.input_price);
    mCountry = view.findViewById(R.id.input_country);
    mStateProvince = view.findViewById(R.id.input_state_province);
    mCity = view.findViewById(R.id.input_city);
    mContactEmail = view.findViewById(R.id.input_email);
    mPost = view.findViewById(R.id.btn_post);
    mProgressBar = (ProgressBar) view.findViewById(R.id.progressBar);

    getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

    init();

    return view;
}

private void init(){

    mPostImage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(TAG, "onClick: opening dialog to choose new photo");
            SelectPhotoDialog dialog = new SelectPhotoDialog();
            dialog.show(getFragmentManager(), getString(R.string.dialog_select_photo));
            dialog.setTargetFragment(PostFragment.this, 1);
        }
    });

    mPost.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(TAG, "onClick: attempting to post...");
            if(!isEmpty(mTitle.getText().toString())
                    && !isEmpty(mDescription.getText().toString())
                    && !isEmpty(mPrice.getText().toString())
                    && !isEmpty(mCountry.getText().toString())
                    && !isEmpty(mStateProvince.getText().toString())
                    && !isEmpty(mCity.getText().toString())
                    && !isEmpty(mContactEmail.getText().toString())){

                //we have a bitmap and no Uri
                if(mSelectedBitmap != null && mSelectedUri == null){
                    uploadNewPhoto(mSelectedBitmap);
                }
                //we have no bitmap and a uri
                else if(mSelectedBitmap == null && mSelectedUri != null){
                    uploadNewPhoto(mSelectedUri);
                }
            }else{
                Toast.makeText(getActivity(), "You must fill out all the fields", Toast.LENGTH_SHORT).show();
            }
        }
    });
}

private void uploadNewPhoto(Bitmap bitmap){
    Log.d(TAG, "uploadNewPhoto: uploading a new image bitmap to storage");
    BackgroundImageResize resize = new BackgroundImageResize(bitmap);
    Uri uri = null;
    resize.execute(uri);
}

private void uploadNewPhoto(Uri imagePath){
    Log.d(TAG, "uploadNewPhoto: uploading a new image uri to storage.");
    BackgroundImageResize resize = new BackgroundImageResize(null);
    resize.execute(imagePath);
}

public class BackgroundImageResize extends AsyncTask<Uri, Integer, byte[]>{

    Bitmap mBitmap;

    public BackgroundImageResize(Bitmap bitmap) {
        if(bitmap != null){
            this.mBitmap = bitmap;
        }
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        Toast.makeText(getActivity(), "compressing image", Toast.LENGTH_SHORT).show();
        showProgressBar();
    }

    @Override
    protected byte[] doInBackground(Uri... params) {
        Log.d(TAG, "doInBackground: started.");

        if(mBitmap == null){
            try{
                RotateBitmap rotateBitmap = new RotateBitmap();
                mBitmap = rotateBitmap.HandleSamplingAndRotationBitmap(getActivity(), params[0]);
            }catch (IOException e){
                Log.e(TAG, "doInBackground: IOException: " + e.getMessage());
            }
        }
        byte[] bytes = null;
        Log.d(TAG, "doInBackground: megabytes before compression: " + mBitmap.getByteCount() / 1000000 );
        bytes = getBytesFromBitmap(mBitmap, 100);
        Log.d(TAG, "doInBackground: megabytes before compression: " + bytes.length / 1000000 );
        return bytes;
    }

    @Override
    protected void onPostExecute(byte[] bytes) {
        super.onPostExecute(bytes);
        mUploadBytes = bytes;
        hideProgressBar();
        //execute the upload task
        executeUploadTask();
    }
}

private void executeUploadTask(){
    Toast.makeText(getActivity(), "uploading image", Toast.LENGTH_SHORT).show();

    final String postId = FirebaseDatabase.getInstance().getReference().push().getKey();

    final StorageReference storageReference = FirebaseStorage.getInstance().getReference()
            .child("posts/users/" + FirebaseAuth.getInstance().getCurrentUser().getUid() +
                    "/" + postId + "/post_image");

    UploadTask uploadTask = storageReference.putBytes(mUploadBytes);
    uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
            Toast.makeText(getActivity(), "Post Success", Toast.LENGTH_SHORT).show();

            //insert the download url into the firebase database
            Uri firebaseUri = taskSnapshot.getDownloadUrl();

            Log.d(TAG, "onSuccess: firebase download url: " + firebaseUri.toString());
            DatabaseReference reference = FirebaseDatabase.getInstance().getReference();

            Post post = new Post();
            post.setImage(firebaseUri.toString());
            post.setCity(mCity.getText().toString());
            post.setContact_email(mContactEmail.getText().toString());
            post.setCountry(mCountry.getText().toString());
            post.setDescription(mDescription.getText().toString());
            post.setPost_id(postId);
            post.setPrice(mPrice.getText().toString());
            post.setState_province(mStateProvince.getText().toString());
            post.setTitle(mTitle.getText().toString());
            post.setUser_id(FirebaseAuth.getInstance().getCurrentUser().getUid());

            reference.child(getString(R.string.node_posts))
                    .child(postId)
                    .setValue(post);

            resetFields();
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Toast.makeText(getActivity(), "could not upload photo", Toast.LENGTH_SHORT).show();
        }
    }).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
            double currentProgress = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
            if( currentProgress > (mProgress + 15)){
                mProgress = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
                Log.d(TAG, "onProgress: upload is " + mProgress + "& done");
                Toast.makeText(getActivity(), mProgress + "%", Toast.LENGTH_SHORT).show();
            }
        }
    });
}

public static byte[] getBytesFromBitmap(Bitmap bitmap, int quality){
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, quality,stream);
    return stream.toByteArray();
}


private void resetFields(){
    UniversalImageLoader.setImage("", mPostImage);
    mTitle.setText("");
    mDescription.setText("");
    mPrice.setText("");
    mCountry.setText("");
    mStateProvince.setText("");
    mCity.setText("");
    mContactEmail.setText("");
}

private void showProgressBar(){
    mProgressBar.setVisibility(View.VISIBLE);

}

private void hideProgressBar(){
    if(mProgressBar.getVisibility() == View.VISIBLE){
        mProgressBar.setVisibility(View.INVISIBLE);
    }
}

/**
 * Return true if the @param is null
 * @param string
 * @return
 */
private boolean isEmpty(String string){
    return string.equals("");
}

SelectPhotoDialog.java

public class SelectPhotoDialog extends DialogFragment{

private static final String TAG = "SelectPhotoDialog";
private static final int PICKFILE_REQUEST_CODE = 1234;
private static final int CAMERA_REQUEST_CODE = 4321;

public interface OnPhotoSelectedListener{
    void getImagePath(Uri imagePath);
    void getImageBitmap(Bitmap bitmap);
}
OnPhotoSelectedListener mOnPhotoSelectedListener;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.dialog_selectphoto, container, false);



    TextView selectPhoto = (TextView) view.findViewById(R.id.dialogChoosePhoto);
    selectPhoto.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(TAG, "onClick: accessing phones memory.");
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.setType("image/*");
            startActivityForResult(intent, PICKFILE_REQUEST_CODE);
        }
    });

    TextView takePhoto = (TextView) view.findViewById(R.id.dialogOpenCamera);
    takePhoto.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(TAG, "onClick: starting camera.");
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(intent, CAMERA_REQUEST_CODE);
        }
    });
    return view;
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    /*
        Results when selecting a new image from memory
     */
    if(requestCode == PICKFILE_REQUEST_CODE && resultCode == Activity.RESULT_OK){
        Uri selectedImageUri = data.getData();
        Log.d(TAG, "onActivityResult: image uri: " + selectedImageUri);

        //send the uri to PostFragment & dismiss dialog
        mOnPhotoSelectedListener.getImagePath(selectedImageUri);
        getDialog().dismiss();
    }
    /*
        Results when taking a new photo with camera
     */
    else if(requestCode == CAMERA_REQUEST_CODE && resultCode == Activity.RESULT_OK){
        Log.d(TAG, "onActivityResult: done taking new photo");
        Bitmap bitmap;
        bitmap = (Bitmap) data.getExtras().get("data");

        //send the bitmap to PostFragment and dismiss dialog
        mOnPhotoSelectedListener.getImageBitmap(bitmap);
        getDialog().dismiss();
    }
}

@Override
public void onAttach(Context context) {
    try{
        mOnPhotoSelectedListener = (OnPhotoSelectedListener) getTargetFragment();
    }catch (ClassCastException e){
        Log.e(TAG, "onAttach: ClassCastException: " + e.getMessage() );
    }
    super.onAttach(context);
}
}

UniversalImageLoader.java

public class UniversalImageLoader {

private static final int defaultImage = R.drawable.ic_name;
private Context mContext;

public UniversalImageLoader(Context context) {
    mContext = context;
}

public ImageLoaderConfiguration getConfig(){
    DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
            .showImageOnLoading(defaultImage)
            .showImageForEmptyUri(defaultImage)
            .showImageOnFail(defaultImage)
            .considerExifParams(true)
            .cacheOnDisk(true).cacheInMemory(true)
            .cacheOnDisk(true).resetViewBeforeLoading(true)
            .imageScaleType(ImageScaleType.EXACTLY)
            .displayer(new FadeInBitmapDisplayer(300)).build();

    ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(mContext)
            .defaultDisplayImageOptions(defaultOptions)
            .memoryCache(new WeakMemoryCache())
            .diskCacheSize(100 * 1024 * 1024).build();

    return configuration;
}

/**
 * this method can be sued to set images that are static. It can't be used if the images
 * are being changed in the Fragment/Activity - OR if they are being set in a list or
 * a grid
 * @param imgURL
 * @param image
 */
public static void setImage(String imgURL, ImageView image){

    ImageLoader imageLoader = ImageLoader.getInstance();
    imageLoader.displayImage(imgURL, image);
}
}

RotateBitmap.java

    public class RotateBitmap {

private static final String TAG = "RotateBitmap";

private Context mContext;

/*
----------------------------- Image Rotation --------------------------------------------------
 */

private static Bitmap rotateImage(Bitmap img, int degree) {
    Matrix matrix = new Matrix();
    matrix.postRotate(degree);
    Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
    img.recycle();
    return rotatedImg;
}

/**
 * This method is responsible for solving the rotation issue if exist. Also scale the images to
 * 1024x1024 resolution
 *
 * @param selectedImage The Image URI
 * @return Bitmap image results
 * @throws IOException
 */
public Bitmap HandleSamplingAndRotationBitmap(Context context, Uri selectedImage)
        throws IOException {
    mContext = context;
    int MAX_HEIGHT = 1024;
    int MAX_WIDTH = 1024;

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
    BitmapFactory.decodeStream(imageStream, null, options);
    imageStream.close();

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    imageStream = context.getContentResolver().openInputStream(selectedImage);
    Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);

    img = rotateImageIfRequired(img, selectedImage);
    return img;
}


private static int calculateInSampleSize(BitmapFactory.Options options,
                                         int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee a final image
        // with both dimensions larger than or equal to the requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

        // This offers some additional logic in case the image has a strange
        // aspect ratio. For example, a panorama may have a much larger
        // width than height. In these cases the total pixels might still
        // end up being too large to fit comfortably in memory, so we should
        // be more aggressive with sample down the image (=larger inSampleSize).

        final float totalPixels = width * height;

        // Anything more than 2x the requested pixels we'll sample down further
        final float totalReqPixelsCap = reqWidth * reqHeight * 2;

        while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
            inSampleSize++;
        }
    }
    return inSampleSize;
}

/**
 * Rotate an image if required.
 *
 * @param img           The image bitmap
 * @param selectedImage Image URI
 * @return The resulted Bitmap after manipulation
 */
private Bitmap rotateImageIfRequired(Bitmap img, Uri selectedImage) throws IOException {

    InputStream input = mContext.getContentResolver().openInputStream(selectedImage);
    ExifInterface ei;
    try {
        ei = new ExifInterface(input);

        int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                return rotateImage(img, 90);
            case ExifInterface.ORIENTATION_ROTATE_180:
                return rotateImage(img, 180);
            case ExifInterface.ORIENTATION_ROTATE_270:
                return rotateImage(img, 270);
            default:
                return img;
        }
    } catch (NullPointerException e) {
        Log.e(TAG, "rotateImageIfRequired: Could not read file." + e.getMessage());
    }
    return img;
}
}

Solution

  • You haven't initialized ImageLoader in your onCreateView. Add this line after onCreateView:

    ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(getActivity()));
    

    From the library documentation:

    1. Application or Activity class (before the first usage of ImageLoader)
    public class MyActivity extends Activity {
        @Override
        public void onCreate() {
            super.onCreate();
    
            // Create global configuration and initialize ImageLoader with this config
            ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
                ...
                .build();
            ImageLoader.getInstance().init(config);
            ...
        }
    }