Android Volley error in getInstance(this) when adding ImageLoader
Asked Answered
C

3

8

I am following up image cashing tutorial using Volley on Android developers, I am having problem with requesting an image request and caching it, I guess because of the singelton that I created (copied from the tutorial).

My Eclipse is giving error in the getInstance(this) because this is context and I am requesting an image I guess.

ImageRequest request = new ImageRequest(
    url,
    new Response.Listener<Bitmap>() {
        @Override
        public void onResponse(Bitmap bitmap) {
            mNetworkImageView = (NetworkImageView) findViewById(R.id.ImageView);
            mImageLoader = MySingleton.getInstance(this).getImageLoader();
            mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);
        //  mImageLoader = MySingleton.getInstance(this).getImageLoader();
        //  mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView,
        //      R.drawable.ic_launcher, R.drawable.ic_launcher));
            }
        },
    0,
    0,
    null,
    new Response.ErrorListener() {
        public void onErrorResponse(VolleyError error) {
        //  mImageView.setImageResource(R.drawable.ic_launcher);
        }
    });
MySingleton.getInstance(this).addToRequestQueue(request);

This is singleton:

package com.example.p;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class MySingleton {
    private static MySingleton mInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static Context mCtx;

    private MySingleton(Context context) {
        mCtx = context;
        mRequestQueue = getRequestQueue();

        mImageLoader = new ImageLoader(
            mRequestQueue,
            new ImageLoader.ImageCache() {
                private final LruCache<String, Bitmap>
                    cache = new LruCache<String, Bitmap>(20);

                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }

                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
    }

    public static synchronized MySingleton getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new MySingleton(context);
        }
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            // getApplicationContext() is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
        }
        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req) {
        getRequestQueue().add(req);
    }

    public ImageLoader getImageLoader() {
        return mImageLoader;
    }
}

I am able to get the image and display it in such way , but I need to cache it , so I guess it to add it in a request right ? .. any help ?

mNetworkImageView = (NetworkImageView) findViewById(R.id.ImageView);
mImageLoader = MySingleton.getInstance(this).getImageLoader();
mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);
Comstock answered 12/8, 2015 at 18:3 Comment(18)
Java's basics: what this means, how use outer class inside anonymous interface implementationSheikdom
@Sheikdom I thought it refers to the context of the activity, as this activity. anyway i still dont understand how to solve my above problem, I guess you dont know how to use volley right?Comstock
I know how to use volley, but you don't know java... Also what is the point of getting singleton instance when in onResponse you already have the bitmap?Sheikdom
@Sheikdom I am learning java , now I am googling about this to update my knowledge about java, and if you know volley can you help me with my question ?Comstock
well thats what it described in the tutorial , I mentioned in my question without the onResponse its working, so my the singleton work I should remove the instance ? @SheikdomComstock
You should put the logcat (error message) for more information.Bunche
@ChungPham I wasnt able to run the app because I had syntax error , the error as described in the question is here mImageLoader = MySingleton.getInstance(this).getImageLoader(); due to instace, all i want is a way to send this mNetworkImageView = (NetworkImageView) findViewById(R.id.ImageView); mImageLoader = MySingleton.getInstance(this).getImageLoader(); mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader); as request and cach it .. can you help me with that ?Comstock
I have just added my answer.Bunche
@Comstock In the above code you actually add ImageCache at new ImageLoader.ImageCache() { ... } in MySingleton class.Crosspurpose
@Crosspurpose so no need for a request because the singleton ?Comstock
@Comstock The instance (mImageLoader) you get at mImageLoader = MySingleton.getInstance(this).getImageLoader(); has already been convined with ImageCache in MySingleton. There is no need for additional operation for enabling caching.Crosspurpose
@Crosspurpose ok yes I understand you , but in the android tutorial they said I need to do a request.. my question is in the imageloader I didnt hadn't to do a request, I was able to get the image without a request . understand me now ?Comstock
@Crosspurpose btw a stupid question, but how does the cash work ? I assigned new ImageLoader.ImageCache() in singleton , I opened the app and I saw the image , when I closed the app the image diseapered, shouldnt the image stay because its cached ?Comstock
@Comstock When you setImageUrl on mNetworkImageView, the imageLoader does ImageRequest internally.Crosspurpose
@Comstock ImageCache is L1 Cache. That means it resides only during the app is launching. Volley also has internal L2 Cache (DiskBasedCache). It's size is 5MB.Crosspurpose
@Crosspurpose I was doing some google about DiskBasedCachebut I couldnt find anything helpful tutorial or examples about it especially there was some performance problems , your informations and help is really apreciatedComstock
@Comstock You should read the source code of Volley if you are interested in DiskBasedCache. And such discussions are beyond commenting. If you have further questions, please post new questions.Crosspurpose
Let us continue this discussion in chat.Comstock
B
5

