粗略搜了一下,网站较少android listview的错位解决方法,有些解决方法通过修改缓存来实现,比较复杂,而且看得不是很明白。参考了小米自带相册的实现,通过用默认纯色空白图片代替处理中的图片,经过几天的努力,终于研究出多线程解决android ListView图片错位的问题。

主要的解决思路如下:
1.图片信息通过ContentResolver获取,由于图片不符合规格,需要自己写一个decodeBitmap()方法进行压缩
2.每次调用Adapter中的getView()方法才检测该图片是否已经被压缩,如果没有压缩则开启压缩线程进行压缩,然后将图片保存到本地,并将压缩图片的信息保存到本地的Sqlite
3.如果调用getView方法时,图片已经压缩,则通过BitmapFactory.decodeFile(pathName)的方法调用本地压缩后的图片
4.图片错位问题,用默认的空白图片对view进行初始化

布局非常简单:MainActivity.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <GridView
        android:numColumns="3"
        android:id="@+id/gridView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</RelativeLayout>

item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/imgView"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:scaleType="centerCrop" />
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {
    public static final int DECODE_OK = 0x000011;
    private static final int defNum = 14800000;
    GridView gridView;
//    这个SparseArray是android的集合类型,本来想测试从内存中load图片会不会比本地快,但后来没测
    SparseArray<String> imgInfos;
    static MyAdapter adapter;
    DBHelper helper;
    SQLiteDatabase db;
    ContentResolver resolver;
    int count;
    String thumbDir;

    @Override
    protected void onStart() {
        super.onStart();
        helper = new DBHelper(this);
//        测试时,为了观察效果,每次打开程序都清空本地压缩图
        File delFile = new File(this.getFilesDir() + "/thumbnails");
        if (delFile.isDirectory()) {
            File[] files = delFile.listFiles();
            for (File file : files) {
                file.delete();
            }
        }
        initDate();
//        Context context = this.getApplicationContext();
//        Log.v("fileDir",""+context.getFilesDir());
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        gridView = (GridView) findViewById(R.id.gridView);
        adapter = new MyAdapter();
        gridView.setAdapter(adapter);
    }

    @Override
    protected void onStop() {
        super.onStop();
        db.close();
    }

//    初始化数据
    private void initDate() {
        thumbDir = this.getFilesDir() + "/" + "thumbnails" + "/";
        db = helper.getWritableDatabase();
        Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        imgInfos = new SparseArray<>();
        resolver = this.getContentResolver();
        String[] counts = new String[]{"count(*)"};
        Cursor cursor = resolver.query(uri, counts, null, null, null);
        if (cursor != null && cursor.moveToNext()) {
            count = cursor.getInt(0);
            cursor.close();
        }
        //        测试时,为了观察效果,每次打开程序都清空压缩图信息
        db.execSQL("DELETE FROM thumbnails");
        Log.v("count", "found " + count + " record");
    }

    private class MyAdapter extends BaseAdapter {
        ViewHolder holder;
        final Drawable defDrawable = MainActivity.this.getResources().getDrawable(R.drawable.default_drawable);
        Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        String[] queryColumns =queryColumns = new String[]{
                MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA,
                MediaStore.Images.Media.DATE_MODIFIED,
        };
        ContentResolver resolver = MainActivity.this.getContentResolver();
        Cursor cursor = resolver.query(uri,queryColumns,null,null,"date_modified DESC");

        @Override
        public int getCount() {
            return count;
        }

        @Override
        public Object getItem(int i) {
            return null;
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(final int i, View view, ViewGroup viewGroup) {
            final MyHandler handler;
            holder = new ViewHolder();
            if (view == null) {
                LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
                view = inflater.inflate(R.layout.item, viewGroup, false);
                holder.imageView = (ImageView) view.findViewById(R.id.imgView);
                holder.imageView.setImageDrawable(defDrawable);
                view.setTag(holder);

            } else {
//                holder.imageView = (ImageView) view.findViewById(R.id.imgView);
                holder = (ViewHolder) view.getTag();
                holder.imageView.setImageDrawable(defDrawable);

            }

            handler = new MyHandler(holder);

            if (cursor != null) {
                cursor.moveToPosition(i);
                String displayName = String.valueOf(defNum + cursor.getInt(0)) + ".jpg";
//                将cursor信息保存到ContentValues中去,方便下一步查询,不用每次都执行query方法
                final ContentValues values = new ContentValues();
                values.put("parent_id", cursor.getInt(0));
                values.put("parent_data", cursor.getString(1));
                values.put("_data",thumbDir+displayName);
                values.put("displayName", displayName);
                values.put("parent_date_modified", cursor.getInt(2));

//                Log.v("position", "position:" + i);
                Cursor tCursor = db.rawQuery("SELECT _data,parent_date_modified,parent_id FROM thumbnails " +
                        "WHERE parent_id = ?", new String[]{values.getAsString("parent_id")});
                if (!tCursor.moveToNext() || tCursor.getInt(1) != values.getAsInteger("parent_date_modified")) {
//                    Log.v("situation", "one");
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            zipAndStore(values,handler);
                        }
                    }).start();
                    tCursor.close();
                } else {
//                    Log.v("situation", "two");
                    Bitmap bitmap = BitmapFactory.decodeFile(tCursor.getString(0));
                    holder.imageView.setImageBitmap(bitmap);
//                    Message msg = Message.obtain();
//                    msg.what = DECODE_OK;
//                    msg.obj = bitmap;
//                    handler.sendMessage(msg);
                    tCursor.close();
                }
            } else {
                Log.v("cursor", "null");
            }
            return view;
        }
    }
