配色: 字号:
微信朋友圈的图片上传,多图上传怎么去撸才合适?我们一起来实现吧!
2016-10-08 | 阅:  转:  |  分享 
  
微信朋友圈的图片上传,多图上传怎么去撸才合适?我们一起来实现吧!



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



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

activity_main.xml






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">




android:id="@+id/btnAddPhoto"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="上传图片"/>









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

MainActivity



packagecom.liuguilin.uploadphotossample;



importandroid.content.Intent;

importandroid.support.v7.app.AppCompatActivity;

importandroid.os.Bundle;

importandroid.view.View;

importandroid.widget.Button;



publicclassMainActivityextendsAppCompatActivity{



privateButtonbtnAddPhoto;



@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//点击事件

findViewById(R.id.btnAddPhoto).setOnClickListener(newView.OnClickListener(){

@Override

publicvoidonClick(Viewview){

startActivity(newIntent(MainActivity.this,UploadPhotoActivity.class));

}

});

}

}



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

activity_upload.xml






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">




android:id="@+id/mGradView"

android:layout_width="match_parent"

android:layout_height="0dp"

android:layout_weight="1"

android:numColumns="3"/>




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"/>







我们现在就要分析我们怎么去实现了,这个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);



//UsedbyMTPimplementation

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);



/

@deprecatedusethe''basic''or''fancy''searchUrisinstead

/

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);



//usedforsearchsuggestions

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);



//usedbythemusicapp''ssearchactivity

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);

1

1

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

/

初始化数据

/

privatevoidinitData(){

//获取手机相册图片访问本机数据库

ContentResolvermContentResolver=getContentResolver();

//图片数据的url(外部存储)

Uriuri=MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

//查询

Cursorcursor=mContentResolver.query(uri,null,null,null,null);

//遍历

while(cursor.moveToNext()){

PhotoBeanbean=newPhotoBean();

//获取路径

Stringpath=cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));

//设置路径

bean.setPath(path);

//默认fasle

bean.setSelect(false);

//保存

mList.add(bean);

}



}



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

PhotoBean



packagecom.liuguilin.uploadphotossample;



/

项目名:UploadPhotosSample

包名:com.liuguilin.uploadphotossample

文件名:PhotoBean

创建者:LGL

创建时间:2016/8/3113:14

描述:图片存储对象

/



importandroid.graphics.Bitmap;



publicclassPhotoBean{



//路径

privateStringpath;

//是否选择

privatebooleanisSelect;

//位图转换

privateBitmapbitmap;



publicStringgetPath(){

returnpath;

}



publicvoidsetPath(Stringpath){

this.path=path;

}



publicbooleanisSelect(){

returnisSelect;

}



publicvoidsetSelect(booleanselect){

isSelect=select;

}



publicBitmapgetBitmap(){

returnbitmap;

}



publicvoidsetBitmap(Bitmapbitmap){

this.bitmap=bitmap;

}

}



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

GridAdapter



packagecom.liuguilin.uploadphotossample;



/

项目名:UploadPhotosSample

包名:com.liuguilin.uploadphotossample

文件名:GridAdapter

创建者:LGL

创建时间:2016/8/3113:32

描述:数据适配器

/



importandroid.content.Context;

importandroid.graphics.Bitmap;

importandroid.os.AsyncTask;

importandroid.view.LayoutInflater;

importandroid.view.View;

importandroid.view.ViewGroup;

importandroid.widget.BaseAdapter;

importandroid.widget.ImageView;



importjava.util.List;



