微信朋友圈的图片上传,多图上传怎么去撸才合适?我们一起来实现吧!

微信朋友圈的图片上传,多图上传怎么去撸才合适?我们一起来实现吧!



图片上传是非常常见的功能,而多图上传在大多数应用中也是非常常见的,比如微信的朋友圈,微博的动态,都是有九宫格图片的,那这里肯定涉及了多图上传,所以今天我们来一起撸一下,怎么去思考这个实现逻辑!

这里我想到的思路是比较简单的,首先,我们有一个按钮,按钮是上传图片,点击之后弹出某个界面进行图片的选择,一般是九张图片或者十二张,选完之后就直接上传了,大致的流程应该是这个样子,那我们首先来写个按钮

activity_main.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"
    android:orientation="vertical"
    android:padding="10dp">

    <Button
        android:id="@+id/btnAddPhoto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="上传图片"/>

</LinearLayout>

他只是一个主页,我们只要实现它的点击事件就好了,点击之后跳转到我们的上传图片的Activcity

MainActivity

package com.liuguilin.uploadphotossample;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private Button btnAddPhoto;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //点击事件
        findViewById(R.id.btnAddPhoto).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(MainActivity.this,UploadPhotoActivity.class));
            }
        });
    }
}

这些都是可以一笔带过的,真正的逻辑全部都在这个UploadPhotoActivity,我们用GridView显示图片,并且进行多选,下面有一个按钮负责显示已选图片的数量以及完成上传的功能

activity_upload.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"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <GridView
        android:id="@+id/mGradView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:numColumns="3"/>

    <Button
        android:id="@+id/btnOk"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:background="@color/colorAccent"
        android:text="2/12 完成"
        android:textColor="@android:color/white"/>

</LinearLayout>

我们现在就要分析我们怎么去实现了,这个GridView肯定是要写的,但是我们首先得要拿到我们的图片,图片怎么拿?肯定是看相册的源码来分析他是怎么去拿的,这里呢,我们使用的是ContentResolver内容访问者,我们查看下源码,我们主要还是看MediaProvider这个项目

我们只要看他最先的一段静态块

static
    {
        URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA);
        URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID);
        URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS);
        URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID);

        URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA);
        URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID);
        URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES);
        URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID);
        URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS);
        URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID);
        URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES);
        URI_MATCHER.addURI("media", "*/audio/genres/#", AUDIO_GENRES_ID);
        URI_MATCHER.addURI("media", "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS);
        URI_MATCHER.addURI("media", "*/audio/genres/all/members", AUDIO_GENRES_ALL_MEMBERS);
        URI_MATCHER.addURI("media", "*/audio/playlists", AUDIO_PLAYLISTS);
        URI_MATCHER.addURI("media", "*/audio/playlists/#", AUDIO_PLAYLISTS_ID);
        URI_MATCHER.addURI("media", "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS);
        URI_MATCHER.addURI("media", "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID);
        URI_MATCHER.addURI("media", "*/audio/artists", AUDIO_ARTISTS);
        URI_MATCHER.addURI("media", "*/audio/artists/#", AUDIO_ARTISTS_ID);
        URI_MATCHER.addURI("media", "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS);
        URI_MATCHER.addURI("media", "*/audio/albums", AUDIO_ALBUMS);
        URI_MATCHER.addURI("media", "*/audio/albums/#", AUDIO_ALBUMS_ID);
        URI_MATCHER.addURI("media", "*/audio/albumart", AUDIO_ALBUMART);
        URI_MATCHER.addURI("media", "*/audio/albumart/#", AUDIO_ALBUMART_ID);
        URI_MATCHER.addURI("media", "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID);

        URI_MATCHER.addURI("media", "*/video/media", VIDEO_MEDIA);
        URI_MATCHER.addURI("media", "*/video/media/#", VIDEO_MEDIA_ID);
        URI_MATCHER.addURI("media", "*/video/thumbnails", VIDEO_THUMBNAILS);
        URI_MATCHER.addURI("media", "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID);

        URI_MATCHER.addURI("media", "*/media_scanner", MEDIA_SCANNER);

        URI_MATCHER.addURI("media", "*/fs_id", FS_ID);
        URI_MATCHER.addURI("media", "*/version", VERSION);

        URI_MATCHER.addURI("media", "*/mtp_connected", MTP_CONNECTED);

        URI_MATCHER.addURI("media", "*", VOLUMES_ID);
        URI_MATCHER.addURI("media", null, VOLUMES);

        // Used by MTP implementation
        URI_MATCHER.addURI("media", "*/file", FILES);
        URI_MATCHER.addURI("media", "*/file/#", FILES_ID);
        URI_MATCHER.addURI("media", "*/object", MTP_OBJECTS);
        URI_MATCHER.addURI("media", "*/object/#", MTP_OBJECTS_ID);
        URI_MATCHER.addURI("media", "*/object/#/references", MTP_OBJECT_REFERENCES);

        /**
        * @deprecated use the ‘basic‘ or ‘fancy‘ search Uris instead
         */
        URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY,
                AUDIO_SEARCH_LEGACY);
        URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
                AUDIO_SEARCH_LEGACY);

        // used for search suggestions
        URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY,
                AUDIO_SEARCH_BASIC);
        URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY +
               "/*", AUDIO_SEARCH_BASIC);

        // used by the music app‘s search activity
        URI_MATCHER.addURI("media", "*/audio/search/fancy", AUDIO_SEARCH_FANCY);
        URI_MATCHER.addURI("media", "*/audio/search/fancy/*", AUDIO_SEARCH_FANCY);
    }

这段代码块就是我们访问系统数据库索要获取任意数据的URI,而我们访问图片的URI是

URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA);

