gpt4 book ai didi

android - 如何使 Volley Request Activity 在 android 中独立?

转载 作者:行者123 更新时间:2023-11-29 01:08:05 24 4
gpt4 key购买 nike

我读了documentation关于通过创建单例类并将应用程序上下文传递给它来使网络请求 Activity 独立。我以类似的方式实现了它,但是我仍然发现在轮换时,应用程序在显示任何数据之前等待调用再次完成。那么我做错了什么以及如何正确设置它以便调用持续应用程序的生命周期,这样它就不会根据文档每次调用方向更改。我知道它可以使用加载器或改造或 okhttp 来完成,但我想知道如何使用 volley 来实现它

MainActivity.java

package com.example.imnobody.photosearch;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

private ImageGridAdapter imageGridAdapter;
private List<String> imageList;

public static final String URL = "API_HERE";

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

imageList = new ArrayList<>();
//imageList = QueryUtils.extractImages(SAMPLE_JSON_RESPONSE);


GridView gridView = (GridView) findViewById(R.id.gridview);
final TextView emptyTextView = (TextView)findViewById(android.R.id.empty);
gridView.setEmptyView(emptyTextView);

imageGridAdapter = new ImageGridAdapter(MainActivity.this,imageList);

gridView.setAdapter(imageGridAdapter);

gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {

Intent intent = new Intent(MainActivity.this,ImageActivity.class);
intent.putExtra("imageuri",imageList.get(position));
startActivity(intent);

}
});

StringRequest stringRequest = new StringRequest(Request.Method.GET, URL,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {

imageList = QueryUtils.extractImages(response); //extract needed things from json
imageGridAdapter.clear();
imageGridAdapter.addAll(imageList);

}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {

emptyTextView.setText("Unknown error occured");
}
});

VolleySingleton.getInstance(this.getApplicationContext()).addToRequestQueue(stringRequest);


}
}

VolleySingleton.java

package com.example.imnobody.photosearch;

import android.content.Context;
import android.graphics.Bitmap;

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

import android.support.v4.util.LruCache;

/**
* Created by imnobody on 7/8/17.
*/

public class VolleySingleton {

private static VolleySingleton mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mCtx;

private VolleySingleton(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 VolleySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new VolleySingleton(context);
}
return mInstance;
}

public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {

mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}

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

public ImageLoader getImageLoader() {
return mImageLoader;
}
}

最佳答案

好吧,有几点:

每次在 onCreate 中重新创建 Activity 时,您都会发出请求。从理论上讲,如果您真的需要在 Activity 打开时刷新数据,这不一定是坏事,因为 Volley 似乎在创建时自动为自己设置了一个 DiskBasedCache带有 newRequestQueueRequestQueue(参见 here)。

这意味着即使您在每次方向更改后发出新请求,Volley 也会为您获取缓存响应,而不是访问网络。通过启用详细日志记录,您应该可以看到 Volley 何时使用网络或缓存来处理请求。

要启用详细日志记录,请参阅此处:https://stackoverflow.com/a/23654407/2220337

但是,默认缓存仍然只是一个 Disk 缓存,它比内存缓存慢。如果你需要你的缓存更快,你可以通过实现 Cache 来实现你自己的内存缓存。接口(interface),然后按照 here 所述创建您的 RequestQueue ,并在构造函数中提供您自己的自定义内存缓存。

更好的方法是在方向更改后根本不发出请求,而是依靠 onSaveInstanceState/onRestoreInstanceState 来持久化然后恢复数据。这样,如果请求已经完成,您就不会在重新创建 Activity 时触发新请求。

相反,您只显示保存在 onSaveInstanceState 中的数据。

public class MainActivity extends AppCompatActivity {

public static final String URL = "API_HERE";
private static final String SAVED_RESPONSE = "SAVED_RESPONSE";
private ImageGridAdapter imageGridAdapter;
private List<String> imageList;
private GridView gridView;
private String savedResponse;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageList = new ArrayList<>();
gridView = (GridView) findViewById(R.id.gridview);
final TextView emptyTextView = (TextView) findViewById(android.R.id.empty);
gridView.setEmptyView(emptyTextView);
imageGridAdapter = new ImageGridAdapter(MainActivity.this, imageList);
gridView.setAdapter(imageGridAdapter);

gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {

Intent intent = new Intent(MainActivity.this, ImageActivity.class);
intent.putExtra("imageuri", imageList.get(position));
startActivity(intent);
}
});

if (savedInstanceState == null) {
//activity was created for the first time, fetch images
getImages();
} else {
//everything in this else branch can be moved in onRestoreInstanceState, this is just a matter of preference
savedResponse = savedInstanceState.getString(SAVED_RESPONSE);
if (savedResponse != null) {
refreshImages(savedResponse);
} else {
//an error occurred when the request was fired previously
((TextView) gridView.getEmptyView()).setText("Unknown error occured");
}
}
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SAVED_RESPONSE, savedResponse);
}

private void getImages() {
StringRequest stringRequest = new StringRequest(Request.Method.GET, URL,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
savedResponse = response;
refreshImages(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
savedResponse = null;
((TextView) gridView.getEmptyView()).setText("Unknown error occured");
}
});

VolleySingleton.getInstance(this.getApplicationContext()).addToRequestQueue(stringRequest);
}

private void refreshImages(String response) {
imageList = QueryUtils.extractImages(response); //extract needed things from json
imageGridAdapter.clear();
imageGridAdapter.addAll(imageList);
}

还请注意以下几点:

  • 如果您开始一个请求并且在它完成之前发生了方向更改,您将有内存泄漏,并且您的 Activity 将不会被垃圾回收。这是因为您的 stringRequest 是一个匿名内部类实例,它将隐式引用 MainActivity。

    为了避免这种情况,我在过去通过 Android 服务管理我的 Volley 请求和响应并通过粘性广播将响应转发到 UI 取得了不错的效果。事件总线也适用于此目的。

    广播需要保持粘性,以便在重新创建 Activity 时完成时不会丢失响应,因为在重新创建时它没有注册为广播接收器。通过发送粘性广播,它们会持续存在并允许我在 Android 完成重新创建我的 Activity 后读取数据。

  • 如果您的响应字符串是一个不是很大的 JSON,它指向一些稍后将被下载的在线图像,那么我提到的第二种方法应该没问题。但是,如果它包含 BASE64 编码图像,那么 Volley 的默认 DiskBasedCache 可能更适合缓存其数据。

希望这对您有所帮助!

关于android - 如何使 Volley Request Activity 在 android 中独立?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45536102/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com