【问题标题】:Android ListView with custom images from Camera or Gallery带有来自相机或图库的自定义图像的 Android ListView
【发布时间】:2014-10-09 12:02:23
【问题描述】:

我制作 ListView 可以从相机或图库中添加图像。一切正常,但滚动不太顺畅。

这是我的代码:

public boolean onMenuItemClick(MenuItem item) {

        switch (item.getItemId()) {

            case R.id.context_rename:
                 renameDialog(selectedItem);
                 return true;

            case R.id.context_set_foto:
                 selectImage();
                 return true;

            default:
                 return false;
        }
}

 private void selectImage() {

        final CharSequence[] options = { getString(R.string.takeAFoto), getString(R.string.chooseFromGallery),getString(R.string.dialogUserCancel) };

        AlertDialog.Builder builder = new AlertDialog.Builder(List.this);

        builder.setTitle(getString(R.string.addFoto));

        builder.setItems(options, new DialogInterface.OnClickListener() {

            @Override

            public void onClick(DialogInterface dialog, int item) {

                if (options[item].equals(getString(R.string.takeAFoto))) {


                    //define the file-name to save photo taken by Camera activity
                    String fileName = "new-photo-name.jpg";
                    //create parameters for Intent with filename
                    ContentValues values = new ContentValues();
                    values.put(MediaStore.Images.Media.TITLE, fileName);
                    values.put(MediaStore.Images.Media.DESCRIPTION,"Image captured by camera");
                    //imageUri is the current activity attribute, define and save it for later usage (also in onSaveInstanceState)
                    imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                    //create new Intent
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
                    startActivityForResult(intent, 1);

                }

                else if (options[item].equals(getString(R.string.chooseFromGallery))) {

                    try {
                        Intent gintent = new Intent();
                        gintent.setType("image/*");
                        gintent.setAction(Intent.ACTION_GET_CONTENT);
                        startActivityForResult(
                                Intent.createChooser(gintent, "Select Picture"),
                                2);
                    } catch (Exception e) {
                        Toast.makeText(getApplicationContext(),
                                e.getMessage(),
                                Toast.LENGTH_LONG).show();
                        Log.e(e.getClass().getName(), e.getMessage(), e);
                    }

                }

                else if (options[item].equals(getString(R.string.dialogUserCancel))) {

                    dialog.dismiss();

                }

            }

        });

        builder.show();

    }

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        super.onActivityResult(requestCode, resultCode, data);

        Uri selectedImageUri = null;
        String filePath = null;

        if (resultCode == RESULT_OK) {

            if (requestCode == 1) {

                if (resultCode == RESULT_OK) {
                    //use imageUri here to access the image
                    selectedImageUri = imageUri;

                } else if (resultCode == RESULT_CANCELED) {
                    Toast.makeText(this, "Picture was not taken", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(this, "Picture was not taken", Toast.LENGTH_SHORT).show();
                }

            } else if (requestCode == 2) {

                selectedImageUri = data.getData();

            }

            if(selectedImageUri != null){
                try {
                    // OI FILE Manager
                    String filemanagerstring = selectedImageUri.getPath();

                    // MEDIA GALLERY
                    String selectedImagePath = getPath(selectedImageUri);

                    if (selectedImagePath != null) {
                        filePath = selectedImagePath;
                    } else if (filemanagerstring != null) {
                        filePath = filemanagerstring;
                    } else {
                        Toast.makeText(getApplicationContext(), "Unknown path",
                                Toast.LENGTH_LONG).show();
                        Log.e("Bitmap", "Unknown path");
                    }

                    if (filePath != null) {
                        decodeFile(filePath);
                    } else {
                        bitmap = null;
                    }
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "Internal error",
                            Toast.LENGTH_LONG).show();
                    Log.e(e.getClass().getName(), e.getMessage(), e);
                }
            }

        }

    }

    public String getPath(Uri uri) {
        String res = null;
        String[] proj = { MediaStore.Images.Media.DATA };
        Cursor cursor = getContentResolver().query(uri, proj, null, null, null);
        if(cursor.moveToFirst()){;
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            res = cursor.getString(column_index);
        }
        cursor.close();
        return res;
    }

    public void decodeFile(String filePath) {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, o);
        // The new size we want to scale to
        final int REQUIRED_SIZE = 1024;
        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
                break;
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }
        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        bitmap = BitmapFactory.decodeFile(filePath, o2);
        prod_image.setImageBitmap(bitmap);
        replaceBitmapInArray(bitmap);
    }

