Ошибка Android Volley в getInstance (это) при добавлении ImageLoader

Я следую руководству по кэшированию изображений с помощью Volley для разработчиков Android. У меня возникла проблема с запросом запроса изображения. и кэширование, я думаю, из-за созданного мною синглтона (скопировано из туториала).

Мое Eclipse выдает ошибку в getInstance(this), потому что это контекст, и я думаю, что запрашиваю изображение.

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);

Это синглтон:

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;
    }
}

Я могу получить изображение и отобразить его таким образом, но мне нужно его кэшировать, поэтому я думаю, что добавить его в запрос, верно? .. любая помощь ?

mNetworkImageView = (NetworkImageView) findViewById(R.id.ImageView);
mImageLoader = MySingleton.getInstance(this).getImageLoader();
mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);

person Moudiz    schedule 12.08.2015    source источник
comment
Основы Java: что означает this, как использовать внешний класс внутри реализации анонимного интерфейса   -  person Selvin    schedule 12.08.2015
comment
@Selvin Я думал, что это относится к контексту действия, как это действие. в любом случае, я до сих пор не понимаю, как решить мою проблему, я думаю, вы не знаете, как правильно использовать залп?   -  person Moudiz    schedule 12.08.2015
comment
Я знаю, как использовать залп, но вы не знаете java ... И какой смысл получать экземпляр singleton, когда в onResponse у вас уже есть растровое изображение?   -  person Selvin    schedule 12.08.2015
comment
@Selvin Я изучаю java, теперь я гуглю о this, чтобы обновить свои знания о java, и если вы знаете залп, не могли бы вы помочь мне с моим вопросом?   -  person Moudiz    schedule 12.08.2015
comment
хорошо, это то, что описано в учебнике, я упомянул в своем вопросе, что onResponse не работает, поэтому моя работа с синглтоном должна удалить экземпляр? @Селвин   -  person Moudiz    schedule 12.08.2015
comment
Вы должны поставить logcat (сообщение об ошибке) для получения дополнительной информации.   -  person BNK    schedule 13.08.2015
comment
@ChungPham Я не смог запустить приложение, потому что у меня была синтаксическая ошибка, ошибка, описанная в вопросе, здесь mImageLoader = MySingleton.getInstance(this).getImageLoader(); из-за instace все, что я хочу, это способ отправить это mNetworkImageView = (NetworkImageView) findViewById (R.id.ImageView); mImageLoader = MySingleton.getInstance(this).getImageLoader(); mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader); как запрос и кешировать его .. вы можете мне помочь с этим?   -  person Moudiz    schedule 13.08.2015
comment
Я только что добавил свой ответ.   -  person BNK    schedule 13.08.2015
comment
@Moudiz В приведенном выше коде вы фактически добавляете ImageCache в new ImageLoader.ImageCache() { ... } в классе MySingleton.   -  person hata    schedule 13.08.2015
comment
@hata, так что запрос не нужен, потому что синглтон?   -  person Moudiz    schedule 13.08.2015
comment
@Moudiz Экземпляр (mImageLoader), который вы получаете в mImageLoader = MySingleton.getInstance(this).getImageLoader();, уже был проверен с помощью ImageCache в MySingleton. Нет необходимости в дополнительной операции для включения кэширования.   -  person hata    schedule 13.08.2015
comment
@hata хорошо, да, я тебя понимаю, но в руководстве по Android они сказали, что мне нужно сделать request.. мой вопрос в загрузчике изображений, мне не нужно было делать запрос, я смог получить изображение без запроса. понял меня сейчас?   -  person Moudiz    schedule 13.08.2015
comment
@hata, кстати, глупый вопрос, но как работают наличные? Я назначил новый ImageLoader.ImageCache() в singleton, я открыл приложение и увидел изображение, когда я закрыл приложение, изображение исчезло, не должно ли изображение остаться, потому что оно кэшировано?   -  person Moudiz    schedule 13.08.2015
comment
@Moudiz Когда вы setImageUrl на mNetworkImageView, imageLoader выполняет ImageRequest внутренне.   -  person hata    schedule 13.08.2015
comment
@Moudiz ImageCache – это кеш L1. Это означает, что он находится только во время запуска приложения. Volley также имеет внутренний кэш L2 (DiskBasedCache). Его размер составляет 5 МБ.   -  person hata    schedule 13.08.2015
comment
@hata Я кое-что искал в Google по поводу DiskBasedCache, но я не смог найти ничего полезного в руководстве или примерах по этому поводу, особенно было несколько проблемы с производительностью , мы очень ценим вашу информацию и помощь   -  person Moudiz    schedule 13.08.2015
comment
@Moudiz Вам следует прочитать исходный код Volley, если вас интересует DiskBasedCache. И такие обсуждения не поддаются комментариям. Если у вас есть дополнительные вопросы, пожалуйста, опубликуйте новые вопросы.   -  person hata    schedule 14.08.2015
comment
Давайте продолжим это обсуждение в чате.   -  person Moudiz    schedule 14.08.2015


