问题描述
我已经使用了异步任务,下载数据,然后显示我用缓存来存储影像,因为他们都在重复,但不是在命令列表视图中的图像。但图像被错杂,有时他们不下载。我试图寻找这一点,但未能找到。
这是我的梦想公司的问题之一,我没有因为这一点不明确。
请帮我身边。
公共类MainActivity扩展AppCompatActivity { 私有静态最后弦乐TAG =MainActivity;
私有静态最后弦乐BASE_URL =https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=android&start=;
私有静态最后弦乐IMAGE_JSON_KEY =unescapedUrl;
私有静态最后弦乐RESULTS_JSON_KEY =成果;
私有静态最后弦乐RESPONSE_DATA_JSON_KEY =responseData; 私人诠释mCurrentPage;
私人的ListView mListView;
私人语境mContext;
ArrayList的<串GT; mImageUrls;
私人LruCache<弦乐,位图> mCache;
私人CustomListAdapter mAdapter; @覆盖
保护无效的onCreate(捆绑savedInstanceState){
super.onCreate(savedInstanceState);
的setContentView(R.layout.activity_main); //获取内存类本设备,超过此量就会抛出
// OutOfMemory例外。
最终诠释memClass =((ActivityManager)getSystemService(Context.ACTIVITY_SERVICE))getMemoryClass()。 //使用可用内存的1/8这个内存缓存。
最终诠释的cachesize = 1024 * 1024 * memClass / 8; //初始化变量
mContext =这一点;
mCache =新LruCache<弦乐,位图>(CACHESIZE){ @覆盖
保护INT整型尺寸(字符串键,位值){
//缓存大小以字节为单位,而不是项目的数量来衡量。
返回value.getByteCount();
}
};
mListView =(ListView控件)findViewById(R.id.list_view);
mAdapter =新CustomListAdapter();
mImageUrls =新的ArrayList<>(); //如果URL是错误的,那么
如果(mImageUrls.isEmpty()|| checkDiff()){
fetchNewImageUrls();
} //适配器设置列表视图
mListView.setAdapter(mAdapter);
} 类BitmapWorkerTask扩展的AsyncTask<弦乐,太虚,位图> { 私人最终的WeakReference< ImageView的> imageViewReference;
私人字符串mUrl; 公共BitmapWorkerTask(ImageView的ImageView的){
//使用的WeakReference,确保ImageView的可以被垃圾收集
imageViewReference =新的WeakReference< ImageView的>(ImageView的);
} @覆盖
保护位图doInBackground(字符串... PARAMS){
字符串图片网址=参数[0];
mUrl =图片网址;
位图位图= getBitmapFromMemCache(图片网址); 如果(位图== NULL){
尝试{
网址URL =新的URL(图片网址);
HttpURLConnection的连接=(HttpURLConnection类)url.openConnection();
connection.setDoInput(真);
connection.connect(); //获取样本的大小后关闭流
为InputStream的InputStream = connection.getInputStream();
字节[] = imageByteArray convertToByteArray(InputStream的);
位=去codeSampledBitmap(imageByteArray,200,200);
inputStream.close(); 如果(位图!= NULL){
Log.d(TAG,图片下载+图片网址);
addBitmapToMemoryCache(图片网址,位图);
}其他{
Log.d(TAG,空位图下载了:+图片网址);
}
connection.disconnect();
}赶上(MalformedURLException的E){
e.printStackTrace();
}赶上(IOException异常五){
e.printStackTrace();
}
}其他{
Log.d(TAG,已经present在Cache);
}
返回位图;
} @覆盖
保护无效onPostExecute(位图位图){
如果(imageViewReference = NULL&放大器;!&安培;!=位图NULL){
最后ImageView的ImageView的=(ImageView的)imageViewReference.get(); 如果(ImageView的= NULL&放大器;!&安培; imageView.getTag()等于(mUrl)){
imageView.setImageBitmap(位图);
}
}
}
} 公共类CustomListAdapter延伸BaseAdapter { @覆盖
公众诠释的getCount(){
返回mImageUrls.size();
} @覆盖
公共对象的getItem(INT位置){
返回mImageUrls.get(位置);
} @覆盖
众长getItemId(INT位置){
返回的位置;
} @覆盖
公共查看getView(INT位置,查看convertView,父母的ViewGroup){
Log.d(TAG,获取视图被调用的位置:+位置); 查看查看= convertView;
持有人持有人= NULL; //持有再presents视图的元件使用
//这里初始化
如果(查看== NULL){
鉴于= LayoutInflater.from(mContext).inflate(R.layout.row_item,父母,假);
持有人=新的持有人();
holder.mRowImage =(ImageView的)view.findViewById(R.id.image_view);
holder.mRowText =(TextView中)view.findViewById(R.id.row_text);
view.setTag(保持器);
}其他{
支架=(座)view.getTag();
} //设置默认图像背景
holder.mRowImage.setImageResource(R.drawable.ic_launcher); //这里做的持有人变量实例操作
holder.mRowText.setText(图像编号+位置); //设置标签的ImageView的
holder.mRowImage.setTag(mImageUrls.get(位置)); 新BitmapWorkerTask(holder.mRowImage).execute(mImageUrls.get(位置));
返回视图。
}
} 公共静态类持有人{
TextView的mRowText;
ImageView的mRowImage;
} 公共无效addBitmapToMemoryCache(字符串键,位图位图){
如果(getBitmapFromMemCache(键)== NULL){
mCache.put(键,位图);
}
} 公共位图getBitmapFromMemCache(字符串键){
返回(位图)mCache.get(密钥);
} 公共位图德codeSampledBitmap(字节[] imageByteArray,INT reqWidth,诠释reqHeight){
位图BM = NULL; //首先去code。与inJustDe codeBounds = true来检查尺寸
最后BitmapFactory.Options选项=新BitmapFactory.Options();
options.inJustDe codeBounds = TRUE;
BitmapFactory.de codeByteArray的(imageByteArray,0,imageByteArray.length,期权); //计算inSampleSize
options.inSampleSize = calculateInSampleSize(选项,reqWidth,reqHeight);
options.inJustDe codeBounds = FALSE;
BM = BitmapFactory.de codeByteArray的(imageByteArray,0,imageByteArray.length,期权);
返回BM;
} 公众诠释calculateInSampleSize(BitmapFactory.Options选项,诠释reqWidth,诠释reqHeight){
//原始高度和图像宽度
最终诠释身高= options.outHeight;
最终诠释宽度= options.outWidth;
INT inSampleSize = 1; 如果(高度> reqHeight ||宽度GT; reqWidth){
如果(宽>高度){
inSampleSize = Math.round((浮点)高度/(浮点)reqHeight);
}其他{
inSampleSize = Math.round((浮点)宽/(浮点)reqWidth);
}
} Log.d(TAG,试样尺寸为:+ inSampleSize);
返回inSampleSize;
} 私人无效fetchNewImageUrls(){
新的AsyncTask<弦乐,太虚,布尔>(){ @覆盖
保护布尔doInBackground(字符串... PARAMS){
尝试{
StringBuilder的响应=新的StringBuilder(); 网址URL =新的URL(PARAMS [0]);
HttpURLConnection的连接=(HttpURLConnection类)url.openConnection();
connection.setRequestMethod(GET);
connection.connect();
在的BufferedReader =新的BufferedReader(新的InputStreamReader(connection.getInputStream()));
串inputLine;
而((inputLine = in.readLine())!= NULL)
response.append(inputLine);
附寄();
connection.disconnect(); 字符串RESP = response.toString();
Log.d(TAG的回应是:+响应); //解析响应
的JSONObject的JSONObject =新的JSONObject(RESP);
JSONObject的jsonObject1 = jsonObject.getJSONObject(RESPONSE_DATA_JSON_KEY);
JSONArray jsonArray = jsonObject1.getJSONArray(RESULTS_JSON_KEY); 对(INT I = 0; I&下; 4;我++){
JSONObject的dataObject时= jsonArray.getJSONObject(I)
mImageUrls.add(dataObject.getString(IMAGE_JSON_KEY));
}
mCurrentPage ++;
Log.d(TAG,图片链接数是:+ mImageUrls.size());
返回true;
}赶上(JSONException E){
e.printStackTrace();
}赶上(MalformedURLException的E){
e.printStackTrace();
}赶上(IOException异常五){
e.printStackTrace();
}
返回false;
} @覆盖
保护无效onPostExecute(布尔值){
super.onPostExecute(值); 如果(checkDiff()及&放大器;值){
Log.d(TAG,再次取的图像);
fetchNewImageUrls();
} 如果(!值){
Log.d(TAG,错误而得到响应);
}
mAdapter.notifyDataSetChanged();
}
} .execute(BASE_URL + mCurrentPage);
} 私人布尔checkDiff(){
INT的diff = mImageUrls.size() - mCurrentPage * 4;
Log.d(TAG,差别是:+差异);
返回DIFF< 8;
} 公共静态的byte [] convertToByteArray(输入的InputStream){
字节[]缓冲区=新的字节[8192];
INT读取动作;
ByteArrayOutputStream输出=新ByteArrayOutputStream();
尝试{
而((读取动作= input.read(缓冲液))!= - 1){
output.write(缓冲液,0,读取动作);
}
}赶上(IOException异常五){
e.printStackTrace();
}
返回output.toByteArray();
}
}
既然你不取消未完成的拿出来看下载这些可能与您的GUI干扰。
示例
- 列表视图一号线显示项目#1用了一个异步任务,下载图像一尚未完成
- 向下滚动,一号线现在是无形的;
- 列表视图line8变得可见回收项目#1的新任务异步下载图像的x
- 异步任务,下载图像一显示完错误的图像。 Line8显示图像A代替X
要解决这个问题,你必须取消挂起不必要的未完成的异步任务-S
公共静态类持有人{
ImageView的mRowImage;
串mImageUrl; // neccessary取消未完成的下载
BitmapWorkerTask mDownloader;
}静态类BitmapWorkerTask扩展的AsyncTask<持有人,太虚,位图> {
持有人mHolder;
保护位图doInBackground(持有人持有...){
mHolder =持有者[0];
...
}
保护无效onPostExecute(...){
mHolder.mDownloader = NULL;
如果(!isCancelled()){
this.mHolder.mRowImage.setImageBitmap(图片);
}
this.mHolder = NULL;
}
}公共类CustomListAdapter延伸BaseAdapter {
@覆盖
公共查看getView(INT位置,...){
...
如果(查看== NULL){
持有人= ...
...
}其他{
支架=(座)view.getTag();
}
...
//取消未完成的mDownloader
如果(holder.mDownloader!= NULL){
holder.mDownloader.cancel(假);
holder.mDownloader = NULL;
}
holder.mImageUrl = mImageUrls.get(位置);
holder.mDownloader =新BitmapWorkerTask()
holder.mDownloader.execute(保持器);
}
}
这里是适配器+支架+的AsyncTask的组合工作示例
[更新]
潜在的问题与该溶液中。
- 大多数现代的Android版本一次执行只有一个异步任务。如果您是通过网络获取图像,你不能在同一时间下载multible图像。见running-parallel-asynctask@stackoverflow了解详情。
- 可能有配置更改(如方向)promlems。见下面@ Selvin-的评论。我已经张贴了这个问题:what-happens-with-view-references-in-unfinished-asynctask-after-orientation-chan@stackoverflow\"要了解更多有关它。
I have used the async task to download the data and then showing those images in the list view I used the cache to store the images as they are repeating but not in an order. But the images gets jumbled up and sometimes they don't download. I tried searching this, but couldn't find that.
This was one of mine dream company question and i didn't clear because of this.Please help me around.
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final String BASE_URL = "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=android&start=";
private static final String IMAGE_JSON_KEY = "unescapedUrl";
private static final String RESULTS_JSON_KEY = "results";
private static final String RESPONSE_DATA_JSON_KEY = "responseData";
private int mCurrentPage;
private ListView mListView;
private Context mContext;
ArrayList<String> mImageUrls;
private LruCache<String, Bitmap> mCache;
private CustomListAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
// Initialize variables
mContext = this;
mCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
// The cache size will be measured in bytes rather than number of items.
return value.getByteCount();
}
};
mListView = (ListView) findViewById(R.id.list_view);
mAdapter = new CustomListAdapter();
mImageUrls = new ArrayList<>();
// If the urls are wrong then
if (mImageUrls.isEmpty() || checkDiff()) {
fetchNewImageUrls();
}
// Set the adapter to the list view
mListView.setAdapter(mAdapter);
}
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private String mUrl;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
protected Bitmap doInBackground(String... params) {
String imageUrl = params[0];
mUrl = imageUrl;
Bitmap bitmap = getBitmapFromMemCache(imageUrl);
if (bitmap == null) {
try {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
// Closing the stream after getting the sample size
InputStream inputStream = connection.getInputStream();
byte[] imageByteArray = convertToByteArray(inputStream);
bitmap = decodeSampledBitmap(imageByteArray, 200, 200);
inputStream.close();
if (bitmap != null) {
Log.d(TAG, "Image downloaded: " + imageUrl);
addBitmapToMemoryCache(imageUrl, bitmap);
} else {
Log.d(TAG, "Null Bitmap downloaded for: " + imageUrl);
}
connection.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
Log.d(TAG, "Already present in the Cache");
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = (ImageView) imageViewReference.get();
if (imageView != null && imageView.getTag().equals(mUrl)) {
imageView.setImageBitmap(bitmap);
}
}
}
}
public class CustomListAdapter extends BaseAdapter {
@Override
public int getCount() {
return mImageUrls.size();
}
@Override
public Object getItem(int position) {
return mImageUrls.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.d(TAG, "Get View is called for position: " + position);
View view = convertView;
Holder holder = null;
// Holder represents the elements of the view to use
// Here are initialized
if (view == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.row_item, parent, false);
holder = new Holder();
holder.mRowImage = (ImageView) view.findViewById(R.id.image_view);
holder.mRowText = (TextView) view.findViewById(R.id.row_text);
view.setTag(holder);
} else {
holder = (Holder) view.getTag();
}
// Set default image background
holder.mRowImage.setImageResource(R.drawable.ic_launcher);
// here do operations in holder variable example
holder.mRowText.setText("Image Number: " + position);
// Set the tag for the imageview
holder.mRowImage.setTag(mImageUrls.get(position));
new BitmapWorkerTask(holder.mRowImage).execute(mImageUrls.get(position));
return view;
}
}
public static class Holder {
TextView mRowText;
ImageView mRowImage;
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return (Bitmap) mCache.get(key);
}
public Bitmap decodeSampledBitmap(byte[] imageByteArray, int reqWidth, int reqHeight) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length, options);
return bm;
}
public 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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
Log.d(TAG, "Sample size is: " + inSampleSize);
return inSampleSize;
}
private void fetchNewImageUrls() {
new AsyncTask<String, Void, Boolean>() {
@Override
protected Boolean doInBackground(String... params) {
try {
StringBuilder response = new StringBuilder();
URL url = new URL(params[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
response.append(inputLine);
in.close();
connection.disconnect();
String resp = response.toString();
Log.d(TAG, "Response is: " + response);
// Parsing the response
JSONObject jsonObject = new JSONObject(resp);
JSONObject jsonObject1 = jsonObject.getJSONObject(RESPONSE_DATA_JSON_KEY);
JSONArray jsonArray = jsonObject1.getJSONArray(RESULTS_JSON_KEY);
for (int i = 0; i < 4; i++) {
JSONObject dataObject = jsonArray.getJSONObject(i);
mImageUrls.add(dataObject.getString(IMAGE_JSON_KEY));
}
mCurrentPage++;
Log.d(TAG, "Number of image urls are: " + mImageUrls.size());
return true;
} catch (JSONException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
protected void onPostExecute(Boolean value) {
super.onPostExecute(value);
if (checkDiff() && value) {
Log.d(TAG, "Again fetching the Images");
fetchNewImageUrls();
}
if (!value) {
Log.d(TAG, "Error while getting the response");
}
mAdapter.notifyDataSetChanged();
}
}.execute(BASE_URL + mCurrentPage);
}
private boolean checkDiff() {
int diff = mImageUrls.size() - mCurrentPage * 4;
Log.d(TAG, "Diff is: " + diff);
return diff < 8;
}
public static byte[] convertToByteArray(InputStream input) {
byte[] buffer = new byte[8192];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
return output.toByteArray();
}
}
Since you do not cancel the unfinished "out of view" downloads these may interfere with your gui.
Example
- listview line1 shows item#1 with has an async task to download image "a" not completed yet
- scroll down, line1 is now invisible;
- listview line8 becomes visible recycling item#1 new async task to download image "x"
- async task to download image "a" finishes displaying wrong image. Line8 shows image "a" instead of "x"
to solve this you have to cancel the pending unnecessary unfinished async task-s
public static class Holder {
ImageView mRowImage;
String mImageUrl;
// neccessary to cancel unfinished download
BitmapWorkerTask mDownloader;
}
static class BitmapWorkerTask extends AsyncTask<Holder, Void, Bitmap> {
Holder mHolder;
protected Bitmap doInBackground(Holder... holders) {
mHolder = holders[0];
...
}
protected void onPostExecute(...) {
mHolder.mDownloader = null;
if (!isCancelled()) {
this.mHolder.mRowImage.setImageBitmap(image);
}
this.mHolder = null;
}
}
public class CustomListAdapter extends BaseAdapter {
@Override
public View getView(int position, ...) {
...
if (view == null) {
holder = ...
...
} else {
holder = (Holder) view.getTag();
}
...
// cancel unfinished mDownloader
if (holder.mDownloader != null) {
holder.mDownloader.cancel(false);
holder.mDownloader = null;
}
holder.mImageUrl = mImageUrls.get(position);
holder.mDownloader = new BitmapWorkerTask()
holder.mDownloader.execute(holder);
}
}
Here is a working example for this combination of Adapter + Holder + AsyncTask
[Update]Potential problems with this solution.
- Most modern android versions execute only one async task at a time. If you are fetching the images via the web you cannot download multible images at the same time. See running-parallel-asynctask@stackoverflow for details.
- There may be promlems with configuration change(like orientation). See @Selvin-s comment below. I have posted this question "what-happens-with-view-references-in-unfinished-asynctask-after-orientation-chan@stackoverflow" to find out more about it.
这篇关于显示图像列表视图使用的AsyncTask下载图像后混乱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!