当列表视图项超过显示大小时,滚动不流畅。或者也许对图像进行更强大的压缩?怎么会好。 是否可以在没有权限的情况下实现“从相机拍摄照片”?

提前谢谢!

/变化/

我也在使用这个函数,用于对象 Arraylist 的变化

private void replaceBitmapInArray(Bitmap bitmap){

        Product p = productsArray.get(selectedPosition);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
        byte[] bArray = bos.toByteArray();

        p.setProdImage(bArray);

        productsArray.set(selectedPosition,p);

        animAdapter.notifyDataSetChanged();

    }

和适配器的代码:

public class MyListAdapter extends ArrayAdapter<Product> implements UndoAdapter {

    private final Context mContext;
    HashMap<Product, Integer> mIdMap = new HashMap<Product, Integer>();
    ArrayList<Product> products = new ArrayList<Product>();
    final int INVALID_ID = -1;
    LayoutInflater lInflater;

    public MyListAdapter(Context context, int textViewResourceId, List<Product> prod) {
        //super(context, textViewResourceId, prod);
        super(prod);
        lInflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mContext = context;
        for (int i = 0; i < prod.size(); i++) {
            //add(prod.get(i));
            mIdMap.put(prod.get(i),i);
        }
    }

    @Override
    public long getItemId(final int position) {
        //return getItem(position).hashCode();
        Product item = (Product) getItem(position);
        return mIdMap.get(item);
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public View getView(final int position, View convertView, final ViewGroup parent) {
        //TextView view = (TextView) convertView;
        /*View view = convertView;
        if (view == null) {
            //view = (TextView) LayoutInflater.from(mContext).inflate(R.layout.list_row, parent, false);
            view = lInflater.inflate(R.layout.item, parent, false);
            view.setBackgroundResource(R.drawable.rounded_corners);

            Product p = getItem(position);

            //view.setText(getItem(position).getProductName());
            ((TextView) view.findViewById(R.id.tvDescr)).setText(p.getProductName());
            ((ImageView) view.findViewById(R.id.ivImage)).setImageResource(p.getProductImage());

            if(p.getProductImageBitmap() != null) {

                if (p.getProductImageBitmap().length > 0) {
                    Bitmap bmp = BitmapFactory.decodeByteArray(p.getProductImageBitmap(), 0, p.getProductImageBitmap().length);
                    ImageView image = (ImageView) view.findViewById(R.id.list_image);
                    image.setImageBitmap(bmp);
                }

            }


            ImageView iv = (ImageView)view.findViewById(R.id.ivImage);
            iv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    MyListAdapter.this.remove(getItem(position));
                    Product p = getItem(position);
                    Toast.makeText(mContext, p.getProductName() + " " + mContext.getString(R.string.deleted_item), Toast.LENGTH_SHORT).show();
                    MyListAdapter.this.notifyDataSetChanged();
                }
            });

        }

        return view;*/

        ViewHolder holder = null;;
        Product p = getItem(position);

        if (convertView == null) {

            convertView = lInflater.inflate(R.layout.item, null);
            convertView.setBackgroundResource(R.drawable.rounded_corners);
            holder = new ViewHolder();

            holder.tvDescr = (TextView) convertView.findViewById(R.id.tvDescr);
            holder.list_image = (ImageView) convertView.findViewById(R.id.list_image);
            holder.products_amount = (TextView) convertView.findViewById(R.id.products_amount);
            holder.products_price = (TextView) convertView.findViewById(R.id.products_price);
            holder.ivImage = (ImageView) convertView.findViewById(R.id.ivImage);

            convertView.setTag(holder);

        } else {

            holder = (ViewHolder) convertView.getTag();

        }

        if (p.getProductImageBitmap() != null && p.getProductImageBitmap().length > 0) {
            Bitmap bmp = BitmapFactory.decodeByteArray(p.getProductImageBitmap(), 0, p.getProductImageBitmap().length);
            holder.list_image.setImageBitmap(bmp);
        } else {
            holder.list_image.setImageResource(R.drawable.ic_launcher);
        }

        holder.tvDescr.setText(p.getProductName());

        holder.ivImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                String deletedItem = getItem(position).getProductName();
                MyListAdapter.this.remove(getItem(position));

                if (MyListAdapter.this.getCount() > 0) {

                    Toast.makeText(mContext, deletedItem + " " + mContext.getString(R.string.deleted_item), Toast.LENGTH_SHORT).show();
                    MyListAdapter.this.notifyDataSetChanged();

                } else {

                    Toast.makeText(mContext,mContext.getString(R.string.sklerolist_empty), Toast.LENGTH_SHORT).show();

                }

            }
        });

        return convertView;
    }

    static class ViewHolder {
        ImageView list_image;
        TextView tvDescr;
        TextView products_amount;
        TextView products_price;
        ImageView ivImage;
    }

    @NonNull
    @Override
    public View getUndoView(final int position, final View convertView, @NonNull final ViewGroup parent) {
        View view = convertView;
        if (view == null) {
            //view = LayoutInflater.from(mContext).inflate(R.layout.undo_row, parent, false);
            view = lInflater.inflate(R.layout.undo_row, parent, false);
        }
        return view;
    }

    @NonNull
    @Override
    public View getUndoClickView(@NonNull final View view) {
        return view.findViewById(R.id.undo_row_undobutton);
    }

