I meet a problem when download apk with HttpUrlConnection.
I develop a app about 30Mb, and I create a manager to check the latest version and download it.
Because of its size, I checked the downloaded file size and resume downloading if connection was cutted off or app was shutdown by system.
The problem is that a parse error happened when install downloading apk if the whole downloading process was interrupted once.
This is the error message:
Parse error: There was a problem parsing the package.
And here is my code of downloading:
private File downloadApk(File aApkFile, String aUrl, long aStartPosition, long aEndPosition) {
try {
URL url = new URL(aUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setReadTimeout(5 * 1000);
conn.setRequestMethod("GET");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Range", StringFormatter.format("bytes=%s-", aStartPosition));
conn.connect();
sendUpdateNotification(0, 100); // update notifaction info
InputStream inputStream = conn.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(aApkFile);
int currentPercent = 0;
long currentDownloadSize = aStartPosition;
byte readBuffer[] = new byte[1024 * 10];
int byteReadSize = 0;
while (!((byteReadSize = inputStream.read(readBuffer)) <= 0)) {
fileOutputStream.write(readBuffer, 0, byteReadSize);
currentDownloadSize += byteReadSize;
int index = (int) (currentDownloadSize * 100 / aEndPosition);
if (index != currentPercent) {
currentPercent = index;
sendUpdateNotification(currentPercent, 100);
}
}
fileOutputStream.close();
inputStream.close();
conn.disconnect();
return aApkFile;
} catch (MalformedURLException aE) {
aE.printStackTrace();
Log.e("Version", aE.getMessage());
} catch (IOException aE) {
aE.printStackTrace();
Log.e("Version", aE.getMessage());
}
return null;
}
ApkFile is the downloaded file which will not be null here.
StartPosition is the apkfile's size, and get by apkFile.length().
Endposition is the whole size of apk and get by conn.getContentLength().
Is there any ideas to fix it? Thanks.
You are deleting a former partial file with:
FileOutputStream fileOutputStream = new FileOutputStream(aApkFile);
Change to appending mode:
FileOutputStream fileOutputStream = new FileOutputStream(aApkFile, true);
Check file size of original and downloaded file. Every byte counts!
Related
Got an weird issue. A file with Url: https://s3.amazonaws.com/myappdata/msg/171401089927.mp3 (not available any more) downloads ok on PC and its mp3 file. But when I try to DL it on Android FOA Im getting content-type "application/xml" instead of "audio/mpeg" and when downloading starts I'm getting:
05-30 12:13:44.478: E/PlayerService(28023): java.io.FileNotFoundException: https://s3.amazonaws.com/myappdata/msg/171401089927.mp3
05-30 12:13:44.478: E/PlayerService(28023): at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
05-30 12:13:44.478: E/PlayerService(28023): at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:270)
The code used to DL:
/**
* Download the url stream to a temporary location
*/
public void downloadAudioIncrement(String mediaUrl) throws IOException {
Log.i(TAG, "downloadAudioIncrement(): mediaUrl: "+mediaUrl+"\ncacheDir: "+cacheDir);
URL url = null;
try {
url = new URL(mediaUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
throw new IOException("Unable to create InputStream for mediaUrl:" + mediaUrl);
}
// this file will represent whole downloaded song
mp3FileDownloaded = new File(cacheDir, mp3FileName);
if (!mp3FileDownloaded.exists())
//FileUtils.makeDirsForFile(mp3FileDownloaded);
try{
mp3FileDownloaded.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (!mp3FileDownloaded.canWrite())
throw new IOException("Can't open temporary file for writing");
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setReadTimeout(1000 * 20);
urlConnection.setConnectTimeout(1000 * 5);
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
int mp3BytesSize = urlConnection.getContentLength();
// final String
// contentLengthStr=urlConnection.getHeaderField("content-length");
String ctype = urlConnection.getContentType();
if (ctype == null) {
ctype = "";
} else {
ctype = ctype.toLowerCase(Locale.US);
}
// See if we can handle this type
Log.i(TAG, "Content Type: " + ctype);
if ( ctype.contains("audio/mpeg") || TextUtils.isEmpty(ctype) ) {
String temp = urlConnection.getHeaderField(BITRATE_HEADER);
Log.i(TAG, "Bitrate: " + temp);
// if (temp != null){
// bitrate = new Integer(temp).intValue();
// }
} else {
Log.e(TAG, UNSUPPORTED_AUDIO_TYPE+": " + ctype);
// throw new IOException(UNSUPPORTED_AUDIO_TYPE+": " + ctype);
// Log.e(TAG, "Or we could not connect to audio");
// stop();
// return;
}
final InputStream stream = new BufferedInputStream(urlConnection.getInputStream(),8192);
...
Right at the last shown line of code (instantiating the InputStream stream) the mentioned IOExeption raised. There are other mp3 files exists at same location and they are downloading with no any issue but only mentioned above url fails.What could be wrong here?
UPDATE
Its appears that this issue happens on HTC Rezound with AOS 4.0.4. On other device, with AOS 2.3.5 everything works ok.
seems like the line
urlConnection.setDoOutput(true);
was the source of issue since I don't upload any data. Everything works fine since I'd comment it. Also these FileNotFoundException while getting the InputStream object from HttpURLConnection and Android HttpUrlConnection getInputStream throws NullPointerException threads might be helpfull.
I'm new to Android and developing a file downloading app with a ProgressDialog which shows the downloading percentage.
I use AsyncTask and here is the trouble part of my code.
protected String doInBackground(String... f_url){
int count;
try {
URL url = new URL(f_url[0]);
URLConnection conn = url.openConnection();
conn.connect();
// getting file length
int lenghtOfFile = conn.getContentLength();
// input stream to read file - with 8k buffer
InputStream input = new BufferedInputStream(url.openStream(), 8192);
File direct = new File(folder);
if(!direct.exists()) {
direct.mkdirs();
}
// Output stream to write file
OutputStream output = new FileOutputStream(apkPath);
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
// After this onProgressUpdate will be called
publishProgress(""+(int)((total*100)/lenghtOfFile));
// writing data to file
output.write(data, 0, count);
}
// flushing output
output.flush();
// closing streams
output.close();
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
return null;
}
My issue is this code works really well on Android API 16 (JB) but not on API 19 (KitKat). On KitKat devices, the progress bar percentage does not update (always 0). After checking the codes, I found conn.getContentLength() returns -1 when I run it on KitKat. So it can not update the progress. But it returns correct file size when I run it on API 16 (JB).
Can somebody please help me to solve this?
Thank you in advance.
Have you read Migrating to WebView in Android 4.4: http://developer.android.com/guide/webapps/migrating.html
Blockquote
If you call methods on WebView from any thread other than your app's UI thread, it can cause unexpected results. For example, if your app uses multiple threads, you can use the runOnUiThread() method to ensure your code executes on the UI thread:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code for WebView goes here
}
});
You can try this:
conn.setRequestProperty("Accept-Encoding", "identity");
I am using AsyncTask to download ~50 MB files from internet. Sometimes, when I download this file, progress bar gain is very slow (even when I am on Wi-Fi). And after minute, phone shows me, download complete, but the file itself has only ~100kB, no more. But when I restart device, and try to download file, download is executed briefly and quick. Has anyone faced same problem? Do I need to erase same download memory before downloading new file? I am downloading file to Environment.externalStoryDirectory().
Thx
Calling download from activity:
mProgressDialog = new ProgressDialog(ItemDetails.this);
mProgressDialog.setTitle("Downloading");
mProgressDialog.setMessage("Downloading sth...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
DownloadMapTask downloadFile = new DownloadMapTask(ItemDetails.this);
downloadFile.execute(web_location_url);
mProgressDialog.show();
Download Async Task (two methods):
#Override
protected String doInBackground(String... urls) {
int count;
PATH=maps_loc+"/Android/data/test/maps/";
try {
URL url = new URL(urls[0]);
HttpURLConnection connection2 = (HttpURLConnection) url.openConnection();
connection2.setRequestMethod("GET");
connection2.setDoOutput(true);
connection2.connect();
int lenghtOfFile = connection2.getContentLength();
File apkdir = new File(PATH);
apkdir.mkdirs();
File newInstall = new File(PATH, name+".tmp");
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(newInstall);
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1 && running==true) {
total += count;
publishProgress((int) (total * 100 / lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void onProgressUpdate(Integer... args) {
ItemDetails.mProgressDialog.setProgress(args[0]);
}
Some servers will close the connection if the client has slow speed and the download takes long time, which can be the case if your program is connected to the Internet through mobile data not Wi-Fi.
You should consider supporting download resume in your program to not start from scratch every time.
I do not think there is sort of download memory that you need to clear. I have an app that can easily downloads over 50MB with no problems.
Also, you might consider obtaining a lock for both Wi-Fi and processor to keep your program running until the download finishes.
Edit
In your code, try to print the value lenghtOfFile after the line int lenghtOfFile = connection2.getContentLength(); to make sure that it is the same as the actual file size you are downloading.
Below is alternative example code which supports resume that I am using in my projects. (it is just to illustrate the idea, you will need to modify the code to your needs)
HttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(new URI(fileURL)));
HttpResponse response;
InputStream is = null;
FileOutputStream fos = null;
try {
boolean continueDownloading = false;
String tmpFileName = fileName + "_tmp";
outputFile = new File(downloadFolder, tmpFileName);
if (outputFile.exists()) {
localFileLength = outputFile.length();
if (localFileLength > 0) {
continueDownloading = true;
}
if (continueDownloading) {
request.addHeader("Range", "bytes=" + localFileLength + "-");
}
response = httpClient.execute(request);
long remoteFileLength = 0;
Header contentLengthHeader = response.getFirstHeader("Content-Length");
if (contentLengthHeader != null) {
remoteFileLength = Integer.parseInt(contentLengthHeader.getValue());
}
long downloaded = 0;
if (continueDownloading) {
downloaded = localFileLength;
}
long fullFileLength = downloaded + remoteFileLength;
fos = new FileOutputStream(outputFile, true);
is = response.getEntity().getContent();
byte[] buffer = new byte[DOWNLOAD_BUFFER_SIZE];
int len = 0;
while ((len = is.read(buffer)) != -1 && isDownloading) {
fos.write(buffer, 0, len);
downloaded += len;
}
fos.flush();
boolean success = downloaded == fullFileLength;
if (success) {
outputFile.renameTo(new File(downloadFolder, fileName));
}
} catch (Throwable ex) {
ex.printStackTrace();
} finally {
// clean up resources
}
Try using downloadManager instead of downloading manually , there are many advantages to using it.
Here is an example for it : DownloadManager Example
and take a look at the documentations : DownloadManager
From my Android app I try to download from the windows Azure blob storage using the following URL: http://iclyps.blob.core.windows.net/broadcasts/23_6.mp4
The resulting file is corrupt when I download it from within my app. Same error occurs when I download it using the default Browser or Chrome. Also from the Easy Downloader app, the same error occurs. Only a download from my PC or using Firefox Beta from the Android device (or emulator), the file is retrieved correctly.
I use the following code (snippet):
try {
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//set up some things on the connection
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
//and connect!
urlConnection.connect();
bis = new BufferedInputStream(urlConnection.getInputStream(), BUFSIZE);
bos = new BufferedOutputStream(
context.openFileOutput(TMPFILE, Context.MODE_PRIVATE), BUFSIZE);
/*
* Read bytes to the buffer in chunks of BUFSIZE bytes until there is nothing more to read.
* Each chunk is written to the output file.
*/
byte[] buf = new byte[BUFSIZE];
int nBytes = 0;
int tBytes = 0;
while ((nBytes = bis.read(buf, 0, BUFSIZE)) > 0) {
bos.write(buf, 0, nBytes);
tBytes += nBytes;
}
if (tBytes == 0) throw new Exception("no bytes received");
bos.flush();
MobyLog.d(TAG, "download succeeded: #bytes = " + Integer.toString(tBytes));
return true;
} catch (Exception e) {
MobyLog.e(TAG, "download failed: " + e);
context.deleteFile(TMPFILE); // remove possibly present partial file.
return false;
} finally {
if (bis != null) try { bis.close(); } catch (IOException e) {MobyLog.e(TAG, "bis close exception: " + e); };
if (bos != null) try { bos.close(); } catch (IOException e) {MobyLog.e(TAG, "bos close exception: " + e); };
}
Analyzing the files shows that the first part (about 700K) of the original file is repeated a number of times in the corrupted files, resulting in an invalid mp4 file.
Putting the file on another webserver (Apache/IIS), and downloading the file from that location does result in a correct download.
Has anyone experienced a similar problem performing a download from Azure? Can someone provide a solution?
Cheers,
Harald...
Have you tried using the azure-sdk-for-java in your android app?
Our scenario is slightly different in that we using the sdk to pull and push images from blob storage to a custom android app. But the fundamentals should be the same.
Currently doing project on live Streaming, and I succeed to play live video. Now my next task is to record the video which is playing in VideoView.
I had searched, able to found capturing video but with surface(camera) but here in VideoView I am not having any surface.
any help appreciated
You can see this link. In short your server has to support downloading. If it does, you can try the following code:
private final int TIMEOUT_CONNECTION = 5000; //5sec
private final int TIMEOUT_SOCKET = 30000; //30sec
private final int BUFFER_SIZE = 1024 * 5; // 5MB
private final int TIMEOUT_CONNECTION = 5000; //5sec
private final int TIMEOUT_SOCKET = 30000; //30sec
private final int BUFFER_SIZE = 1024 * 5; // 5MB
try {
URL url = new URL("http://....");
//Open a connection to that URL.
URLConnection ucon = url.openConnection();
ucon.setReadTimeout(TIMEOUT_CONNECTION);
ucon.setConnectTimeout(TIMEOUT_SOCKET);
// Define InputStreams to read from the URLConnection.
// uses 5KB download buffer
InputStream is = ucon.getInputStream();
BufferedInputStream in = new BufferedInputStream(is, BUFFER_SIZE);
FileOutputStream out = new FileOutputStream(file);
byte[] buff = new byte[BUFFER_SIZE];
int len = 0;
while ((len = in.read(buff)) != -1)
{
out.write(buff,0,len);
}
} catch (IOException ioe) {
// Handle the error
} finally {
if(in != null) {
try {
in.close();
} catch (Exception e) {
// Nothing you can do
}
}
if(out != null) {
try {
out.flush();
out.close();
} catch (Exception e) {
// Nothing you can do
}
}
}
If the server doesn't support downloading, there is nothing you can do.
You can use platform-tools and record video using:
adb shell screenrecord --verbose /sdcard/demo.mp4
Replace Demo with whatever file name you want.
Also this will be placed on your phone, and defaults to 6 minutes I believe.
Check out the options of screen record.
To pull the file to your computer.... (the following command, or use Android Device Monitor
adb pull /sdcard/demo.mp4
I have used this to record demo's of apps, and even played youtube, and had it record that.
It does not have audio, so that may be a major problem.
But this is included in the sdk, and records any screen showing while it is recording.