Ответы (3)


Это мой рабочий пример кода. Надеюсь, что это поможет:

Основная активность.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>
person BNK    schedule 13.08.2015
comment
Я попробовал ваш пример, но когда я закрываю приложение, а затем открываю его, изображение исчезает, как тогда изображение должно быть кэшировано? - person Moudiz; 13.08.2015
comment
что, если я хочу добавить DiskBasedCache? не могли бы вы добавить это в свой пример? - person Moudiz; 13.08.2015
comment
Я думаю, вы можете найти больше информации о кэшировании здесь. Попробуйте увеличить размер кэша. Удачи! - person BNK; 14.08.2015
comment
Привет! Я обновил свой ответ. Посмотрите на Volley.newRequestQueue(mContext.getApplicationContext(), 10 * 1024 * 1024);, это для кеширования - person BNK; 17.08.2015
comment
Должен ли я добавить diskcache? и теперь я пытаюсь показать изображения в адаптере arraylist, у вас есть готовый простой пример, с которым вы можете мне помочь? - person Moudiz; 17.08.2015
comment
Это diskcache, вы можете нажать Ctrl-B на newRequestQueue, чтобы просмотреть более подробную информацию (которая будет newRequestQueue(Context context, int maxDiskCacheBytes)) - person BNK; 17.08.2015
comment
о, хорошо, плохо, проверьте, большое спасибо, у меня есть еще один вопрос, который я следил за этим tutoria android-custom-listview-with-image-and-text-using-volleyl, и это сработало хорошо. но у меня проблема с реализацией в его коде diskcache, у вас есть простой пример с вашим кодом для отображения загрузчика изображений в списке? - person Moudiz; 17.08.2015
comment
хорошо, в любом случае, спасибо, сегодня вечером я опубликую, что я уже сделал в своем коде, и если вы можете мне помочь, это было бы здорово: d - person Moudiz; 17.08.2015
comment
Попробуйте приведенный выше newRequestQueue для вашего примера списка и проверьте, кэшируется он или нет. - person BNK; 17.08.2015

Вы находитесь в неправильном контексте.. инициализируйте член класса

private final Context ctx = this; 

и чем использовать ctx внутри onResponse

mImageLoader = MySingleton.getInstance(ctx).getImageLoader();
person Alexander Sidikov Pfeif    schedule 13.08.2015

Одним из предложений по оптимизации для метода getInstance является использование блокировки с двойной проверкой, поскольку она синхронизируется только в том случае, если экземпляр фактически равен нулю:

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;
}

Дополнительную информацию о синглтонах и различных способах их создания можно найти здесь.

Ключевое слово volatile гарантирует, что поле сразу же будет видно всем потокам и не кэшируется локально в потоке. Если для getInstance не требуется контекст, в ссылке описан другой метод, который был бы более подходящим, чем блокировка с двойной проверкой.

person AgentKnopf    schedule 20.11.2015