1.先列出Android端使用的library:
dependencies {
...
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.1.0'
compile 'com.jakewharton:butterknife:7.0.1'
compile 'com.squareup:otto:1.3.5'
compile 'cn.finalteam:galleryfinal:1.4.8.4'
compile 'com.github.bumptech.glide:glide:3.6.1'
compile 'com.jcodecraeer:xrecyclerview:1.2.6'
compile 'com.baoyz.actionsheet:library:1.1.5'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
compile 'org.xutils:xutils:3.1.22'
compile 'io.reactivex:rxjava:1.0.6'
compile 'io.reactivex:rxandroid:0.23.0'
compile files('libs/fastjson-1.2.7.jar')
compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.2.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
...
}
Android端代码:
public interface ApiService {
/**上传单张及多张图片与文本*/
@Multipart
@POST("/PHP/uploads.php")
Observable<Message> updateImages(@PartMap() Map<String, RequestBody> maps);
/**上传单张及多张图片与文本*/
@Multipart
@POST("/PHP/uploads.php")
Observable<Message> updateImages(@Part("filename") String description, @PartMap() Map<String, RequestBody> maps);
/**上传单张及多张图片与文本*/
@Multipart
@POST("/PHP/uploads.php")
Observable<Message> updateImages2(@Part MultipartBody.Part[] parts);
/**上传单张及多张图片与文本*/
@Multipart
@POST("/PHP/uploads.php")
Observable<Message> updateImages2(@Part("description") RequestBody description, @Part("key") String value ,@Part MultipartBody.Part[] parts);
/**上传单张图片*/
@Multipart
@POST("/PHP/uploads.php")
Observable<Message> updateImage(
@QueryMap Map<String, String> usermaps,
@Part("avatar\"; filename=\"avatar.jpg") RequestBody avatar);
public class Client {
public static String API_URL = Constant.API_URL;
public static ExecutorService mExecutorService;
private static ApiService instance;
public static ApiService getServiceClient() {
if (instance == null) {
synchronized (Client.class) {
okhttp3.OkHttpClient okHttpClient = new okhttp3.OkHttpClient.Builder()
// .addNetworkInterceptor(
// new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
// .cookieJar(new NovateCookieManger(context))
// .cache(cache)
.addInterceptor(new ApiHeaders())
// .addInterceptor(new CaheInterceptor(context))
// .addNetworkInterceptor(new CaheInterceptor(context))
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(8, 15, TimeUnit.SECONDS))
// 这里你可以根据自己的机型设置同时连接的个数和时间,我这里8个,和每个保持时间为10s
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(API_URL)
.build();
mExecutorService = Executors.newCachedThreadPool();
instance = retrofit.create(ApiService.class);
}
}
}
return instance;
}
public static void stopAll() {
List<Runnable> pendingAndOngoing = mExecutorService.shutdownNow();
}
static class ApiHeaders implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
builder.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
.addHeader("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; HTC One X - 4.1.1 - API 16 - 720x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30")
.addHeader("Accept-Encoding", "gzip")
.addHeader("Accept", "*/*")
.addHeader("Accept-Language", "zh-cn,zh")
.addHeader("Authorization", "");
Request newRequest = builder.build();
return chain.proceed(newRequest);
}
}
上传关键代码:
public void uploadFiles(List<String> paths) {
// retrofit1 的上传
// MultipartTypedOutput multipartTypedOutput = new MultipartTypedOutput();
// for (String imgPath : paths){
// multipartTypedOutput.addPart("uploadfile[]", new TypedFile("image/*", new File(imgPath)));
// }
// mApi.uploadFiles(multipartTypedOutput)
// .subscribeOn(Schedulers.computation())
// .subscribe(response -> handleUploadFile(response), error -> handleFailure(error));
if (true) { //retrofit2第一种@PartMap() Map<String, RequestBody>方式上传多张图片
HashMap<String, RequestBody> map = new HashMap<>();
MultipartBody.Part[] parts = new MultipartBody.Part[paths.size()];
for (String imgPath : paths) {
final File file = new File(imgPath);
map.put("uploadfile[]\"; filename=\"" + file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
}
// create a map of data to pass along
RequestBody tokenBody = RequestBody.create(
MediaType.parse("multipart/form-data"), "xxxx");
map.put("token", tokenBody);
//实测,zyp传过去的值有引号"zyp",所以要用body传值
// mApi.updateImages(map)
mApi.updateImages("zyp",map)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> handleUploadFile(response), error -> handleFailure(error));
} else {//第二种MultipartBody.Part[]方式上传多张图片
MultipartBody.Part[] parts = new MultipartBody.Part[paths.size()];
int cnt = 0;
for (String imgPath : paths) {
final File file = new File(imgPath);
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("uploadfile[]", file.getName(), requestFile);
parts[cnt] = filePart;
cnt++;
}
// create a map of data to pass along
RequestBody body = RequestBody.create(
MediaType.parse("multipart/form-data"), "xxxx");
// mApi.updateImages2(parts)
//实测,value传过去的值有引号"value",所以要用body传值
mApi.updateImages2(body,"value", parts)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> handleUploadFile(response), error -> handleFailure(error));
}
// //okhttp上传图片
// RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
// .addFormDataPart("name", "zyp")
// .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file))
// .build();
}
private void handleUploadFile(Message message) {
//otto事件传递
mBus.post(message);
}
//接收事件代码
@Subscribe //需要注解@Subscribe ,表明在这个函数接收数据
public void uploadFileResponse(Message msg) {
Log.i("@@@","uploadFileResponse: "+msg.getMessage());
Toast.makeText(this, msg.getMessage(), Toast.LENGTH_SHORT).show();
List<String> imgUrls = msg.getImgUrls();
if (msg.getCode() == 1) {
if (choosePhotoListAdapter == null) {
choosePhotoListAdapter = new ChoosePhotoListAdapter(this, null, imgUrls);
lvPhotoShow.setAdapter(choosePhotoListAdapter);
}
choosePhotoListAdapter.notifyDataSetChanged();
}
}
Php端代码:
//初学php,写的比较简单,不太健壮,像图片是否已经上传过,都没有判断,大家自己补充啊^_^
<?php
/**
* Created by PhpStorm.
* User: zhangyipeng
* Date: 16/2/18
* Time: 下午3:48
*/
$base_path = "./upload_file/"; //接收文件目录
$imgs = array(); //定义一个数组存放上传图片的路径
$isSave = false;
if (!file_exists($base_path)) {
mkdir($base_path);
}
foreach ($_FILES["uploadfile"]["error"] as $key => $error) {
if ($error == UPLOAD_ERR_OK) {
$tmp_name = $_FILES["uploadfile"]["tmp_name"][$key];
$name = $_FILES["uploadfile"]["name"][$key];
$uploadfile = $base_path . $name;
$isSave = move_uploaded_file($tmp_name, $uploadfile);
if ($isSave){
$imgs[]=$uploadfile;
}
}
}
if ($isSave) {
$array = array("code" => "1", "message" =>"上传图片成功"
, "imgUrls" => $imgs);
echo json_encode($array);
} else {
$array = array("code" => "0", "message" => "上传图片失败," . $_FILES ['uploadfile'] ['error']
, "imgUrls" => $imgs);
echo json_encode($array);
}
其实上传多张图片成功的关键是key(uploadfile)需要带[],即uploadfile[] 。
map.put("uploadfile[]\"; filename=\"" + file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
//下面的这种上传方式其实内部也是拼接成了"uploadfile[]\"; filename=\"" + file.getName()这个字符串
MultipartBody.Part filePart = MultipartBody.Part.createFormData("uploadfile[]", file.getName(), requestFile);
Paste_Image.png Paste_Image.png Paste_Image.png Paste_Image.png
补充:�PHP环境使用的是MAMP,默认文件所在目录如下,想要测试的可以看看,这里我使用了ln命令的软链接,指向到上图中得目录了,这样就不必把PHP代码放到下图目录下了,指向下就可以了,方便很多。本人对PHP了解不多,就这点小技巧,希望能帮到Android的同学。
php.png1.超级简单的Android Studio jni 实现(无需命令行)
2.让Android开发者相见恨晚的软件及插件
3.GitHub上一些超炫的Android开源项目推荐
网友评论