This is my working sample code. Hope this help:

MainActivity.java:

import ...

public class MainActivity extends Activity {

    final Context mContext = this;   

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        NetworkImageView mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView);

        String mUrl = "http://192.168.0.100/api/getimage";
        mNetworkImageView.setImageUrl(mUrl, VolleySingleton.getInstance(mContext).getImageLoader());       
    }

    ...  

}

VolleySingleton.java:

public class VolleySingleton {
    private static VolleySingleton mInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static Context mContext;

    private VolleySingleton(Context context) {
        mContext = context;
        mRequestQueue = getRequestQueue();

        mImageLoader = new ImageLoader(mRequestQueue,
                new ImageLoader.ImageCache() {
                    private final LruCache<String, Bitmap>
                            cache = new LruCache<>(20);

                    @Override
                    public Bitmap getBitmap(String url) {
                        return cache.get(url);
                    }

                    @Override
                    public void putBitmap(String url, Bitmap bitmap) {
                        cache.put(url, bitmap);
                    }
                });
    }

    public static synchronized VolleySingleton getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new VolleySingleton(context);
        }
        return mInstance;
    }

    private RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            // getApplicationContext() is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext(), 10 * 1024 * 1024); // this for caching
        }
        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req) {
        getRequestQueue().add(req);
    }

    public ImageLoader getImageLoader() {
        return mImageLoader;
    }   
}

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    tools:context=".MainActivity">       

        <com.android.volley.toolbox.NetworkImageView
            android:id="@+id/networkImageView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />       

</LinearLayout>

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.volleyapp" >

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>        
    </application>

</manifest>
Bunche answered 13/8, 2015 at 14:25 Comment(9)
I tried your example but when I close the app then open it , the image disapear, how then the image should be cached ?Comstock
what if I want to add DiskBasedCache? can you please add it in your example ?Comstock
I think you can find more about caching here. Try increase your cache size. Goodluck!Bunche
Hi! I updated my answer. Look at Volley.newRequestQueue(mContext.getApplicationContext(), 10 * 1024 * 1024);, this is for cachingBunche
shoudlnt i add diskcache ? and now I am trying to show the images in arraylist adapter , do you a ready simple example that you can help me with ?Comstock
That's diskcache, you can press Ctrl-B at newRequestQueue to view more details (which will be newRequestQueue(Context context, int maxDiskCacheBytes))Bunche
oh nice ill check that thanks a alot , I have another question I was following this tutoria android-custom-listview-with-image-and-text-using-volleyl and it worked good. but I am have problem implementing in his code the diskcache , do u have a simple example with your code to display the imageloader in a listview ?Comstock
ok thanks anyway , tonight Ill post what I have already done in my code , and If you can help me that would be great :dComstock
Try the above newRequestQueue for your listview example and check if it caches or not.Bunche
D
1

You´r in the wrong Context .. init a class member

private final Context ctx = this; 

and than use ctx inside onResponse

mImageLoader = MySingleton.getInstance(ctx).getImageLoader();
Decennial answered 13/8, 2015 at 14:32 Comment(0)
L
1

One optimization suggestion for the getInstance method is to use double checked locking as it only synchronizes in case the instance is actually null:

private volatile static VolleySingleton self;

public static VolleySingleton getInstance(Context context) {
    if (self == null) {
        //Using double checked locking
        synchronized (VolleySingleton.class) {
            if (self == null) {
                //Using app context prevents leaking of activity context
                self = new VolleySingleton(context.getApplicationContext());
            }
        }
    }
    return self;
}

More information on singletons and the different ways of instantiating them can be found here.

The volatile keyword ensures, that the field is immediately seen by all threads and is not cached thread-locally. If the getInstance did not require a Context, there are other method explained in the link that would be more suitable than double checked locking.

Lopeared answered 20/11, 2015 at 19:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.