0

Я делаю ListView с возможностью добавлять изображения с камеры или галереи. Все работает нормально, но прокрутка работает не так гладко.Android 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); 
    } 

Когда элемент ListView больше размера экрана, прокрутка не работает гладко. Или, возможно, сделать более сильный компресс для изображений? Как будет лучше. И возможно ли реализовать «Возьмите фото с камеры» без разрешения в манифест для хранения?

Thx заранее!

/МЕНЯЕТ/

Я использую эту функцию тоже, за исключением изменений в 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)); 
    } 

ответ

0

На мой взгляд, главная проблема заключается в том, что метод decodeFile(String filePath) занимает много времени. Во время прокрутки система ждет его, а прокрутка не является гладкой.

Попробуйте запустить decodeFile(String filePath) в новой теме (вы можете использовать AsyncTask).

EDIT: Метод getView вызывается каждый раз, когда вы прокручиваете, добавляете элементы или обновляете listView. Элемент отображается после завершения getView. Длительные операции (более 100 мс) могут привести к негладкой прокрутке.

Эта длительная работа (например, декодирование растрового изображения) должна запускаться в новом потоке (AsyncTask). Но из-за recycling views в списке адаптеровViewView может показывать старые изображения перед концами потоков. Поэтому полезно показать некоторое изображение-заполнитель (например, ProgressBar) в getView перед началом нового потока.

Подробнее об этом: http://developer.android.com/training/improving-layouts/smooth-scrolling.html

+0

Thx, я буду стараться, а затем записать обратно – kbu

+0

я прочитал ваш код, но я не могу видеть код вашего адаптера и метода GetView. В моем случае проблема была там, и мне пришлось использовать новый поток для загрузки изображений в этот метод. – vzoha

+0

Я добавил изменения выше. – kbu