不过既然是内容提供者,google也是封装好了一些方法供我们使用

    /**
     * 初始化数据
     */
    private void initData() {
        //获取手机相册图片 访问本机数据库
        ContentResolver mContentResolver = getContentResolver();
        //图片数据的url(外部存储)
        Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        //查询
        Cursor cursor = mContentResolver.query(uri,null,null,null,null);
        //遍历
        while (cursor.moveToNext()){
            PhotoBean bean = new PhotoBean();
            //获取路径
            String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            //设置路径
            bean.setPath(path);
            //默认fasle
            bean.setSelect(false);
            //保存
            mList.add(bean);
        }

    }

OK,当我们拿到这些相册的图片肯定是要去存储,那我们怎么去存储?一般都是用个实体对象的

PhotoBean

package com.liuguilin.uploadphotossample;

/*
 *  项目名:  UploadPhotosSample
 *  包名:    com.liuguilin.uploadphotossample
 *  文件名:   PhotoBean
 *  创建者:   LGL
 *  创建时间:  2016/8/31 13:14
 *  描述:    图片存储对象
 */

import android.graphics.Bitmap;

public class PhotoBean {

    //路径
    private String path;
    //是否选择
    private boolean isSelect;
    //位图转换
    private Bitmap bitmap;

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public boolean isSelect() {
        return isSelect;
    }

    public void setSelect(boolean select) {
        isSelect = select;
    }

    public Bitmap getBitmap() {
        return bitmap;
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
    }
}

OK,现在可以专心的来写我们的Adapter,也就是数据适配器了

GridAdapter

package com.liuguilin.uploadphotossample;

/*
 *  项目名:  UploadPhotosSample
 *  包名:    com.liuguilin.uploadphotossample
 *  文件名:   GridAdapter
 *  创建者:   LGL
 *  创建时间:  2016/8/31 13:32
 *  描述:    数据适配器
 */

import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;

import java.util.List;

public class GridAdapter extends BaseAdapter {

    //数据
    private List<PhotoBean> mList;
    //布局加载器
    private LayoutInflater mInflater;
    //实体类
    private PhotoBean bean;
    //上下文
    private Context mContext;
    //屏幕宽高
    private int w, h;

