Common issues and solutions for OSS SDK for Android.
Before you use the sample code, you must install HTTPDNS SDK for Android. For more information, see Install HTTPDNS SDK for Android.
Does OSS SDK for Android support DNS pre-resolution and cache policies?
Yes. Use HTTPDNS SDK and OkHttp together to implement DNS pre-resolution and caching. For more information, see Best practices for using HTTPDNS and OkHttp on Android.
-
Implement the API for a custom DNS resolution service.
public class OkHttpDns implements Dns { private static final Dns SYSTEM = Dns.SYSTEM; HttpDnsService httpdns; private static OkHttpDns instance = null; private OkHttpDns(Context context) { this.httpdns = HttpDns.getService(context, "account id"); } public static OkHttpDns getInstance(Context context) { if(instance == null) { instance = new OkHttpDns(context); } return instance; } @Override public List<InetAddress> lookup(String hostname) throws UnknownHostException { // Use the asynchronous resolution API to get the IP address. String ip = httpdns.getIpByHostAsync(hostname); if(ip != null) { // IP address resolved — use it for the network request. List<InetAddress> inetAddresses = Arrays.asList(InetAddress.getAllByName(ip)); Log.e("OkHttpDns", "inetAddresses:" + inetAddresses); return inetAddresses; } // No IP address resolved — fall back to the system DNS service. return Dns.SYSTEM.lookup(hostname); } } -
Create an OkHttpClient instance and configure DNS pre-resolution and caching.
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com"; ClientConfiguration conf = new ClientConfiguration(); conf.setConnectionTimeout(15 * 1000); // Connection timeout. Default: 15 seconds. conf.setSocketTimeout(15 * 1000); // Socket timeout. Default: 15 seconds. conf.setMaxConcurrentRequest(5); // Maximum concurrent requests. Default: 5. conf.setMaxErrorRetry(2); // Maximum retries. Default: 2. OkHttpClient.Builder builder = new OkHttpClient.Builder() .dns(OkHttpDns.getInstance(getApplicationContext())); // If you set a custom OkHttpClient, it overrides some ClientConfiguration settings. // Set those settings directly on the builder. if (conf != null) { Dispatcher dispatcher = new Dispatcher(); dispatcher.setMaxRequests(conf.getMaxConcurrentRequest()); builder.connectTimeout(conf.getConnectionTimeout(), TimeUnit.MILLISECONDS) .readTimeout(conf.getSocketTimeout(), TimeUnit.MILLISECONDS) .writeTimeout(conf.getSocketTimeout(), TimeUnit.MILLISECONDS) .followRedirects(conf.isFollowRedirectsEnable()) .followSslRedirects(conf.isFollowRedirectsEnable()) .dispatcher(dispatcher); if (conf.getProxyHost() != null && conf.getProxyPort() != 0) { builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(conf.getProxyHost(), conf.getProxyPort()))); } } // Android SDK 2.9.12 and later support conf.setOkHttpClient(). conf.setOkHttpClient(builder.build()); OSS oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider, conf);
Why does the progress callback return totalSize=-1 when downloading objects?
Cause: When OkHttp downloads objects of certain content types (text/cache-manifest, text/xml, text/plain, text/css, application/javascript, application/x-javascript, application/rss+xml, application/json, text/json) that are 1 KB or larger, it automatically adds the Accept-Encoding: gzip header — even if you did not set it. OSS then returns the object in gzip format without a Content-Length header, which causes the progress callback to report totalSize=-1.
-
Fix: Set a Range header on the request. This prevents OkHttp from adding Accept-Encoding: gzip, so OSS returns Content-Length and the progress callback reports the correct size.
Map<String, String> header = new HashMap<>(); header.put("x-oss-range-behavior", "standard"); // Replace examplebucket with your bucket name and exampledir/exampleobject.txt with the full object path. GetObjectRequest get = new GetObjectRequest("examplebucket", "exampledir/exampleobject.txt"); get.setRange(new Range(0, -1)); get.setRequestHeaders(header); OSSAsyncTask task = oss.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>() { @Override public void onSuccess(GetObjectRequest request, GetObjectResult result) { InputStream inputStream = result.getObjectContent(); byte[] buffer = new byte[2048]; int len; try { while ((len = inputStream.read(buffer)) != -1) { // Process the downloaded data. } } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(GetObjectRequest request, ClientException clientExcepion, ServiceException serviceException) { if (clientExcepion != null) { // Handle a local exception, such as a network error. clientExcepion.printStackTrace(); } if (serviceException != null) { // Handle a service exception. Log.e("ErrorCode", serviceException.getErrorCode()); Log.e("RequestId", serviceException.getRequestId()); Log.e("HostId", serviceException.getHostId()); Log.e("RawMessage", serviceException.getRawMessage()); } } });
onFailure callback not triggered in Kotlin
Cause
This is a Kotlin nullability issue. The OSS Android SDK defines the onFailure callback using Java syntax, where parameters are non-nullable by default:
@Override
public void onFailure(GetObjectRequest request, ClientException clientException, ServiceException serviceException){
if (clientException != null) {
clientException.printStackTrace();
}
if (serviceException != null) {
Log.e("ErrorCode", serviceException.getErrorCode());
Log.e("RequestId", serviceException.getRequestId());
Log.e("HostId", serviceException.getHostId());
Log.e("RawMessage", serviceException.getRawMessage());
}
}
Kotlin treats these parameters as non-nullable, so the callback may not trigger as expected. Explicitly declare the parameters as nullable in the function signature:
onFailure(request: ResumableUploadRequest, clientException: ClientException?, serviceException: ServiceException?)