//    储存本地图片的方法
    private void storeThumbnail(Bitmap bitmap, String filePath, String display_name) {
        File file = new File(filePath);
//        删除重名的本地文件
        if (!file.exists()) {
            if (file.mkdir()) {
                Log.v("dir_make", "dir maked");
            }
        }

        file = new File(filePath, display_name);
        if (file.exists()) {
            if (file.delete()) {
                Log.v("file_delete", "found same file " + display_name + " and deleted");
            }
        }
        try {
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//    压缩图片的方法,由于在小米note测试的时候遇到各种图片,所以算法多了一点
    private Bitmap decodeBitmap(String path) {
        Log.v("decode_path",path);
        Bitmap bitmap;
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);
        int realWidth = options.outWidth;
        int realHeight = options.outHeight;
        Log.v("width&height", options.outWidth + "|" + options.outHeight);
        int scale = (realWidth > realHeight ? realHeight : realWidth) / 100;
        if (scale <= 1) {
            scale = 1;
        }
        options.inSampleSize = scale;
        options.inJustDecodeBounds = false;
        options.outMimeType = "mime/jpeg";
        bitmap = BitmapFactory.decodeFile(path, options);
//        裁切出中间方形的bitmap
        int rectWidth;
        int rectHeight;
        int x;
        int y;
        if (options.outWidth < 100) {
            rectWidth = options.outWidth;
            x = 0;
        } else {
            rectWidth = 100;
            x = (options.outWidth - 100) / 2;
        }
        if (options.outHeight < 100) {
            rectHeight = options.outHeight;
            y = 0;
        } else {
            rectHeight = 100;
            y = (options.outHeight - 100) / 2;
        }
        bitmap = Bitmap.createBitmap(bitmap, x, y, rectWidth, rectHeight, null, false);
//        Log.v("decoding", path + " done");
        return bitmap;
    }

    private static class ViewHolder {
        ImageView imageView;
    }
//      这个类本来打算用来测试线程池,不用管
    public class MyDecodeTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... voids) {
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            Log.v("init_state", "init done");
        }
    }

    private static class MyHandler extends Handler {
        ViewHolder holder;

        public MyHandler(ViewHolder holder) {
            this.holder = holder;
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DECODE_OK:
                    holder.imageView.setImageBitmap((Bitmap) msg.obj);
                    break;
            }
        }
    }

//    压缩图片,保存到本地,将压缩图片信息保存到本地数据库
    public void zipAndStore(ContentValues values,Handler handler){
        Log.v("situation", "one");
        Bitmap bitmap = decodeBitmap(values.getAsString("parent_data"));
        Message msg = Message.obtain();
        msg.what = DECODE_OK;
        msg.obj = bitmap;
        handler.sendMessage(msg);
        storeThumbnail(bitmap, thumbDir, values.getAsString("displayName"));
        values.put("width", bitmap.getWidth());
        values.put("height", bitmap.getHeight());
        values.remove("parent_data");
//        更新本地数据库记录
        synchronized(this){
            db.delete("thumbnails", "parent_id=?", new String[]{values.getAsString("parent_id")});
            db.insert("thumbnails", null, values);
        }
    }
}

由于篇幅太大,就不把数据库类和model类都放上来,那些都比较简单而且不用管。小弟菜鸟,如果有更好的解决方法,希望大神们指点一下!