安卓Base64批量上傳至服務器

Step1:整體過程

/**
* 由於請求框架開始就是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:結束

發佈了43 篇原創文章 · 獲贊 62 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章