Spinner,gridview,异步显示

时间:2016-12-23 16:06:26

标签: android gridview android-asynctask spinner

背景

嗨,我对Android编程比较陌生。我还在学习。

我有一个包含两个表的数据库:Item和Type。 Item包含以下列:_id,code,type。 Type包含以下列:_id,name。

在我的活动中,我会显示各种类型的微调器以及项目的网格视图。微调器应该过滤结果并更新gridview。

gridview项目仅包含图像。列代码给出了图像文件的名称。 我有一个数据库助手DatabaseHelper,它以不同的方式打开,关闭和访问数据库。

在我的活动ItemList的开头,调用getContents(),getContents()调用数据库,并根据selectedType的值更新listOfIds和listOfCodes(初始化为0)。然后创建gridview。

对于gridview,我在显示图像和滚动(内存不足)时遇到了内存问题。所以我遵循了Android教程:https://developer.android.com/training/displaying-bitmaps/process-bitmap.html现在,每个项目都是异步显示的。它工作正常。

问题

当我在微调器中选择一个类型时,selectedType被更新,调用getContents()然后调用notifyDataSetChanged()。有时它工作正常,有时会崩溃。我认为当我选择一个类型时,尚未终止的旧线程正在更新时访问listOfIds和listOfCodes。

如何杀死所有thoses线程(在更新列表之前)并阻止gridview在更新期间调用getView? 我在考虑创建一个包含线程的列表,更新它,并在更新列表之前终止所有线程。但我无法找到阻止gridview适配器在更新期间创建视图的正确方法。

感谢您的帮助。

代码

以下是我的代码的一部分:

ItemList.java

public class ItemList extends Activity {

    private ImageAdapter mAdapter;
    private Bitmap mPlaceHolderBitmap;
    private DatabaseHelper myHelper;
    public static int column = 3;
    public static int MARGIN = 5; //margin in dp
    public static int width;
    public GridView gallery;
    public SpinnerAdapter spinnerAdapter;
    public Spinner mySpinner;
    public int defaultImageID;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.item_list);

        initialiseValues();
        createHelper();
        resetPositions();

        getContents();
        createLists();

        createSpinnerListener();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    public void createHelper() {
        myHelper = new DatabaseHelper(getApplicationContext());
        myHelper.getSpinnerIds();
    }

    public void initialiseValues(){
        myHelper.selectedType = 0;

        //determines the width of the displayed image
        Point size = new Point();
        Display display = getWindowManager().getDefaultDisplay();
        display.getSize(size);
        width = size.x - dpToPx(2*column*MARGIN);

        //determines the default image to display
        defaultImageID = ...; //here I get the id of the default image;
        mPlaceHolderBitmap = decodeSampledBitmapFromResource(getResources(), defaultImageID, null, null), width, width);
    }

    public void createList() {
        spinnerAdapter = new SpinnerAdapter(this, myHelper, myHelper.spinnerNames);
        spinnerAdapter.setDropDownViewResource(R.layout.spinner_item);
        mySpinner = (Spinner) findViewById(R.id.spinner);
        mySpinner.setAdapter(spinnerAdapter);

        gallery = (GridView) findViewById(R.id.gallery);
        mAdapter = new ImageAdapter(this);
        gallery.setAdapter(mAdapter);
    }

    public void getContents() {
        myHelper.getLists();
    }

    public void createSpinnerListener() {
        mySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

                myHelper.selectedType = myHelper.spinnerIds.get(position);
                getContents();
                mAdapter.notifyDataSetChanged();
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });

    }

    public int dpToPx(int dp) {
        DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
        return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
    }

    private class ImageAdapter extends BaseAdapter {
        private final Context mContext;

        public ImageAdapter(Context context) {
            super();
            mContext = context;
        }

        @Override
        public int getCount() {
            return myHelper.listOfCodes.size();
        }

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

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

        @Override
        public View getView(int position, View convertView, ViewGroup container) {
            View view;
            if (convertView == null) { // if it's not recycled, initialize some attributes
                LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.grid_item, null);
            }
            else {view = convertView;}

            int image_id = getApplicationContext().getResources().getIdentifier(".../" + myHelper.listOfCodes.get(position), null, null);
            if (image_id == 0) {image_id = R.drawable.item_unknown;}

            loadBitmap(image_id, imageView);

            return view;
        }
    }

    public void loadBitmap(int resId, ImageView imageView) {
        if (cancelPotentialWork(resId, imageView)) {
            final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
            final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
            imageView.setImageDrawable(asyncDrawable);
            task.execute(resId);
        }
    }

    public static boolean cancelPotentialWork(int data, ImageView imageView) {
        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

        if (bitmapWorkerTask != null) {
            final int bitmapData = bitmapWorkerTask.data;
            if (bitmapData != data) {
                bitmapWorkerTask.cancel(true);  // Cancel previous task
            }
            else {
                return false;   // The same work is already in progress
            }
        }
        return true;    // No task associated with the ImageView, or an existing task was cancelled
    }

    private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
        if (imageView != null) {
            final Drawable drawable = imageView.getDrawable();
            if (drawable instanceof AsyncDrawable) {
                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
                return asyncDrawable.getBitmapWorkerTask();
            }
        }
        return null;
    }

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    public static 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) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

    static class AsyncDrawable extends BitmapDrawable {
        private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;

        public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
            super(res, bitmap);
            bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
        }

        public BitmapWorkerTask getBitmapWorkerTask() {
            return bitmapWorkerTaskReference.get();
        }
    }

    class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

        private final WeakReference<ImageView> imageViewReference;

        private int data = 0;

        public BitmapWorkerTask(View view) {
            // Use a WeakReference to ensure the ImageView can be garbage collected
            imageViewReference = new WeakReference<ImageView>(imageView);
        }

        // Decode image in background.
        @Override
        protected Bitmap doInBackground(Integer... params) {
            data = params[0];
            return decodeSampledBitmapFromResource(getResources(), data, width, width);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (isCancelled()) {
                bitmap = null;
            }

            if (imageViewReference != null && bitmap != null) {
                final ImageView imageView = imageViewReference.get();

                final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
                if (this == bitmapWorkerTask && imageView != null) {
                    imageView.setImageBitmap(bitmap);
                }
            }
        }
    }
}

