我正在使用listview和checkbox,imageview和2个文本框。 列出使用araayadapter生成的,但我正在轻轻地滚动列表视图,但是当我以某种速度滚动列表视图时它会崩溃。 以下是我的代码。
import java.io.File; import java.util.ArrayList; import java.util.List;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
@SuppressLint("SdCardPath")
public class AddOptionItemAdapter extends ArrayAdapter<String>
{
String MenuId="";
Context context;
String tag;
String tag1;
String ogFilePath="";
String imgpath="";
private List<NameBean> list;
ArrayList< String>priceList=new ArrayList<String>();
ArrayList< String>imagepathList=new ArrayList<String>();
public AddOptionItemAdapter(Context context, List<NameBean> list,ArrayList<String> priceList,ArrayList<String> imagePathList) {
super(context, R.layout.lvoptncat,priceList);
this.list=list;
this.priceList=priceList;
this.imagepathList=imagePathList;
this.context=context;
}
@TargetApi(16)
public View getView (int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
if (convertView == null)
{
holder = new ViewHolder();
convertView = LayoutInflater.from(getContext()).inflate(R.layout.lvoptncat, null);
holder.tvOptnCatName=(com.example.hotelmenu.CustomTextView)convertView.findViewById(R.id.tvSubMenu);
holder.tvPrice=(com.example.hotelmenu.CustomTextView)convertView.findViewById(R.id.tvPrice);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.checkBox1);
holder.imgPath = (ImageView) convertView.findViewById(R.id.imgMenu);
holder.checkbox
.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton view,
boolean isChecked) {
int getPosition = (Integer) view.getTag();
addOptionActivity.optnCatNameList.get(getPosition).setSelected(view.isChecked());
}
});
}
else
holder = (ViewHolder) convertView.getTag();
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath,"HotelMenuImages");
if(!file.exists())
{
file.mkdirs();
}
ogFilePath=file.getAbsolutePath();
//String str=getItem(position);
//String []OptnCatDetails=str.split(",");
//DataSource datasource=new DataSource(context);
try
{
//Log.d("ImagePath111",MenuDetails[3].trim());
//String photo2 =OptnCatDetails[2];
//Log.d("ImagePath1222",photo2);
String photo2=imagepathList.get(position);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inSampleSize = 4;
Bitmap myBitmap = BitmapFactory.decodeFile(ogFilePath+"/"+photo2, options);
holder.imgPath.setImageBitmap(myBitmap);
}
catch(OutOfMemoryError e)
{
Log.d("ImageError",""+e);
}
holder.tvOptnCatName.setText(list.get(position).getName());
holder.tvPrice.setText(priceList.get(position));
holder.checkbox.setTag(position);
holder.checkbox.setChecked(addOptionActivity.optnCatNameList.get(position).isSelected());
return convertView;
}
class ViewHolder {
protected com.example.hotelmenu.CustomTextView tvOptnCatName,tvPrice;
protected CheckBox checkbox;
protected ImageView imgPath;
}
}
以下是我的logcat
07-19 10:56:13.549: E/InputEventReceiver(11356): Exception dispatching input event.
07-19 10:56:13.549: D/AndroidRuntime(11356): Shutting down VM
07-19 10:56:13.549: W/dalvikvm(11356): threadid=1: thread exiting with uncaught exception (group=0x4169a2a0)
07-19 10:56:13.565: E/AndroidRuntime(11356): FATAL EXCEPTION: main
07-19 10:56:13.565: E/AndroidRuntime(11356): java.lang.NullPointerException
07-19 10:56:13.565: E/AndroidRuntime(11356): at com.example.hotelmenu.AddOptionItemAdapter.getView(AddOptionItemAdapter.java:95)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.widget.AbsListView.obtainView(AbsListView.java:2449)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.widget.ListView.makeAndAddView(ListView.java:1769)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.widget.ListView.fillUp(ListView.java:706)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.widget.ListView.correctTooHigh(ListView.java:1395)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.widget.ListView.fillGap(ListView.java:637)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5534)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3417)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.widget.AbsListView.onTouchEvent(AbsListView.java:3910)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.View.dispatchTouchEvent(View.java:7340)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2181)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1914)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2113)
07-19 10:56:13.565: E/AndroidRuntime(11356): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1466)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.app.Activity.dispatchTouchEvent(Activity.java:2468)
07-19 10:56:13.565: E/AndroidRuntime(11356): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2061)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.View.dispatchPointerEvent(View.java:7525)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3370)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3302)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4394)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4372)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4476)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4444)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4495)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.Choreographer.doCallbacks(Choreographer.java:555)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.Choreographer.doFrame(Choreographer.java:523)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.os.Handler.handleCallback(Handler.java:615)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.os.Handler.dispatchMessage(Handler.java:92)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.os.Looper.loop(Looper.java:137)
07-19 10:56:13.565: E/AndroidRuntime(11356): at android.app.ActivityThread.main(ActivityThread.java:4895)
07-19 10:56:13.565: E/AndroidRuntime(11356): at java.lang.reflect.Method.invokeNative(Native Method)
07-19 10:56:13.565: E/AndroidRuntime(11356): at java.lang.reflect.Method.invoke(Method.java:511)
07-19 10:56:13.565: E/AndroidRuntime(11356): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
07-19 10:56:13.565: E/AndroidRuntime(11356): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
07-19 10:56:13.565: E/AndroidRuntime(11356): at dalvik.system.NativeStart.main(Native Method)
答案 0 :(得分:0)
请从getView()中删除文件操作和繁重的位图操作。
不使用此类,而是使用以下类来处理列表视图中的图像。
public class ImageStorage {
private String mBaseDir;
private static final String TAG = "Image Storage";
private static boolean DEBUG = false;
public static final int DEFAULT_CACHE_SIZE = 64;
private BasicBitmapCache mCache;
private Handler mHandler = new Handler();
private ExecutorService mExecutor = Executors.newCachedThreadPool();
private Set<LoadRequest> mActiveRequests = new HashSet<LoadRequest>();
public static class LoadRequest {
public LoadRequest(String key, ImageView v) {
if (key == null)
throw new NullPointerException("key must not be null");
mKey = key;
mImageView = v;
}
public ImageView getImageView() {
return mImageView;
}
public String getKey() {
return mKey;
}
@Override
public boolean equals(Object b) {
if (b instanceof LoadRequest)
return mKey.equals(((LoadRequest) b).getKey());
return false;
}
private String mKey;
private ImageView mImageView;
}
public ImageStorage(String baseDir) {
this.mBaseDir = baseDir;
this.mCache = new BasicBitmapCache(DEFAULT_CACHE_SIZE);
}
public boolean exists(String key) {
File file = new File(new File(mBaseDir), key);
return file.exists();
}
public Bitmap loadData(String key) {
if (!exists(key)) {
return null;
}
// load the bitmap as-is (no scaling, no crop)
Bitmap bitmap = null;
File file = new File(new File(mBaseDir), key);
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
bitmap = BitmapFactory.decodeStream(fis);
if (bitmap == null) {
// something wrong with the persistent data, can't be decoded to
// bitmap.
// removeDir(file); // Let's remove this file will gets
// downloaded again from server
throw new RuntimeException(
"data from db can't be decoded to bitmap");
}
return bitmap;
} catch (IOException e) {
if (DEBUG)
Log.e(TAG, "error loading bitmap", e);
return null;
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
}
}
}
}
public void storeData(String key, Bitmap data) {
if (data == null || data.isRecycled())
return;
//Scaling image before storing
data = scaleBitmap(data);
OutputStream outputStream = null;
try {
File file = new File(new File(mBaseDir), key);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
outputStream = new FileOutputStream(file);
if (!data.compress(Bitmap.CompressFormat.PNG, 100, outputStream)) {
throw new RuntimeException("failed to compress bitmap");
}
} catch (IOException e) {
if (DEBUG)
Log.e(TAG, "error storing bitmap", e);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
}
}
}
}
public void clear() {
try {
this.removeDir(new File(mBaseDir));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public int deleteFile(String key) {
if (!exists(key)) {
return -1;
}
File file = new File(new File(mBaseDir), key);
boolean deleted = file.delete();
if (!deleted)
return 0;
return 1;
}
/**
* Delete a directory
*
* @param d
* the directory to delete
*
*/
private void removeDir(File d) throws IOException {
// to see if this directory is actually a symbolic link to a directory,
// we want to get its canonical path - that is, we follow the link to
// the file it's actually linked to
File candir = d.getCanonicalFile();
// a symbolic link has a different canonical path than its actual path,
// unless it's a link to itself
if (!candir.equals(d.getAbsoluteFile())) {
// this file is a symbolic link, and there's no reason for us to
// follow it, because then we might be deleting something outside of
// the directory we were told to delete
return;
}
// now we go through all of the files and subdirectories in the
// directory and delete them one by one
File[] files = candir.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
File file = files[i];
// in case this directory is actually a symbolic link, or it's
// empty, we want to try to delete the link before we try
// anything
boolean deleted = file.delete();
if (!deleted) {
// deleting the file failed, so maybe it's a non-empty
// directory
if (file.isDirectory())
removeDir(file);
// otherwise, there's nothing else we can do
}
}
}
// now that we tried to clear the directory out, we can try to delete it
// again
d.delete();
}
public Bitmap loadImage(LoadRequest r) {
if (r == null || r.getKey() == null) {
// throw new IllegalArgumentException( "null or empty request");
return null;
}
ImageView v = r.getImageView();
if (v != null) {
synchronized (v) {
v.setTag(r.getKey()); // bind URI to the ImageView, to prevent
// image write-back of earlier requests.
}
}
mExecutor.submit(newRequestCall(r));
return null;
}
private Bitmap scaleBitmap(Bitmap image) {
int width = image.getWidth();
int height = image.getHeight();
float scale = (float)480/(float)width;
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(image,
(int) (width * scale), (int) (height * scale), true);
// Bitmap scaledBitmap = Bitmap.createBitmap(images.get(i), 0, 0, width,
// height, matrix, true);
return scaledBitmap;
}
private Callable<LoadRequest> newRequestCall(final LoadRequest request) {
return new Callable<LoadRequest>() {
public LoadRequest call() {
synchronized (mActiveRequests) {
while (mActiveRequests.contains(request)) {
try {
mActiveRequests.wait();
} catch (InterruptedException e) {
}
}
mActiveRequests.add(request);
}
Bitmap data = null;
try {
String key = request.getKey();
data = mCache.loadData(key);
if (data == null) {
if (DEBUG)
Log.d(TAG, "cache missing " + request.getKey());
// then check the persistent storage
data = loadData(key);
if (data != null) {
if (DEBUG)
Log.d(TAG,
"found in persistent: "
+ request.getKey());
mCache.storeData(key, data);
}
}
if (data != null && !data.isRecycled()
&& request.getImageView() != null) {
final Bitmap theData = data;
final ImageView iv = request.getImageView();
synchronized (iv) {
if (iv != null && iv.getTag() == request.getKey()) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (iv.getTag() == request.getKey()
&& !theData.isRecycled()) {
iv.setAnimation(null);
iv.setImageBitmap(theData);
}
}
});
}
}
}
} catch (Throwable e) {
if (DEBUG)
Log.e(TAG,
"error handling request " + request.getKey(), e);
} finally {
synchronized (mActiveRequests) {
mActiveRequests.remove(request);
mActiveRequests.notifyAll(); // wake up pending requests
// who's querying the
// same URL.
}
if (DEBUG)
Log.d(TAG, "finished request for: " + request.getKey());
}
return request;
}
};
}
}
并在您的适配器中使用
获取图像getImageStorage().loadImage(
new LoadRequest(//name of image,
//your image view));
和基本位图缓存在这里......
/**
* Basic implementation of BitmapCache
*
* @author Chirag Jain
*/
public class BasicBitmapCache {
private static class CacheEntry {
public Bitmap data;
public int nUsed;
public long timestamp;
}
private static final String TAG = "BasicBitmapCache";
private static final boolean DEBUG = false;
private int mMaxSize;
private HashMap<String, CacheEntry> mMap = new HashMap<String, CacheEntry>();
/**
* max number of resource this cache contains
*
* @param size
*/
public BasicBitmapCache(int size) {
this.mMaxSize = size;
}
public synchronized boolean exists(String key) {
return mMap.get(key) != null;
}
public synchronized void invalidate(String key) {
CacheEntry e = mMap.get(key);
Bitmap data = e.data;
data.recycle();
mMap.remove(key);
if (DEBUG)
Log.d(TAG, key + " is invalidated from the cache");
}
public synchronized void clear() {
for (String key : mMap.keySet()) {
invalidate(key);
}
}
/**
* If the cache storage is full, return an item to be removed.
*
* Default strategy: the least and oldest out: O(n)
*
* @return item key
*/
protected synchronized String findItemToInvalidate() {
Map.Entry<String, CacheEntry> out = null;
for (Map.Entry<String, CacheEntry> e : mMap.entrySet()) {
if (out == null || e.getValue().nUsed < out.getValue().nUsed
|| e.getValue().nUsed == out.getValue().nUsed
&& e.getValue().timestamp < out.getValue().timestamp) {
out = e;
}
}
return out.getKey();
}
public synchronized Bitmap loadData(String key) {
if (!exists(key)) {
return null;
}
CacheEntry res = mMap.get(key);
res.nUsed++;
res.timestamp = System.currentTimeMillis();
return res.data;
}
public synchronized void storeData(String key, Bitmap data) {
if (this.exists(key) || data == null || data.isRecycled()) {
return;
}
CacheEntry res = new CacheEntry();
res.nUsed = 1;
res.timestamp = System.currentTimeMillis();
res.data = data;
// if the number exceeds, move an item out
// to prevent the storage from increasing indefinitely.
if (mMap.size() >= mMaxSize) {
String outkey = this.findItemToInvalidate();
this.invalidate(outkey);
}
mMap.put(key, res);
}
}