Skip to content

Commit ad43020

Browse files
committed
Merge pull request #34 from qiniu/develop
fix multi-part length
2 parents 46e6385 + df392df commit ad43020

20 files changed

+943
-183
lines changed

AndroidManifest.xml

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
android:versionName="1.0">
66
<uses-sdk android:minSdkVersion="9"/>
77
<uses-permission android:name="android.permission.INTERNET" />
8+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
89
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
910
<activity android:name=".demo.MyActivity"
1011
android:theme="@android:style/Theme.Light.NoTitleBar"
@@ -14,5 +15,10 @@
1415
<category android:name="android.intent.category.LAUNCHER"/>
1516
</intent-filter>
1617
</activity>
18+
<activity android:name=".demo.MyResumableActivity"
19+
android:theme="@android:style/Theme.Light.NoTitleBar"
20+
android:label="@string/app_name_resumable">
21+
22+
</activity>
1723
</application>
1824
</manifest>

docs/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
title: Android SDK 使用指南
33
---
44

5+
- Android SDK 下载地址:<https://github.com/qiniu/android-sdk/tags>
6+
- Android SDK 源码地址:<https://github.com/qiniu/android-sdk> (请注意非 master 分支的代码在规格上可能承受变更)
7+
58
此 Android SDK 基于 [七牛云存储官方API](http://docs.qiniu.com/api/index.html) 构建。在开发者的 Android App 工程项目中使用此 SDK 能够非常方便地将 Android 系统里边的文件快速直传到七牛云存储。
69

710
出于安全考虑,使用此 SDK 无需设置密钥(AccessKey / SecretKey)。所有涉及到授权的操作,比如生成上传授权凭证(uploadToken)或下载授权凭证(downloadToken)均在业务服务器端进行。

res/layout/main.xml

+6
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,11 @@
2727
android:id="@+id/textView1"
2828
android:layout_marginBottom="20dp"
2929
android:layout_centerHorizontal="true" android:layout_above="@+id/button1"/>
30+
<Button
31+
android:layout_width="wrap_content"
32+
android:layout_height="wrap_content"
33+
android:text="断点续上传"
34+
android:id="@+id/button"
35+
android:layout_alignParentRight="true" android:layout_alignParentBottom="true"/>
3036
</RelativeLayout>
3137

res/layout/resumable.xml

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:orientation="vertical"
4+
android:padding="8dp"
5+
android:layout_width="fill_parent"
6+
android:layout_height="fill_parent"
7+
>
8+
<Button
9+
android:layout_width="wrap_content"
10+
android:layout_height="wrap_content"
11+
android:text="选择文件并上传"
12+
android:id="@+id/button1"
13+
android:layout_alignParentRight="true" android:layout_alignParentBottom="true"/>
14+
<TextView
15+
android:layout_width="wrap_content"
16+
android:layout_height="wrap_content"
17+
android:layout_centerHorizontal="true"
18+
android:textSize="20sp"
19+
android:layout_marginTop="20dp"
20+
android:text="断点续上传"
21+
android:id="@+id/textView" android:layout_alignParentTop="true"
22+
/>
23+
<TextView
24+
android:layout_width="wrap_content"
25+
android:layout_height="wrap_content"
26+
android:text=""
27+
android:id="@+id/textView1"
28+
android:layout_marginBottom="20dp"
29+
android:layout_centerHorizontal="true" android:layout_above="@+id/button1"/>
30+
<ProgressBar
31+
android:layout_width="wrap_content"
32+
android:layout_height="wrap_content"
33+
android:layout_centerInParent="true"
34+
style="?android:attr/progressBarStyleHorizontal"
35+
android:id="@+id/progressBar"
36+
android:layout_centerVertical="true" android:indeterminate="false"
37+
android:layout_alignRight="@+id/button1" android:layout_alignParentLeft="true"/>
38+
<Button
39+
android:layout_width="wrap_content"
40+
android:layout_height="wrap_content"
41+
android:text="暂停"
42+
android:id="@+id/button2" android:layout_toLeftOf="@+id/button1" android:layout_alignTop="@+id/button1"/>
43+
<TextView
44+
android:layout_width="wrap_content"
45+
android:layout_height="wrap_content"
46+
android:text="New Text"
47+
android:id="@+id/textView2" android:layout_alignLeft="@+id/progressBar"
48+
android:layout_above="@+id/progressBar"/>
49+
</RelativeLayout>
50+

res/values/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
33
<string name="app_name">android-sdk</string>
4+
<string name="app_name_resumable">android-sdk-resumable</string>
45
</resources>

src/com/qiniu/auth/CallRet.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package com.qiniu.auth;
22

3-
public abstract class CallRet {
3+
import com.qiniu.utils.IOnProcess;
4+
5+
public abstract class CallRet implements IOnProcess {
6+
public void onInit(int flag){}
47
public abstract void onSuccess(byte[] body);
58
public abstract void onFailure(Exception ex);
6-
public void onSuccess(){}
7-
}
9+
public void onProcess(long current, long total){}
10+
public void onPause(Object tag){}
11+
}

src/com/qiniu/auth/Client.java

+72-48
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22

33
import android.os.AsyncTask;
44
import com.qiniu.conf.Conf;
5+
import com.qiniu.utils.ICancel;
6+
import org.apache.http.Header;
57
import org.apache.http.HttpEntity;
68
import org.apache.http.HttpResponse;
79
import org.apache.http.client.HttpClient;
10+
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
11+
import org.apache.http.client.methods.HttpGet;
812
import org.apache.http.client.methods.HttpPost;
13+
import org.apache.http.client.methods.HttpRequestBase;
914
import org.apache.http.conn.ClientConnectionManager;
1015
import org.apache.http.conn.scheme.PlainSocketFactory;
1116
import org.apache.http.conn.scheme.Scheme;
@@ -19,86 +24,106 @@
1924
import java.io.IOException;
2025

2126
public class Client {
22-
27+
2328
protected HttpClient mClient;
24-
29+
2530
public Client(HttpClient client) {
2631
mClient = client;
2732
}
2833

29-
public void call(String url, CallRet ret) {
30-
HttpPost httppost = new HttpPost(url);
31-
execute(httppost, ret);
34+
public static ClientExecutor get(String url, CallRet ret) {
35+
Client client = Client.defaultClient();
36+
return client.get(client.makeClientExecutor(), url, ret);
3237
}
3338

34-
public void call(String url, HttpEntity entity, CallRet ret) {
35-
call(url, entity.getContentType().getValue(), entity, ret);
39+
public ClientExecutor call(ClientExecutor client, String url, HttpEntity entity, CallRet ret) {
40+
Header header = entity.getContentType();
41+
String contentType = "application/octet-stream";
42+
if (header != null) {
43+
contentType = header.getValue();
44+
}
45+
return call(client, url, contentType, entity, ret);
3646
}
3747

38-
public void call(String url, String contentType, HttpEntity entity, CallRet ret) {
48+
public ClientExecutor call(ClientExecutor client, String url, String contentType, HttpEntity entity, CallRet ret) {
3949
HttpPost httppost = new HttpPost(url);
4050
httppost.setEntity(entity);
4151

4252
if (contentType != null) {
4353
httppost.setHeader("Content-Type", contentType);
4454
}
45-
execute(httppost, ret);
55+
return execute(client, httppost, ret);
56+
}
57+
58+
public ClientExecutor get(ClientExecutor client, String url, CallRet ret) {
59+
return execute(client, new HttpGet(url), ret);
4660
}
4761

48-
protected void execute(HttpPost httpPost, CallRet ret) {
49-
new ClientExecuter().execute(httpPost, ret);
62+
public ClientExecutor makeClientExecutor() {
63+
return new ClientExecutor();
5064
}
5165

52-
protected HttpResponse roundtrip(HttpPost httpPost) throws IOException {
53-
httpPost.setHeader("User-Agent", Conf.USER_AGENT);
54-
return mClient.execute(httpPost);
66+
protected ClientExecutor execute(ClientExecutor client, HttpRequestBase httpRequest, final CallRet ret) {
67+
client.setup(httpRequest, ret);
68+
client.execute();
69+
return client;
70+
}
71+
72+
protected HttpResponse roundtrip(HttpRequestBase httpRequest) throws IOException {
73+
httpRequest.setHeader("User-Agent", Conf.USER_AGENT);
74+
return mClient.execute(httpRequest);
5575
}
5676

57-
class ClientExecuter extends AsyncTask<Object, Object, Object> {
58-
HttpPost httpPost;
59-
CallRet ret;
77+
public class ClientExecutor extends AsyncTask<Object, Object, Object> implements ICancel {
78+
HttpRequestBase mHttpRequest;
79+
CallRet mRet;
80+
public void setup(HttpRequestBase httpRequest, CallRet ret) {
81+
mHttpRequest = httpRequest;
82+
mRet = ret;
83+
}
84+
public void upload(long current, long total) {
85+
publishProgress(current, total);
86+
}
6087

6188
@Override
6289
protected Object doInBackground(Object... objects) {
63-
httpPost = (HttpPost) objects[0];
64-
ret = (CallRet) objects[1];
65-
String errMsg = "";
66-
67-
HttpResponse resp;
6890
try {
69-
resp = roundtrip(httpPost);
91+
HttpResponse resp = roundtrip(mHttpRequest);
92+
int statusCode = resp.getStatusLine().getStatusCode();
93+
if (statusCode == 401) { // android 2.3 will not response
94+
return new Exception("unauthorized!");
95+
}
96+
byte[] data = EntityUtils.toByteArray(resp.getEntity());
97+
98+
if (statusCode / 100 != 2) {
99+
if (data.length == 0) {
100+
String xlog = resp.getFirstHeader("X-Log").getValue();
101+
if (xlog.length() > 0) {
102+
return new Exception(xlog);
103+
}
104+
return new Exception(resp.getStatusLine().getReasonPhrase());
105+
}
106+
return new Exception(new String(data));
107+
}
108+
return data;
70109
} catch (IOException e) {
71110
e.printStackTrace();
72111
return e;
73112
}
113+
}
74114

75-
if (resp.getHeaders("X-Log").length > 0) {
76-
errMsg = resp.getHeaders("X-Log")[0].getValue();
77-
}
78-
79-
int statusCode = resp.getStatusLine().getStatusCode();
80-
81-
if (statusCode / 100 != 2) {
82-
return new Exception(errMsg);
83-
}
84-
85-
byte[] data = new byte[0];
86-
try {
87-
data = EntityUtils.toByteArray(resp.getEntity());
88-
} catch (IOException e) {
89-
e.printStackTrace();
90-
}
91-
92-
return data;
115+
@Override
116+
protected void onProgressUpdate(Object... values) {
117+
mRet.onProcess((Long) values[0], (Long) values[1]);
93118
}
94119

95120
@Override
96121
protected void onPostExecute(Object o) {
97122
if (o instanceof Exception) {
98-
ret.onFailure((Exception) o);
123+
mRet.onFailure((Exception) o);
99124
return;
100125
}
101-
ret.onSuccess((byte[]) o);
126+
mRet.onSuccess((byte[]) o);
102127
}
103128
};
104129

@@ -107,11 +132,10 @@ public static Client defaultClient() {
107132
}
108133

109134
public static HttpClient getMultithreadClient() {
110-
HttpParams params = new BasicHttpParams();
111-
SchemeRegistry registry = new SchemeRegistry();
112-
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
113-
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, registry);
114-
HttpClient client = new DefaultHttpClient(cm, params);
135+
HttpClient client = new DefaultHttpClient();
136+
ClientConnectionManager mgr = client.getConnectionManager();
137+
HttpParams params = client.getParams();
138+
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()), params);
115139
return client;
116140
}
117141
}

src/com/qiniu/auth/JSONObjectRet.java

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import org.json.JSONObject;
55

66
public abstract class JSONObjectRet extends CallRet {
7+
public JSONObjectRet(){}
8+
protected int mIdx;
9+
public JSONObjectRet(int idx) { mIdx = idx; }
710
@Override
811
public void onSuccess(byte[] body) {
912
if (body == null) {
@@ -13,6 +16,7 @@ public void onSuccess(byte[] body) {
1316
JSONObject obj = new JSONObject(new String(body));
1417
onSuccess(obj);
1518
} catch (JSONException e) {
19+
e.printStackTrace();
1620
onFailure(new Exception(new String(body)));
1721
}
1822
}

src/com/qiniu/auth/UpClient.java

-32
This file was deleted.

0 commit comments

Comments
 (0)