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

您所在的位置:网站首页 微信朋友圈的图片怎么设置 微信朋友圈的图片上传,多图上传怎么去撸才合适?我们一起来实现吧!

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

2024-06-21 17:52| 来源: 网络整理| 查看: 265

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

这里写图片描述

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

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

activity_main.xml

他只是一个主页,我们只要实现它的点击事件就好了,点击之后跳转到我们的上传图片的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

我们现在就要分析我们怎么去实现了,这个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 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 mList; //布局加载器 private LayoutInflater mInflater; //实体类 private PhotoBean bean; //上下文 private Context mContext; //屏幕宽高 private int w, h; /** * @param mContext * @param mList */ public GridAdapter(Context mContext, List 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 { /** * 后台加载 * * @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


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3