publicclassGridAdapterextendsBaseAdapter{



//数据

privateListmList;

//布局加载器

privateLayoutInflatermInflater;

//实体类

privatePhotoBeanbean;

//上下文

privateContextmContext;

//屏幕宽高

privateintw,h;



/

@parammContext

@parammList

/

publicGridAdapter(ContextmContext,ListmList){

this.mContext=mContext;

this.mList=mList;

//系統服務

mInflater=(LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);



getPhoneWH();

}



/

获取手机屏幕的宽高

/

privatevoidgetPhoneWH(){

w=mContext.getResources().getDisplayMetrics().widthPixels;

h=mContext.getResources().getDisplayMetrics().heightPixels;

}



@Override

publicintgetCount(){

returnmList.size();

}



@Override

publicObjectgetItem(inti){

returnmList.get(i);

}



@Override

publiclonggetItemId(inti){

returni;

}



@Override

publicViewgetView(inti,Viewview,ViewGroupviewGroup){

ViewHolderviewHolder=null;

if(view==nulwww.sm136.coml){

viewHolder=newViewHolder();

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){

//图片加载,异步加载

newImgTask().execute(bean.getPath(),String.valueOf(i));

}else{

//设置图片

viewHolder.img.setImageBitmap(bean.getBitmap());

}

returnview;

}





/

緩存

/

staticclassViewHolder{

privateImageViewimg;

privateImageViewimg_select;

}



/

异步任务

/

privateclassImgTaskextendsAsyncTask{



/

后台加载



@paramstrings

@return

/

@Override

protectedBitmapdoInBackground(String...strings){

//图片路径

Stringpath=strings[0];

//position

intposition=Integer.parseInt(strings[1]);

//图片压缩

Bitmapbitmap=BitmapUtils.getScaleBitmapPath(mContext,path);

//设置图片

mList.get(position).setBitmap(bitmap);

returnbitmap;

}



/

刷新视图



@parambitmap

/

@Override

protectedvoidonPostExecute(Bitmapbitmap){

super.onPostExecwww.shanxiwang.netute(bitmap);

//刷新

GridAdapter.this.notifyDataSetChanged();

}

}

}



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

BitmapUtils



packagecom.liuguilin.uploadphotossample;



/

项目名:UploadPhotosSample

包名:com.liuguilin.uploadphotossample

文件名:BitmapUtils

创建者:LGL

创建时间:2016/8/3114:18

描述:图片压缩处理

/



importandroid.content.Context;

importandroid.graphics.Bitmap;

importandroid.graphics.BitmapFactory;



publicclassBitmapUtils{



/

本地图片压缩处理



@parammContext上下文

@parampath路径

@return

/

publicstaticBitmapgetScaleBitmapPath(ContextmContext,Stringpath){

Bitmapbitmap;

intw;

BitmapFactory.Optionsoptions=newBitmapFactory.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);

}

returnbitmap;

}

}



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

/

初始化View

/

privatevoidinitView(){



btnOk=(Button)findViewById(R.id.btnOk);

btnOk.setOnClickListener(this);

mGridView=(GridView)findViewById(R.id.mGridView);



//设置数据

adapter=newGridAdapter(this,mList);

mGridView.setAdapter(adapter);

}



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



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

/

点击事件

/

mGridView.setOnItemClickListener(newAdapterView.OnItemClickListener(){

@Override

publicvoidonItemClick(AdapterViewadapterView,Viewview,inti,longl){

count=0;

PhotoBeanbean=mList.get(i);

bean.setSelect(!bean.isSelect());

//遍历

for(PhotoBeanp:mList){

//如果

if(p.isSelect()){

count++;

}

}

//刷新

adapter.notifyDataSetChanged();

btnOk.setText(count+"/9完成");

}

});



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



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

/

点击事件

/

mGridView.setOnItemClickListener(newAdapterView.OnItemClickListener(){

@Override

publicvoidonItemClick(AdapterViewadapterView,Viewview,inti,longl){

count=0;

mListPath.clear();

PhotoBeanbean=mList.get(i);

bean.setSelect(!bean.isSelect());

//遍历

for(PhotoBeanp:mList){

//如果

if(p.isSelect()){

count++;

mListPath.add(p.getPath());

}

}

//刷新

adapter.notifyDataSetChanged();

btnOk.setText(count+"/9完成");

}

});



而我们的按钮点击事件

/

点击事件



@paramview

/

@Override

publicvoidonClick(Viewview){

switch(view.getId()){

//上传图片

caseR.id.btnOk:

finish();

Toast.makeText(this,mListPath.toString(),Toast.LENGTH_LONG).show();

break;

}

}



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

//post请求简洁版实现

HttpParamsparams=newHttpParams();

//文件上传

params.put("image",newFile("path"))



RxVolley.post(url,params,newHttpCallback(){

@Override

publicvoidonSuccess(Stringt){

Loger.debug("请求到的数据:"+t);

}

});



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



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

献花(0)
+1
(本文系网络学习天...首藏)