和函数SetAdapter:

private void setAdapter(){
        final com.nhaarman.listviewanimations.ArrayAdapter<Product> adapter = new MyListAdapter(this,R.layout.text_view,productsArray);
        SimpleSwipeUndoAdapter simpleSwipeUndoAdapter = new SimpleSwipeUndoAdapter(adapter, this, new MyOnDismissCallback(adapter));
        animAdapter = new AlphaInAnimationAdapter(simpleSwipeUndoAdapter);
        animAdapter.setAbsListView(listView);
        assert animAdapter.getViewAnimator() != null;
        animAdapter.getViewAnimator().setInitialDelayMillis(INITIAL_DELAY_MILLIS);
        listView.setAdapter(animAdapter);
        /* Enable drag and drop functionality */
        listView.enableDragAndDrop();
        listView.setDraggableManager(new TouchViewDraggableManager(R.id.list_row_draganddrop_touchview));
        listView.setOnItemMovedListener(new MyOnItemMovedListener(adapter));
        listView.setOnItemLongClickListener(new MyOnItemLongClickListener(listView));
        /* Enable swipe to dismiss */
        listView.enableSimpleSwipeUndo();
        /* Add new items on item click */
        //listView.setOnItemClickListener(new MyOnItemClickListener(listView));
    }

【问题讨论】:

    标签: android listview android-camera scrollview android-gallery


    【解决方案1】:

    在我看来,主要问题是方法decodeFile(String filePath) 需要很长时间。滚动时系统等待,滚动不流畅。

    尝试在新线程中运行decodeFile(String filePath)(可以使用AsyncTask)。

    编辑: 每次滚动、添加项目或刷新 listView 时都会调用方法 getView。项目在getView 结束后显示。所以长时间运行的操作(超过 100 毫秒)会导致滚动不流畅。

    这个长时间运行的操作(例如:解码位图图像)应该在新线程(AsyncTask)中运行。但是由于适配器 listView 中的recycling views 可以在线程结束之前显示旧图像。因此,在新线程开始之前,最好在 getView 中显示一些占位符图像(例如 ProgressBar)。

    更多信息:http://developer.android.com/training/improving-layouts/smooth-scrolling.html

    【讨论】:

    • 谢谢,我会尝试然后回信
    • 我阅读了您的代码,但看不到您的适配器和方法 getView 的代码。就我而言,问题就在那里,我不得不使用新线程在此方法中加载图像。
    • 我在上面添加了更改。
    • 您可以尝试记录前后时间戳:Bitmap bmp = BitmapFactory.decodeByteArray(p.getProductImageBitmap(), 0, p.getProductImageBitmap().length); holder.list_image.setImageBitmap(bmp);。如果花费的时间太长(超过 100 毫秒),此代码的新线程可能会有所帮助。
    • 会提前尝试。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多