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


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

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

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="10dp"><Buttonandroid: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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//点击事件findViewById(R.id.btnAddPhoto).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {startActivity(new Intent(MainActivity.this,UploadPhotoActivity.class));}});}
}

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

activity_upload.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns: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"><GridViewandroid:id="@+id/mGradView"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:numColumns="3"/><Buttonandroid: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这个项目

  • http://androidxref.com/4.0.3_r1/xref/packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java

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

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 implementationURI_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 suggestionsURI_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 activityURI_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);//默认faslebean.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;}@Overridepublic int getCount() {return mList.size();}@Overridepublic Object getItem(int i) {return mList.get(i);}@Overridepublic long getItemId(int i) {return i;}@Overridepublic 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();}//获取positionbean = 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*/@Overrideprotected Bitmap doInBackground(String... strings) {//图片路径String path = strings[0];//positionint position = Integer.parseInt(strings[1]);//图片压缩Bitmap bitmap = BitmapUtils.getScaleBitmapPath(mContext, path);//设置图片mList.get(position).setBitmap(bitmap);return bitmap;}/*** 刷新视图** @param bitmap*/@Overrideprotected 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() {@Overridepublic 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() {@Overridepublic 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*/@Overridepublic 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() {@Overridepublic void onSuccess(String t) {Loger.debug("请求到的数据:" + t);}});

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

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

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

一起玩玩?加群:555974449

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

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

  1. Android 仿微信朋友圈添加图片

    github地址(欢迎下载Demo) https://github.com/zhouxu88/WXCircleAddPic 老习惯,先上图,着急用的朋友,直接带走Demo,先拿来用吧,毕竟老板催的紧, ...

  2. 安卓开发仿微信图片拖拽_仿微信朋友圈发表图片拖拽和删除功能

    原标题:仿微信朋友圈发表图片拖拽和删除功能 中国联通在香港公布了上市公司2017年中期业绩.2017年上半年,公司主要业绩指标持续向好,收入稳步回升,服务收入达到人民币1,241.1亿元,同比增长3. ...

  3. android 打开微信好友动态图片,Android GridView仿微信朋友圈显示图片

    最近项目要求上传多图并且多图显示,而且要规则的显示,就像微信朋友圈的图片显示一样. 利用GridView再适合不过了,GridView可以动态加载图片的数量,而且还比较规律,下面说一下自己的思路: 1 ...

  4. 【Android 控件使用及源码解析】 GridView规则显示图片仿微信朋友圈发图片

    今天闲下来想用心写一点东西,发现没什么可写的,就写一下最近项目上用到的一些东西吧.最近项目要求上传多图并且多图显示,而且要规则的显示,就像微信朋友圈的图片显示一样. 想了一下用GridView再适合不 ...

  5. 这可能是最接近微信朋友圈的图片压缩算法

    开源最前线(ID:OpenSourceTop) 猿妹 整编 综合自:https://github.com/Curzibn/Luban 目前做APP开发总绕不开图片元素,如今手机拍照分辨率都非常高,图片 ...

  6. android从九宫格全屏预览,仿微信朋友圈展示图片的九宫格图片展示控件,支持点击图片全屏预览大图...

    AssNineGridView 仿微信朋友圈展示图片的九宫格图片展示控件,支持点击图片全屏预览大图(可自定义). 写在前面 这是一个九宫格控件,本来是很久之前就写好了,现在才开源出来,也是看了很多优秀 ...

  7. Android 实现仿微信朋友圈九宫格图片+NineGridView+ImageWatcher(图片查看:1.预览,2.拖动,3.放大,4.左右滑动,5.长按保存到手机)的功能

    一.测试 实现: 二.添加依赖包: implementation 'androidx.appcompat:appcompat:1.1.0'implementation 'androidx.recycl ...

  8. Android仿微信朋友圈发图片和文字

    Android仿微信朋友圈发图片和文字的一个开源项目,其在github上的项目主页是:https://github.com/zhangphil/FangWeiXinPengYouQuanFaTuPia ...

  9. android仿空间照片查看器,PhotoViewer 一个简单仿微信朋友圈的图片查看器

    该图片查看器是模仿微信朋友圈查看图片编写 allprojects { repositories { ... maven { url 'https://jitpack.io' } } } lastRel ...

最新文章

  1. Android被忽略的tools
  2. react笔记-设计复合式控件(三)
  3. Ubuntu18使用kubeadm安装kubernetes1.12
  4. 输入一个数,判断这个数的二进制有几个0,几个1(完整代码)
  5. 《软件工程》总结——第一章
  6. 思科3560交换机端口限速
  7. 设置blender界面语言为中文以及字体大小设置之方法
  8. 在Arcgis中利用Python编写脚本批量化处理数据实例
  9. 用户故事与敏捷方法—一些用户故事(实战二)
  10. Qt学习之资源文件(qrc)的添加以及使用
  11. 正确区分LJMP、AJMP、SJMP、JMP指令
  12. Excel-VBA 快速上手(三、数组和字典)
  13. Java微信公众号开发之微信素材管理工具类
  14. 移动APP测试经验总结
  15. 达人评测:i5-1135g7相当于什么水平-i5-1135g7是低压吗
  16. 计算机英语五人对话,英文应聘对话5人的急求一篇英语对话 关于应聘的 最好是五人的...
  17. 21cn企业邮箱服务器端口号,我怎么样才能知道自己邮箱的端口号?
  18. JavaScript---常用的鼠标事件mouseover 和mouseenter的区别
  19. 当贝显示服务器生病,【当贝市场】DNS服务器失效,解决江苏移动故障
  20. 《精品毕设》 java springboot+mybatis二手物品网站系统完整源码+论文

热门文章

  1. 如何更新Mozilla Firefox
  2. 推荐系统应用---音乐类
  3. js实现滑动验证码功能
  4. ubuntu 终端设置代理上网后,如何清楚代理设置
  5. 因果推断6--多任务学习(个人笔记)
  6. 蓝桥杯算法训练 瓷砖铺放JAVA
  7. js循环添加事件的两种方法
  8. java使用Graphics2D进行图片文字合成示例
  9. iPhone 基带命令
  10. JAVA计算机毕业设计招生平台管理系统Mybatis+源码+数据库+lw文档+系统+调试部署