    /**
     * @param mContext
     * @param mList
     */
    public GridAdapter(Context mContext, List<PhotoBean> mList) {
        this.mContext = mContext;
        this.mList = mList;
        //系統服務
        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        getPhoneWH();
    }

    /**
     * 获取手机屏幕的宽高
     */
    private void getPhoneWH() {
        w = mContext.getResources().getDisplayMetrics().widthPixels;
        h = mContext.getResources().getDisplayMetrics().heightPixels;
    }

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

    @Override
    public Object getItem(int i) {
        return mList.get(i);
    }

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

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder = null;
        if (view == null) {
            viewHolder = new ViewHolder();
            view = mInflater.inflate(R.layout.list_item, null);
            //初始化
            viewHolder.img = (ImageView) view.findViewById(R.id.img);
            //设置图片最小宽高
            viewHolder.img.setMinimumWidth(w / 3);
            viewHolder.img.setMinimumHeight(h / 3);
            viewHolder.img_select = (ImageView) view.findViewById(R.id.img_select);
            view.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) view.getTag();
        }

        //获取position
        bean = mList.get(i);
        //是否选中
        if (bean.isSelect()) {
            viewHolder.img_select.setVisibility(View.VISIBLE);
        } else {
            viewHolder.img_select.setVisibility(View.INVISIBLE);
        }
        //是否有图片
        if (bean.getBitmap() == null) {
            //图片加载,异步加载
            new ImgTask().execute(bean.getPath(), String.valueOf(i));
        } else {
            //设置图片
            viewHolder.img.setImageBitmap(bean.getBitmap());
        }
        return view;
    }

    /**
     * 緩存
     */
    static class ViewHolder {
        private ImageView img;
        private ImageView img_select;
    }

    /**
     * 异步任务
     */
    private class ImgTask extends AsyncTask<String, Void, Bitmap> {

        /**
         * 后台加载
         *
         * @param strings
         * @return
         */
        @Override
        protected Bitmap doInBackground(String... strings) {
            //图片路径
            String path = strings[0];
            //position
            int position = Integer.parseInt(strings[1]);
            //图片压缩
            Bitmap bitmap = BitmapUtils.getScaleBitmapPath(mContext, path);
            //设置图片
            mList.get(position).setBitmap(bitmap);
            return bitmap;
        }

        /**
         * 刷新视图
         *
         * @param bitmap
         */
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            //刷新
            GridAdapter.this.notifyDataSetChanged();
        }
    }
}

我们在里面做了很多的事情,首选是ViewHolder的优化,然后就是异步加载图片了,接着获取屏幕的高宽去适配,当然,这里做了一个bitmap的工具类

BitmapUtils

package com.liuguilin.uploadphotossample;

/*
 *  项目名:  UploadPhotosSample
 *  包名:    com.liuguilin.uploadphotossample
 *  文件名:   BitmapUtils
 *  创建者:   LGL
 *  创建时间:  2016/8/31 14:18
 *  描述:    图片压缩处理
 */

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class BitmapUtils {

    /**
     * 本地图片压缩处理
     *
     * @param mContext 上下文
     * @param path     路径
     * @return
     */
    public static Bitmap getScaleBitmapPath(Context mContext, String path) {
        Bitmap bitmap;
        int w;
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        bitmap = BitmapFactory.decodeFile(path, options);
        w = options.outWidth;
        if (w < 50) {
            options.inSampleSize = w / 50;
            options.inJustDecodeBounds = false;
            bitmap = BitmapFactory.decodeFile(path, options);
        } else {
            bitmap = BitmapFactory.decodeFile(path);
        }
        return bitmap;
    }
}

现在我们可以把我们的数据加载进去了

    /**
     * 初始化View
     */
    private void initView() {

        btnOk = (Button) findViewById(R.id.btnOk);
        btnOk.setOnClickListener(this);
        mGridView = (GridView) findViewById(R.id.mGridView);

        //设置数据
        adapter = new GridAdapter(this, mList);
        mGridView.setAdapter(adapter);
    }

