安卓Base64批量上传至服务器
来源:互联网 发布:西装 知乎 编辑:程序博客网 时间:2024/06/06 08:42
Step1:效果图
Step2:整体过程
/**
* 由于请求框架开始就是Xutils compile ‘org.xutils:xutils:3.3.36’ 不做更改
* 1.第三方的图片选择器(支持选择多张图片、预览、删除等)
* 2.onActivityResult 返回选择图片的数组
* 3.注意:接口有2个 A接口:专门用于接受图片base64码 B接口用来上传 标题、内容和拼接的url链接
* 4.
* ①:将选取的图片路径的转化为base64字符串 encode()方法
* ②:选取多张时采用计数叠加一张张的上传 每上传一张将地址进行拼接 StringBuffer()方法
* ③:当上传图片完成时A接口结束,在调用B接口 传入对应的参数即可,图片是多张之后的url链接,要去除第一个,号否则后台解析失败 substring()方法
*/
上图中一共上传了9张图片,蓝色部分就是一至9张的叠加链接,一共花了9秒 当然这些图片都是很小的,如果是高清图 记着一定要压缩 否则会非常慢,因为流程非常多,容易卡死
Step3:进入主题
build.gradle 引入这些
//recyclerview 展示图片的 compile 'com.android.support:recyclerview-v7:25.3.1' //请求网络框架xutils compile 'org.xutils:xutils:3.3.36' //加载图片的glide compile 'com.github.bumptech.glide:glide:3.7.0' //图库选择器 compile 'me.iwf.photopicker:PhotoPicker:0.9.5@aar' //压缩图片的 compile 'com.zxy.android:tiny:0.0.6' //删除图片显示的snackbar compile 'com.android.support:design:26.0.0-alpha1
Step4:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest package="com.helloworld.base64demo" xmlns:android="http://schemas.android.com/apk/res/android"> <uses-permission android:name="android.permission.INTERNET" /> <application android:name=".AppContext" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <!-- photopicker图片选取界面 --> <activity android:name="me.iwf.photopicker.PhotoPickerActivity" android:theme="@style/Theme.AppCompat.NoActionBar" /> <!-- photopicker选取图片预览删除界面 --> <activity android:name="me.iwf.photopicker.PhotoPagerActivity" android:theme="@style/Theme.AppCompat.NoActionBar" /> </application></manifest>
Step5:4个java类
1.AppContext
2.MainActivity
3.PhotoAdapter
4.RecyclerItemClickListener
1.
package com.helloworld.base64demo;import android.app.Application;import com.zxy.tiny.Tiny;import org.xutils.x;public class AppContext extends Application { public static AppContext mInstace; @Override public void onCreate() { super.onCreate(); /** * 初始化第三方库 */ x.Ext.init(this); mInstace = this; /** * 压缩的 */ Tiny.getInstance().getApplication(); }}
2.
package com.helloworld.base64demo;import android.app.ProgressDialog;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.support.v7.widget.OrientationHelper;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.StaggeredGridLayoutManager;import android.util.Base64;import android.util.Log;import android.view.View;import android.widget.TextView;import android.widget.Toast;import com.zxy.tiny.Tiny;import com.zxy.tiny.callback.BitmapCallback;import org.json.JSONException;import org.json.JSONObject;import org.xutils.common.Callback;import org.xutils.http.RequestParams;import org.xutils.x;import java.io.ByteArrayOutputStream;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;import me.iwf.photopicker.PhotoPicker;import me.iwf.photopicker.PhotoPreview;public class MainActivity extends AppCompatActivity { private RecyclerView recyclerView; private PhotoAdapter photoAdapter; private ArrayList<String> selectedPhotos = new ArrayList<>(); //原生进度框 private ProgressDialog progressdialog; private static final String TAG = "ReleaseActivity"; /** * 图片路径 */ private List<String> photos; //发布标题、内容接口 (这里的链接换上自己服务器上的) private static final String URL = "http://110.110.110.10:8080/api/information/publicInformation"; //上传图片的接口 专门接受base64吗 private static final String URLIMAGE = "http://110.110.110.10:8080/api/information/uploadImage"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView) this.findViewById(R.id.recyclerView); progressdialog = new ProgressDialog(this); progressdialog.setMessage("正在上传,请稍后..."); //发布按钮事件 TextView release_submit = (TextView) this.findViewById(R.id.release_submit); release_submit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //点击后显示弹框 progressdialog.show(); UploadImageBase64(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss "); Date curDate = new Date(System.currentTimeMillis());//获取当前时间 String str = formatter.format(curDate); Log.e(TAG, "UploadImageBase6开始时间: " + str); } }); initview(); } private void initview() { photoAdapter = new PhotoAdapter(this, selectedPhotos); recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, OrientationHelper.VERTICAL)); recyclerView.setAdapter(photoAdapter); recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, new RecyclerItemClickListener .OnItemClickListener() { @Override public void onItemClick(View view, int position) { if (photoAdapter.getItemViewType(position) == PhotoAdapter.TYPE_ADD) { PhotoPicker.builder() .setPhotoCount(9) //可选择的图片数 .setShowCamera(true)//是否打开相机 .setPreviewEnabled(false) .setSelected(selectedPhotos)//选择过的图片出来在进入,默认打上勾 .start(MainActivity.this); } else { PhotoPreview.builder() .setPhotos(selectedPhotos) .setCurrentItem(position) .start(MainActivity.this); } } })); } /** * 选择了图片 */ private String str; private void UploadImageBase64() { //当number大于或等于图片组大小时结束,并return if (number >= photos.size()) { //代表图片上传完毕,开始发布 if (photos.size() > 1) { //图片大于1张时去除第一个, str = String.valueOf(sb).substring(1, sb.length()); } else { str = String.valueOf(sb); } //请求的链接、谁发布的(一般为uid)、发布的标题、发布的内容、最后拼接的图片链接 testUploadFile(URL, "1", "123", "456", str); //打印 最后拼接的图片链接 Log.e(TAG, "UploadImageBase64图片: " + str); return; } //随便找的压缩方法 可以自己写在工具类里 不建议用第三方的 Tiny.BitmapCompressOptions options = new Tiny.BitmapCompressOptions(); Tiny.getInstance().source(photos.get(number)).asBitmap().withOptions(options).compress(new BitmapCallback() { @Override public void callback(boolean isSuccess, Bitmap bitmap) { //A接口 请求专门上传图片的链接、每次转换时的base64字符串、 // 这里的2只是区别是头像上传还是朋友圈上传 可去除该参数 UploadFile(URLIMAGE, "1", encode(photos.get(number)), "2"); //打印 每张图片的base64码 Log.e(TAG, "callback: 压缩方法" + encode(photos.get(number))); } }); } /** * 方法1 */ private String encode(String path) { Bitmap bitmap = BitmapFactory.decodeFile(path); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); byte[] bytes = baos.toByteArray(); //这里有4种模式 defalut 是不连续的 me后台接不到 //NO_WRAP 是连续的 还有2种在这就不做解释了 byte[] encode = Base64.encode(bytes, Base64.NO_WRAP); String encodeString = new String(encode); return encodeString; } //msg 请求的结果 private String msg; /** * 图片上传 */ private void testUploadFile(String url, String userId, String title, String content, String icons) { //4个对应的参数 用户id、标题、内容、拼接的图片地址 RequestParams params = new RequestParams(url); params.addBodyParameter("userId", userId); params.addBodyParameter("title", title); params.addBodyParameter("content", content); params.addBodyParameter("icons", icons); x.http().post(params, new Callback.CacheCallback<String>() { @Override public void onSuccess(String result) { try { JSONObject object = new JSONObject(result); //返回状态 String status = object.optString("status"); //返回的消息 msg = object.optString("msg"); //成功关闭进度框 progressdialog.dismiss(); //200 说明成功 if (status.equals("200")) { Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show(); //记录从点击到结束的所花时间 (可删除) SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss "); Date curDate = new Date(System.currentTimeMillis());//获取当前时间 String str = formatter.format(curDate); Log.e(TAG, "UploadImageBase6结束时间: " + str); } } catch (JSONException e) { e.printStackTrace(); } } @Override public void onError(Throwable ex, boolean isOnCallback) { Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show(); //失败也要关闭对话框 progressdialog.dismiss(); Log.e(TAG, "onError: "); } @Override public void onCancelled(CancelledException cex) { Log.e(TAG, "onCancelled: "); } @Override public void onFinished() { Log.e(TAG, "onFinished456: " + msg); } @Override public boolean onCache(String result) { Log.e(TAG, "onCache: "); return false; } }); } /** * 图片上传 * 地址,图片集、图片名称、type(默认为2) */ private int number = 0; private String status, data; private StringBuffer sb = new StringBuffer(); private void UploadFile(String url, String userId, String icon, String type) { //专门接收base64 的接口 用户id、图片、type与上面一致 只是为了区别(可删除) RequestParams params = new RequestParams(url); params.addBodyParameter("userId", userId); params.addBodyParameter("icon", icon); params.addBodyParameter("type", type); x.http().post(params, new Callback.CacheCallback<String>() { @Override public void onSuccess(String result) { try { JSONObject object = new JSONObject(result); status = object.optString("status"); data = object.optString("data"); } catch (JSONException e) { e.printStackTrace(); } } @Override public void onError(Throwable ex, boolean isOnCallback) { Log.e(TAG, "onError: " + status); } @Override public void onCancelled(CancelledException cex) { Log.e(TAG, "onCancelled: "); } @Override public void onFinished() { //说明上传成功 if (status.equals("200")) { //当图片大于1张是,进行分隔 if (photos.size() > 1) { sb.append("," + data); } else { //等于一张时不用 sb.append(data); } //每上传完一张递增加1 number++; //在此调取上传图片接口 UploadImageBase64(); } Log.e(TAG, "onFinished: " + photos.size() + "\n" + sb); } @Override public boolean onCache(String result) { Log.e(TAG, "onCache: "); return false; } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && (requestCode == PhotoPicker.REQUEST_CODE || requestCode == PhotoPreview.REQUEST_CODE)) { photos = null; if (data != null) { //获取图片的list photos = data.getStringArrayListExtra(PhotoPicker.KEY_SELECTED_PHOTOS); } //清除list selectedPhotos.clear(); if (photos != null) { //添加至list中 selectedPhotos.addAll(photos); } //刷新适配器 photoAdapter.notifyDataSetChanged(); } }}
3.
package com.helloworld.base64demo;import android.content.Context;import android.net.Uri;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import com.bumptech.glide.Glide;import java.io.File;import java.util.ArrayList;import me.iwf.photopicker.utils.AndroidLifecycleUtils;public class PhotoAdapter extends RecyclerView.Adapter<PhotoAdapter.PhotoViewHolder> { private ArrayList<String> photoPaths = new ArrayList<String>(); private LayoutInflater inflater; private Context mContext; public final static int TYPE_ADD = 1; public final static int TYPE_PHOTO = 2; final static int MAX = 9; public PhotoAdapter(Context mContext, ArrayList<String> photoPaths) { this.photoPaths = photoPaths; this.mContext = mContext; inflater = LayoutInflater.from(mContext); } @Override public PhotoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = null; switch (viewType) { case TYPE_ADD: itemView = inflater.inflate(R.layout.item_add, parent, false); break; case TYPE_PHOTO: //包里面的 itemView = inflater.inflate(R.layout.__picker_item_photo, parent, false); break; } return new PhotoViewHolder(itemView); } @Override public void onBindViewHolder(final PhotoViewHolder holder, final int position) { if (getItemViewType(position) == TYPE_PHOTO) { Uri uri = Uri.fromFile(new File(photoPaths.get(position))); boolean canLoadImage = AndroidLifecycleUtils.canLoadImage(holder.ivPhoto.getContext()); if (canLoadImage) { Glide.with(mContext) .load(uri) .centerCrop() .thumbnail(0.1f) .placeholder(R.drawable.__picker_ic_photo_black_48dp) .error(R.drawable.__picker_ic_broken_image_black_48dp) .into(holder.ivPhoto); } } } @Override public int getItemCount() { int count = photoPaths.size() + 1; if (count > MAX) { count = MAX; } return count; } @Override public int getItemViewType(int position) { return (position == photoPaths.size() && position != MAX) ? TYPE_ADD : TYPE_PHOTO; } public static class PhotoViewHolder extends RecyclerView.ViewHolder { private ImageView ivPhoto; private View vSelected; public PhotoViewHolder(View itemView) { super(itemView); ivPhoto = (ImageView) itemView.findViewById(R.id.iv_photo); vSelected = itemView.findViewById(R.id.v_selected); if (vSelected != null) vSelected.setVisibility(View.GONE); } }}
4.
package com.helloworld.base64demo;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;/** * 点击事件 删除 */public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { private OnItemClickListener mListener; public interface OnItemClickListener { void onItemClick(View view, int position); } GestureDetector mGestureDetector; public RecyclerItemClickListener(Context context, OnItemClickListener listener) { mListener = listener; mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } }); } @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { View childView = view.findChildViewUnder(e.getX(), e.getY()); if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { mListener.onItemClick(childView, view.getChildLayoutPosition(childView)); return true; } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }}
step6: 2个布局
1.activity_main.xml
2.item_add.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.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#fff" android:paddingBottom="12dp" android:paddingLeft="6dp" android:paddingRight="6dp" android:paddingTop="12dp"/> <TextView android:id="@+id/release_submit" android:layout_width="match_parent" android:layout_height="40dp" android:layout_marginBottom="70dp" android:layout_marginLeft="22dp" android:layout_marginRight="22dp" android:layout_marginTop="70dp" android:background="#666" android:gravity="center" android:text="发布" android:textColor="#fff"/></LinearLayout>
2.
<?xml version="1.0" encoding="utf-8"?><me.iwf.photopicker.widget.SquareItemLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:background="@drawable/xinxi_tupian" android:layout_width="match_parent" android:layout_height="match_parent" /></me.iwf.photopicker.widget.SquareItemLayout>
Step7:结束
阅读全文
0 0
- 安卓Base64批量上传至服务器
- 安卓图片文字上传至服务器
- 安卓拍照 相册上传图片至服务器
- 安卓上传文件到服务器
- 安卓如何上传文件到服务器
- 安卓客户端上传图片到服务器
- 安卓上传服务器图片处理
- 批量上传SAP服务器文件至FTP服务器
- Android 通过Base64上传图片到服务器
- Android 通过Base64上传图片到服务器
- Android 通过Base64上传图片到服务器
- 图片压缩,Base64编码后上传服务器
- bimap转base64上传到服务器
- Android 通过Base64上传图片到服务器
- 使用Base64上传图片到服务器
- Android 通过Base64上传图片到服务器
- Android Base64上传图片到 SpringMVC服务器
- Android Base64上传图片到 SpringMVC服务器
- Anaconda安装模块
- 单个动画效果
- Requests库入门
- 二、文件I/O
- keyCode案例
- 安卓Base64批量上传至服务器
- 数据结构复习之–“插入排序”-JAVA实现
- 十四大师
- Shuffle an Array问题及解法
- 结构体 struct
- Python3:input()函数
- 欢迎使用CSDN-markdown编辑器
- 开户了哇
- RadioButton与自定义RadioButton