DatabaseHelper.java

public class DatabaseHelper extends SQLiteOpenHelper{

    ...
    public int currentID = 0;
    public int numberOfItems = 0;
    public List<Integer> listOfIds = new ArrayList<>();
    public List<String> listOfCodes = new ArrayList<>();
    public List<Integer> spinnerIds = new ArrayList<>();
    public List<String> spinnerNames = new ArrayList<>();
    public int selectedType = 0;

    private Context context;
    public SQLiteDatabase myDataBase;
    ...

    public DatabaseHelper(Context context) {
        super(context, DB_NAME, null, 1);
        this.context = context;
    }

    ...

    public void getSpinnerIds() {
        spinnerIds.clear();
        spinnerNames.clear();
        /*
        updates spinnerIds by accessing the db, first one is "All types"
        */
    }

    public void getLists() {
        listOfIds.clear();
        listOfCodes.clear();
        numberOfItems = 0;

        String where = " WHERE code <> '0'";
        if (selectedPosition != 0) {where += " AND Type = " + String.valueOf(selectedType);}

        openDataBase();
        try {
            Cursor myCursor = myDataBase.rawQuery("SELECT _id, code, type FROM Item" + where + " ORDER BY _id ASC", null);
            myCursor.moveToFirst();
            do {
                listOfIds.add(myCursor.getInt(0));
                listOfCodes.add(myCursor.getString(1));
            }
            while (myCursor.moveToNext());
            myCursor.close();
            numberOfItems = listOfIds.size();
        }
        catch (Exception CursorIndexOutOfBoundsException) {}
        myDataBase.close();
   }



    public String getName(int id) {
        String name;
        openDataBase();
        Cursor myCursor = myDataBase.rawQuery("SELECT name FROM Item WHERE _id = " + String.valueOf(id), null);
        myCursor.moveToFirst();
        name = myCursor.getString(0);
        myCursor.close();
        myDataBase.close();
        return name;
    }

    ...

}

SpinnerAdapter.java

public class SpinnerAdapter extends ArrayAdapter<String> {

    private Context context;
    private DatabaseHelper helper;

    public SpinnerAdapter(Context context, DatabaseHelper helper, List<String> list) {
        super(context,  R.layout.spinner_item_small, R.id.text, list);
        this.context = context;
        this.helper = helper;
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return getCustomView(position, convertView);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup prnt) {
        return getCustomView(position, convertView);
    }

    public View getCustomView(int position, View convertView) {
        View view;
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.spinner_item_small, null);
        }
        else {view = convertView;}

        TextView textView = (TextView) view.findViewById(R.id.text);
        textView.setText(helper.spinnerNames.get(position));

        return view;
    }
}

0 个答案:

没有答案