Android 实现上传本地图片并实现压缩(避免OOM),支持长按删除

2018,新年快乐,作为开年的第一篇博客,今天来一篇Android上传图片的功能,毕竟这个是大部分的app都有的功能 。今天正好有空,就来记录一下,方便以后再次使用…


GIF原图如下:

个人觉得,如果博客没有效果图来说事,说什么都是白说。。。

  • OK,这个就是最终的实现效果了,接下来就看看具体的实现思路:

  • 首先,想要实现这个功能,需要使用到网格加载控件GridView来加载选择的图片,并且还需要通过adapter来填充GridView,并且使用图片加载库来进行图片的选择。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
注:先注明获取权限;

控件布局:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="activity.cc.com.demo009.MessageEditActivity"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/blue">

        <TextView
            android:id="@+id/textView10"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textSize="18dp"
            android:textColor="@color/black"
            android:text="Edit Text"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true" />

        <TextView
            android:id="@+id/txt_edit_message_canal"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="15dp"
            android:layout_marginStart="15dp"
            android:gravity="center"
            android:textSize="14dp"
            android:textColor="@color/black"
            android:text="canal" />

        <TextView
            android:id="@+id/txt_edit_message_submit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginEnd="15dp"
            android:layout_marginRight="15dp"
            android:gravity="center"
            android:textSize="14dp"
            android:textColor="@color/black"
            android:text="submit" />
    RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:weightSum="1">

        <EditText
            android:id="@+id/txt_edit_message_content"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:layout_marginTop="5dp"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:autoText="true"
            android:background="@null"
            android:capitalize="words"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:freezesText="true"
            android:gravity="top"
            android:hint=""
            android:imeOptions="actionNext"
            android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
            android:isScrollContainer="false"
            android:maxLength="200"
            android:minHeight="24dip"
            android:minLines="5"
            android:textSize="14dp" />

        

    LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:background="@color/gray"/>

    <GridView
        android:id="@+id/gv_edit_message"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:verticalSpacing="10dp"
        android:horizontalSpacing="10dp"
        android:numColumns="3"
        android:columnWidth="60dp"
        android:layout_marginTop="5dp"
        android:stretchMode="columnWidth"
        android:gravity="center"/>

    <TextView
        android:id="@+id/textView11"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="15dp"
        android:text="注:最多只能选择9张照片。" />

LinearLayout>
注:可以根据自己项目需求来设计布局。

Avtivity代码:

初始化图片加载库,并获取GridView并创建适配器填充添加照片(加号)
//获取GridView控件
gv_edit_message = (GridView) findViewById(R.id.gv_edit_message);
//GridView实现单击和长按事件(单击事件用于添加图片,长按事件用于删除图片)
gv_edit_message.setOnItemClickListener(this);
gv_edit_message.setOnItemLongClickListener(this);

//初始化图片加载库
imagePicker = ImagePicker.getInstance();
imagePicker.clear();
//实现图片点击监听事件
imagePicker.addOnImageSelectedListener(this);

//创建数据源并填充adapter适配器加载GridView
editMessageAdapter = new EditMessageAdapter(this, datas, gv_edit_message);
gv_edit_message.setAdapter(editMessageAdapter);
editMessageAdapter.notifyDataSetChanged();

GridView单击事件:

public void onItemClick(AdapterView parent, View view, int position, long id){
    if(position == 0){
        if(datas.get(position).url.equals("default")){
            Log.i(PublicUtils.AppName, "Default添加按钮");
            Intent intent = new Intent(this, ImageGridActivity.class);
            startActivityForResult(intent, IMAGE_PICKER);
        }
    }
}
注:这里之所以判断position,是因为默认当position为0的时候去添加图片。

GridView长按事件:

@Override
    public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
        Log.i(PublicUtils.AppName, "触发长按事件");
        if(position == 0){
            if(datas.get(position).url.equals("default")){
                Log.i(PublicUtils.AppName, "触发长按添加按钮事件");
            }else{
                editMessageAdapter.setImageClose(null, true);
                editMessageAdapter.setDeleteImage(new EditMessageAdapter.DeleteImage() {
                    @Override
                    public void deleteSucc(View view, int position) {
                        Log.i(PublicUtils.AppName, "delete succ");
                        editMessageAdapter.notifyDataSetChanged();
                    }
                });
            }
        }else{
            editMessageAdapter.setImageClose(null, true);
            editMessageAdapter.setDeleteImage(new EditMessageAdapter.DeleteImage() {
                @Override
                public void deleteSucc(View view, int position) {
                    Log.i(PublicUtils.AppName, "delete succ");
                    editMessageAdapter.notifyDataSetChanged();
                }
            });
        }
        return false;
    }
