In my app I have a facility to download reference data updates. The user can modify base url in a PreferenceActivity - and then I append the actual file name to the base URL. When I attempt to download the file, an exception may be thrown if something went wrong. I'd like to present the user with the most appropriate error message rather than simply "error occurred". To do this, I want to catch individual exception and format messages accordingly. So, what exceptions can be thrown when downloading a file? For the reference, here's my downloading code (simplified):
int msgId;
try {
String url = props.getProperty(Constants.SETTINGS_REFDATA_SOURCE);
if(!url.endsWith("/")) {
url += "/";
}
url += Constants.UPDATE_CUSTOMER_FILE;
CSVReader in = new CSVReader(new InputStreamReader(url.openStream()));
...//read and parse file here
}
catch(MalformedURLException e) {
msgId = R.string.error_invalid_base_url;
}
catch(UnknownHostException e) {
msgId = R.string.error_unknown_host;
}
catch(FileNotFoundException e) {
msgId = R.string.error_file_not_found;
}
catch(IOException e) {
msgId = R.string.error_reading_data;
}
catch(MyParseException e) {
msgId = R.string.error_invalid_file_format;
}
catch(Exception e) {
msgId = R.string.error_other_error;
}
finally {
try { in.close(); } catch(Exception e2) {}
}
// then I display AlertDialog using msgId as the message
As you can see, I'm already catching several exception - some that I know can be thrown, some that I encountered in testing. What other exceptions do I need to cater for? Note that the amount of data being download is quite small (at most 15-20 Kb) so things like OutOfMemoryError shouldn't be applicable.
There is the ConnectException due to connection timeout or connection refused (HTTP 403)
//edit: I just read, that "Most applications should not catch the ConnectException; it is more robust to catch the superclass SocketException."
Furthermore you could test if there is an active Internet connection:
private boolean checkCon() {
ConnectivityManager conMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
if ( conMgr.getNetworkInfo(0).getState() == NetworkInfo.State.DISCONNECTED
&& conMgr.getNetworkInfo(1).getState() == NetworkInfo.State.DISCONNECTED) {
return false;
}
return true;
}
Related
I'm using Retrofit with okHTTP cache for my network Calls, when i received a response i have written an interceptor to look for response body "timeToCache" value and re-write the cache header. I'm facing an issue now when I updated an enitity and call the get method it's always return me the cache response. to avoid that I added the below header to request
#GET("ws/something")
Something getSomething(#Header("Cache-Control") String cacheControl);
and then when calling you either supply null for a (maybe-)cached version or "no-cache" for a live version:
myApi.getSomething(forceRefresh ? "no-cache" : null);
now I'm getting the new response but this response not get cache? how can i save this response to cache now?
I couldn't find a better way to solve this so i implmented remove cache entry method to remove the entry after the success of the update event.
public void removeHTTPCacheEntry(final String cachedDelURL) {
try {
if (client != null && client.cache() != null && client.cache().urls() != null) {
Iterator<String> cacheURlsItr = client.cache().urls();
while (cacheURlsItr.hasNext()) {
try {
URL cachedURL = new URL(cacheURlsItr.next());
String urlPath = cachedURL == null ? "" : cachedURL.getPath();
if (!StringUtils.isEmpty(urlPath) && cachedDelURL.equals(urlPath)) {
cacheURlsItr.remove();
break;
}
} catch (MalformedURLException e1) {
Log.e(TAG, "MalformedURLException", e1);
}
}
}
} catch (IOException e1) {
Log.e(TAG, "removeHTTPCacheEntry", e1);
}
}
Does anyone know if BT_MULTI works on Zebra? I'm using ZebraConnection class in my android application and connection with BT:printerAddress as parameter works but with BT_MULTI:printerAddress throws "Invalid connection type".
I'm trying to use BT_MULTI to connect multiple printers in one time, but if you have other ideas of how I can do that I'll be happy to hear them.
This is the code that throws the exception:
Connection connection;
try {
connection= ConnectionBuilder.build(getConnectionStringForSdk(printerBTAddress));
connection.open();
ZebraPrinter printerdemo = ZebraPrinterFactory.getInstance(connection);
} catch (ConnectionException e) {
System.out.println("Connection could not be opened"+e);
} catch (ZebraPrinterLanguageUnknownException e) {
System.out.println("Unable to create printer"+e);
}
private String getConnectionStringForSdk(String btAddress) {
String selectedPrefix="BT_MULTI:";
final String finalConnectionString = selectedPrefix + btAddress;
return finalConnectionString;
}
I've been working with Azure on the Android OS and I managed to upload my video file (.mp4) to a Container I had already prepared for it.
I did this by getting a Shared Access Signature (SAS) first, which provided me with:
a temporary key
the name of the container to where I want to send the files
the server URI
Then, I started an AsyncTask to send the file to the container using the "upload".
I checked the container, and the file gets uploaded perfectly, no problems on that end.
My question is regarding the progress of the upload. Is it possible to track it? I would like to have an upload bar to give a better UX.
P.S - I'm using the Azure Mobile SDK
Here's my code:
private void uploadFile(String filename){
mFileTransferInProgress = true;
try {
Log.d("Funky Stuff", "Blob Azure Config");
final String gFilename = filename;
File file = new File(filename); // File path
String blobUri = blobServerURL + sharedAccessSignature.replaceAll("\"", "");
StorageUri storage = new StorageUri(URI.create(blobUri));
CloudBlobClient blobCLient = new CloudBlobClient(storage);
//Container name here
CloudBlobContainer container = blobCLient.getContainerReference(blobContainer);
blob = container.getBlockBlobReference(file.getName());
//fileToByteConverter is a method to convert files to a byte[]
byte[] buffer = fileToByteConverter(file);
ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer);
if (blob != null) {
new UploadFileToAzure().execute(inputStream);
}
} catch (StorageException e) {
Log.d("Funky Stuff", "StorageException: " + e.toString());
e.printStackTrace();
} catch (IOException e) {
Log.d("Funky Stuff", "IOException: " + e.toString());
e.printStackTrace();
} catch (Exception e) {
Log.d("Funky Stuff", "Exception: " + e.toString());
e.printStackTrace();
}
mFileTransferInProgress = false;
//TODO: Missing ProgressChanged method from AWS
}
private class UploadFileToAzure extends
AsyncTask <ByteArrayInputStream, Void, Void>
{
#Override
protected Void doInBackground(ByteArrayInputStream... params) {
try {
Log.d("Funky Stuff", "Entered UploadFileToAzure Async" + uploadEvent.mFilename);
//Method to upload, takes an InputStream and a size
blob.upload(params[0], params[0].available());
params[0].close();
} catch (StorageException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Thanks!
You can split your file and send its part using Block, there is a good example of your case in this link but it used C# so you should find the corresponding function in the android library reference.
Basically instead of sending you file as one big file, you split it to multiple files (bytes) and send it to azure so you can track the progress on how many bytes that already sent to azure
Having some issues with a custom class that extends AsyncTask. My app is Targeting Android 4.0.3 and the below code works fine for 30+ people testing it. However there are two users that are seeing the app crash when I call new AsyncRequest like below.
I've got a working logger that is recording to a text file on the users storage and doesn't record the entry that is in the AsyncRequest constructor. So I have to assume that the crash is happening before the constructor is called.
One of the two devices that are experiencing this crash is running Android 4.0.4 apparently. Not sure what the other device is running. Unfortunately I dont' have access to the two devices so can't see a logcat output.
Any input as to why the object creation is causing a crash would be greatly appreciated.
String url = "www.google.com";
new AsyncRequest(callback, context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
And here is the full AsyncRequest class
public class AsyncRequest extends AsyncTask<String, String, String>{
HttpURLConnection connection;
InputStream inStream;
IApiCallback callback;
Context context_;
public AsyncRequest(IApiCallback callback, Context context) {
// Log entry added for testing. Never gets called.
FileLogger.getFileLogger(context).ReportInfo("Enter AsyncRequest Constructor");
this.callback = callback;
context_ = context;
}
#Override
protected String doInBackground(String... uri) {
try {
URL url = new URL(uri[0] + "?format=json");
FileLogger.getFileLogger(context_).ReportInfo("Async Request: Sending HTTP GET to " + url);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
connection.addRequestProperty("Accept-Encoding", "gzip");
connection.addRequestProperty("Cache-Control", "no-cache");
connection.connect();
String encoding = connection.getContentEncoding();
// Determine if the stream is compressed and uncompress it if needed.
if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
inStream = new GZIPInputStream(connection.getInputStream());
} else {
inStream = connection.getInputStream();
}
if (inStream != null) {
// process response
BufferedReader br = new BufferedReader(new InputStreamReader(inStream));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
} catch (SocketTimeoutException e) {
FileLogger.getFileLogger(context_).ReportException("Async Request: SocketTimeoutException", e);
Log.i("AsyncRequest", "Socket Timeout occured");
} catch (MalformedURLException e) {
FileLogger.getFileLogger(context_).ReportException("Async Request: MalformedUrlException", e);
} catch (IOException e) {
FileLogger.getFileLogger(context_).ReportException("Async Request: IOException", e);
Log.i("doInBackground:","IOException");
if (e != null && e.getMessage() != null) {
Log.i("doInBackground:",e.getMessage());
}
} catch (Exception e) {
FileLogger.getFileLogger(context_).ReportException("Async Request: Exception", e);
} finally {
if (connection != null)
connection.disconnect();
}
return null;
}
#Override
protected void onPostExecute(String result) {
if (result != null)
FileLogger.getFileLogger(context_).ReportInfo("Async Request: Response is valid");
else
FileLogger.getFileLogger(context_).ReportInfo("Async Request: Invalid response");
callback.Execute(result);
}
}
EDIT: As per comments below.
Here is the full method that I call my custom AsyncTask from. All the logging messages I have up to creating the AsyncTask are showing in the log. None of the exceptions are.
The logging displays the url value just before creating my AsyncRequest and the URL is not malformed at all. It's what I'm expecting.
public void GetServerInfoAsync(IApiCallback callback, Context context) throws IllegalArgumentException, Exception {
if (callback == null)
throw new IllegalArgumentException("callback");
if (context == null)
throw new IllegalArgumentException("context");
try {
FileLogger.getFileLogger(context).ReportInfo("Build URL");
String url = GetApiUrl("System/Info");
FileLogger.getFileLogger(context).ReportInfo("Finished building URL");
if (url != null) {
FileLogger.getFileLogger(context).ReportInfo("GetServerInfoAsync: url is " + url);
new AsyncRequest(callback, context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
} else {
FileLogger.getFileLogger(context).ReportError("GetServerInfoAsync: url is null");
}
} catch (IllegalArgumentException iae) {
FileLogger.getFileLogger(context).ReportException("GetServerInfoAsync: IllegalArgumentException", iae);
throw iae;
} catch (Exception e) {
FileLogger.getFileLogger(context).ReportException("GetServerInfoAsync: Exception", e);
throw e;
}
}
First of all, just keep in mind that executeOnExecutor() is not available prior to Api 11. You have already said the issue is with a 4.0.4 device, but just keep this in mind.
Here are the steps I would take in order to troubleshoot what the problem is. It seems as if you have already done a few of these with all those ReportInfo() statements.
First, I assume your call to GetServerInfoAsync is within a try...catch, correct? I am checking because of your use of Throw. Also, you have already added logging to check for errors with the url. Since the errors occur before you actually use it, the error cannot be with the url, or any internet permissions.
You call the AsyncTask generation with references to callback and context. You have added logging via ReportInfo() which references context, and those work, yes? Therefore, context is not your issue. However, you never check what callback is. You throw an error if it is null, but you never do anything with it before you call AsyncRequest. Try a ReportInfo(callback.toString()) to see what it is.
If all else fails, it would seem to be an error with threading. Why not try using just AsyncTask, instead of executeOnExecutor(). Do you really need more than 1 background thread?
Sorry for not getting back to this sooner. There were numerous issues here.
First off... Thanks to Wolfram's suggestion I was able to catch the exception and diagnose that the issue was that my FileLogger (and another class) was a static reference and these two tablets couldn't find the reference at runtime. So I ended up removing Logging from my async methods.
Secondly, after making the above changes there was another issue which was that a looper had to be called from the main thread. It turned out that these two tablets weren't calling my async task from the main thread. So I had to enclose the async call in a new Handler using the MainLooper.
This is a follow-up of this question. I have written my data file on Drive application folder, now the same app that created these files needs to retrieve them.
This doesn't work (I get the listing of the file, but the request of file download return with a 401 error):
private ArrayList<File> listFilesInApplicationDataFolder(Drive service) throws IOException {
ArrayList<File> result = new ArrayList<File>();
Files.List request = service.files().list();
request.setQ("'appdata' in parents");
do {
try {
FileList files = request.execute();
result.addAll(files.getItems());
request.setPageToken(files.getNextPageToken());
} catch (IOException e) {
System.out.println("An error occurred: " + e);
request.setPageToken(null);
}
} while (request.getPageToken() != null &&
request.getPageToken().length() > 0);
for (File file:result){
System.out.println("##### "+file.getOriginalFilename()+ " "+file.toPrettyString());
if (file.getDownloadUrl() != null && file.getDownloadUrl().length() > 0) {
try {
HttpResponse resp =
service.getRequestFactory().buildGetRequest(new GenericUrl(file.getDownloadUrl()))
.execute();
InputStream in= resp.getContent();
FileOutputStream fos = openFileOutput("pinmemo",
Context.MODE_PRIVATE);
while(in.available()>0)
fos.write(in.read());
fos.close();
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
return null;
} catch (IOException e) {
// An error occurred.
e.printStackTrace();
return null;
}
} else {
// The file doesn't have any content stored on Drive.
return null;
}
}
return result;
}
What should I do?
EDIT:
I get this error message:
04-17 11:19:30.614: W/System.err(2022): com.google.api.client.http.HttpResponseException: 401 Unauthorized
04-17 11:19:30.614: W/System.err(2022): at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1095)
EDIT: the new Google play games services basically covers my needs (the only problem is that my app isn't a game...), therefore this question is now partially obsolete. Of course, Google play games uses "Cloud save" instead of "drive", but for my needs that's sufficent. However, should I use Google play games for non-gaming app?
Make sure that your access token has permissions for the appdata scope:
https://www.googleapis.com/auth/drive.appdata