这样,我们其实是可以看到加载的效果的,这就是相册实现的最基本原理了

到这里,基本上就成功了一半了,现在开始做点击了,只要点击图片,就显示勾选,那我们就要监听他的点击事件了

        /**
         * 点击事件
         */
        mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                count =0;
                PhotoBean bean = mList.get(i);
                bean.setSelect(!bean.isSelect());
                //遍历
                for (PhotoBean p : mList) {
                    //如果
                    if (p.isSelect()) {
                        count++;
                    }
                }
                //刷新
                adapter.notifyDataSetChanged();
                btnOk.setText(count + "/ 9 完成");
            }
        });

到这里,我们大致的模样是不是已经出来了,我们看下效果

现在只要点击做的就是上传了,我们怎么上传?其实很简单,我们只要在遍历的时候同时拿到路径就好了,所以我们的GradView的点击事件应该是这样写的

        /**
         * 点击事件
         */
        mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                count = 0;
                mListPath.clear();
                PhotoBean bean = mList.get(i);
                bean.setSelect(!bean.isSelect());
                //遍历
                for (PhotoBean p : mList) {
                    //如果
                    if (p.isSelect()) {
                        count++;
                        mListPath.add(p.getPath());
                    }
                }
                //刷新
                adapter.notifyDataSetChanged();
                btnOk.setText(count + "/ 9 完成");
            }
        });

而我们的按钮点击事件

    /**
     * 点击事件
     *
     * @param view
     */
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            //上传图片
            case R.id.btnOk:
                finish();
                Toast.makeText(this, mListPath.toString(), Toast.LENGTH_LONG).show();
                break;
        }
    }

我就直接Toast了,因为我们有路径了,只要往服务器一扔就完事了,对吧,这里就推荐使用RxVolley了,很方便

   //post请求简洁版实现
    HttpParams params = new HttpParams();
    //文件上传
    params.put("image", new File("path"))

    RxVolley.post(url, params, new HttpCallback() {
        @Override
        public void onSuccess(String t) {
           Loger.debug("请求到的数据:" + t);
      }
 });

OK,我们来最后看一遍效果图

记得在清单文件里添加一个小权限哦!

好的,这篇博客就到这里了,每次写博客都写到深更半夜,太痛苦了!!!

一起玩玩?加群:555974449

UploadPhotosSample:http://download.csdn.net/detail/qq_26787115/9618368

时间: 2024-10-10 09:45:55

微信朋友圈的图片上传,多图上传怎么去撸才合适?我们一起来实现吧!的相关文章

仿微信朋友圈发图片

仿微信朋友圈发图片 下载地址:http://www.devstore.cn/code/info/934.html 运行截图:    

微信朋友圈广告来袭,IBM制定史上最大规模裁员计划

1.第一波微信朋友圈广告来袭,宝马中国.vivo和可口可乐你收到了哪一个? 1 月 21 日,就有消息称,第一支微信朋友圈广告会上线,不过直到昨晚,跳票了 4 天之久的朋友圈广告才终于露面.而最终与4亿多用户见面的是三条不同的广告:不同的人群收到的分别是宝马中国.vivo手机和可口可乐的推广广告. 在形式上,朋友圈第一波广告和普通好友的图文朋友圈差别不大,都是文字配图片,只是附加了“推广”标识,以及“查看详情”的 Html5 链接,可点击进入.从这一点来说,朋友圈广告也许并不比代购小广告惹人烦.

一百行代码实现微信朋友圈九宫格图片显示

前言 很多时候我们都在刷微博或者微信朋友圈的时候都会看到很多图片,而这些图片的显示跟我们平时很多控件的显示方式都不一样,而且,当我们仔细去观察后就会发现,他加载的图片都是根据图片数量动态加载的,根据不同的图片数量来用不同的布局显示 当图片是4张的时候,就会形成一个2x2的正方形,除了一张的情况,另外的都是按照九宫格的方式显示和排列图片的.那么这种布局是怎么实现的呢,一开始,好多人都可能认为用原生的GridView就能搞掂,但是,却有几种特殊的情况是GridView解决不了的,例如4张图片的情况,