注:这里判断也是因为当position为加号添加图片时长按误删掉。

实现onActivityResult,接收回传值:

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == ImagePicker.RESULT_CODE_ITEMS) {//返回多张照片
            if (data != null) {
                //是否发送原图
                boolean isOrig = data.getBooleanExtra(ImagePreviewActivity.ISORIGIN, false);
                ArrayList images = (ArrayList) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS);
                Log.e("CSDN_LQR", isOrig ? "发原图" : "不发原图");//若不发原图的话,需要在自己在项目中做好压缩图片算法
                datas.clear();
                for (ImageItem imageItem : images) {
                    Log.e("CSDN_LQR", imageItem.path);
                    String ImgUrl = imageItem.path;
                    imageData = new ImageData(ImgUrl);
                    datas.add(imageData);
                }
                //刷新一下数据
            }
        }
    }
注:当data != null,刷新一下数据源,避免删除或者添加之后看不到效果。

Adapter适配器.java:

public class EditMessageAdapter extends BaseAdapter {

    Activity activity;

    List datas = new ArrayList<>();

    GridView gv_edit_message;

    LayoutInflater inflater;

    ImageView gv_edit_message_item, gv_edit_message_item_close;

    boolean showImageClose = false;

    ImageClose imageClose;

    public void setImageClose(ImageClose imageClose, boolean showImageClose) {
        this.imageClose = imageClose;
        this.showImageClose = showImageClose;
        notifyDataSetChanged();
    }

    interface ImageClose{

    };

    DeleteImage deleteImage;

    public void setDeleteImage(DeleteImage deleteImage) {
        this.deleteImage = deleteImage;
    }

    public interface DeleteImage{
        void deleteSucc(View view,int position);
    };

    public EditMessageAdapter(Activity activity, List datas, GridView gv_edit_message){
        this.activity = activity;
        this.datas = datas;
        this.gv_edit_message = gv_edit_message;

        this.inflater = activity.getLayoutInflater();
    }

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

    @Override
    public ImageData getItem(int position) {
        return datas.get(position);
    }

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        //当回收的view为空,重新获取
        if(convertView == null){
            convertView = inflater.inflate(R.layout.gv_edit_message_item, null);
        }
        convertView.setTag(position);
        //拿到每一个item的值
        ImageData info = getItem(position);

        gv_edit_message_item = convertView.findViewById(R.id.gv_edit_message_item);
        gv_edit_message_item_close = convertView.findViewById(R.id.gv_edit_message_item_close);

        if(showImageClose){
            gv_edit_message_item_close.setVisibility(View.VISIBLE);
        }else{
            gv_edit_message_item_close.setVisibility(View.GONE);
        }

        gv_edit_message_item_close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                datas.remove(position);
                if(datas.size() == 0){
                    Log.i(PublicUtils.AppName, "delete结束,默认加载Add按钮!");
                    datas.add(new ImageData("default"));
                    showImageClose = false;
                    gv_edit_message_item.setImageResource(R.mipmap.qq_groupmanager_edit_add_icon);
                }
                deleteImage.deleteSucc(v, position);
                Log.i(PublicUtils.AppName, "delete succ");
            }
        });

        if(info.url.equals("default")){
            Log.i(PublicUtils.AppName, "默认加载Add按钮!");
        }else{
            gv_edit_message_item.setImageBitmap(compressImageFromFile(info.url));
        }

        return convertView;
    }

    /**
     * 压缩本地图片
     * @param srcPath
     * @return
     */
    private Bitmap compressImageFromFile(String srcPath) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;//只读边,不读内容
        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);

        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        float hh = 800f;//
        float ww = 480f;//
        int be = 1;
        if (w > h && w > ww) {
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;//设置采样率

        newOpts.inPreferredConfig = Bitmap.Config.ARGB_8888;//该模式是默认的,可不设
        newOpts.inPurgeable = true;// 同时设置才会有效
        newOpts.inInputShareable = true;//。当系统内存不够时候图片自动被回收

        bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
//      return compressBmpFromBmp(bitmap);//原来的方法调用了这个方法企图进行二次压缩
        //其实是无效的,大家尽管尝试
        return bitmap;
    }

}
注:当图片选定之后,需要使用compressImageFromFile压缩图片,避免因为图片过大出现oom。

当然是需要第三方的图片压缩库的,附上链接:
http://download.csdn.net/download/qq_35840038/10184262


因为上传图片功能在我的完整项目中,而完整项目太大,csdn无法上传,所以有需要的还是加我Q吧
q:486789970
email:[email protected]


由于个人原因,今天就先到这里,如果有什么问题,欢迎大家指导,也供大家相互学习。

你可能感兴趣的:(上传图片)