阿里大神动态教你ViewGroup(实现微信朋友圈九宫格图片控件)你还不来看看吗?

简介 最近项目里有个类似微信朋友圈的九图控件的需求,Github找了一下,发现都不太满足需求,我需要单张图片的时候可以按照图片宽高比列在一定范围内自适应,而大多开源项目单张图片也是一个小正方形,所以,干脆自己动手写一个 项目源码 具体自定义NineImageLayout过程,可以查看NineImageLayout. 效果图如下: 主要功能如下: 1:单张图片的时候支持按照图片宽高比列在设定区域内自适应2:Adapter方式绑定数据和UI3:图片点击事件回调4:设置图片间隔大小5:自由通过Glid

微信朋友圈:应对春节千亿访问量背后的故事

欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯技术工程官方号 微信朋友圈包括图片和视频两套业务架构组成,朋友圈图片的特点是请求量大.消耗计算资源较多,视频则主要消耗带宽.朋友圈的数据是永远存储的,而且随着业务的快速发展,存储容量.带宽和设备的消耗大量增加,而重大节日带来的使用量增长,更加剧了消耗,也给运维人员的保障带来了巨大压力. 节日保障主要由三方面组成:软件保障指通过程序.业务逻辑层面的优化和评估,减轻负载:硬件保障主要指带宽.机器负载的评估和扩容:柔性措施指的是通过业

iOS微信朋友圈 评论点击姓名功能 (补充)

如果要做成微信朋友圈的评论效果, 那么评论用一个UITableview去加载,每个UITableviewCell上加载一个PPLabel. 但是这样会导致一个问题,PPLable在响应点击单词的时候,同样UITableviewCell会响应select事件. 有两种处理办法: 1.截取点击事件,这种办法比较复杂,需要了解iOS的事件传递机制.由于PPLable在事件响应的最底层,而我们需要在PPLable中判断了是否点击到单词,才能决定UITableviewCell是否响应点击事件,这样的做法过

iOS开发——项目实战总结&amp;类微信朋友圈发动态功能初步-图片与视频上传

类微信朋友圈发动态功能初步-图片与视频上传 最近在做一个新的项目,涉及到了关于图片和视频上传和显示的功能,研究了一段时间,总结一下. 使用AFNetworking上传图片(可一次上传多张图片,包含不同类型png, jpeg)和视频 1 AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 2 3 AFHTTPRequestOperation *operation = [manager P

【史上最全】微信朋友圈游戏源码下载

源码介绍:  所有源码都是html5开发,可以跨平台,无论谷歌安卓还是苹果ios都可以流畅运行,游戏可以根据自己的情况添加链接,可以分享到微信圈后跳转的你的游戏平台页.个别游戏可以设置指定次数提示添加微信账号回复指定内容获得答案.保证游戏可运行性,不像某些不良卖家价格很高买来的根本没几个能用或者很多凑数游戏. 一个简单的营利模式: 通过手机作为入口,分享某某游戏的得分到朋友圈,朋友圈内的病毒式传播速度超过你想象.然后你可以自己加入关注微信代码.百度移动广告代码.淘客代码.等等吧,可以发挥的空间非

Android:NineGridLayout — 仿微信朋友圈和QQ空间的九宫格图片展示自定义控件

NineGridLayout 一个仿微信朋友圈和QQ空间的九宫格图片展示自定义控件. GitHub:https://github.com/HMY314/NineGridLayout 一.介绍 1.当只有1张图时,可以自己定制图片宽高,也可以使用默认九宫格的宽高: 2.当只有4张图时,以2*2的方式显示: 3.除以上两种情况下,都是按照3列方式显示,但这时有一些细节: a.如果只有9张图,当然是以3*3的方式显示: b.如果超过9张图,可以设置是否全部显示. 如果设置不完全显示,则按照3*3的方式