I am working on an application that plays a video file on a loop. Up until now I was just mounting the device and copying the video file onto the SD card and then using the file path to start it up on my VideoView. I am trying to implement a way that I can remotely update what video it plays so I have moved to storing my video online. Inside the app I check for a local copy and download if it doesn't exist, or if there is a newer one. I have tested it on two different video files both .mp4s. After downloading one of them plays the first time but upon trying to start again for the loop it tells me video cannot be played. The other won't even play the first time, it just gives me the dialog that says the video cannot be played. Both of these files work correctly with my app if I copy them onto the SD card via the USB cable. They work if I exit my app and manually download them with something else(dropbox) but not if I download them from within my app. Here is the code I am using to download the file:
public static void DownloadFromUrl(String fileName) { //this is the downloader method
try {
URL url = new URL("http://dl.dropbox.com/u/myfile.mp4");
File file = new File(PATH + fileName);
long startTime = System.currentTimeMillis();
Log.d(myTag, "download begining");
Log.d(myTag, "download url:" + url);
Log.d(myTag, "downloaded file name:" + fileName);
/* Open a connection to that URL. */
URLConnection ucon = url.openConnection();
Log.i(myTag, "Opened Connection");
/*
* Define InputStreams to read from the URLConnection.
*/
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
Log.i(myTag, "Got InputStream and BufferedInputStream");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
Log.i(myTag, "Got FileOutputStream and BufferedOutputStream");
/*
* Read bytes to the Buffer until there is nothing more to read(-1).
*/
int current = 0;
Log.i(myTag, "About to write");
while ((current = bis.read()) != -1) {
bos.write(current);
}
fos.close();
Log.d(myTag, "download ready in"
+ ((System.currentTimeMillis() - startTime))
+ " sec");
} catch (IOException e) {
Log.d(myTag, "Error: " + e);
}
}
I know the dropbox url in this snippet is not correct I changed it only for this post, in my app the url is pointing to a file correctly. And the variable PATH thats used when creating the File is set in my code outside of this snippet.
Is there something about this code snippet that could be corrupting my mp4 files?
That method was corrupting the file somehow, I am still not quite sure how but I changed part of it and now it is fixed.
I am now using this:
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = bis.read(data)) != -1) {
total += count;
fos.write(data, 0, count);
}
fos.flush();
fos.close();
instead of the old while loop and it works correctly.
Related
I am trying to download a PPT file from a server.
it's in Bytes.
but while debugging I noticed that the input stream throws an exception of FileNotFound while running.. the file does exist on the server, here's my code, any help would be greatly appreciated.
public class DownloadFileAsync extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... aurl) {
int count;
try {
URL url = new URL(aurl[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("Authorization", "Basic " + SharedPref.getAuthPrefValue());
connection.addRequestProperty("Device", BaseApplication.getCurrentDevice().getDevice().toString());
connection.addRequestProperty("DeviceId", BaseApplication.getCurrentDevice().getDeviceId());
connection.connect();
int lengthOfFile = connection.getContentLength();
Log.d("ANDRO_ASYNC", "Length of file: " + lengthOfFile);
InputStream input = new BufferedInputStream(url.openStream());
File sdcardDest = new File(Environment.getExternalStorageDirectory(), "Availo");
String finalDest = sdcardDest + File.separator + "Check1" + "." + "PPT";
OutputStream output = new FileOutputStream(finalDest);
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
publishProgress(""+(int)((total*100)/lengthOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
I am using Charles on Mac (which is similar to fiddler on windows.) to see what I send and receive from the server,
The server doesn't return any error, though it shows download steps for 6-7 sec, downloading around 400 bytes and then it stops.
The Exception is thrown from the input stream line.
Thanks!
I suggest you take a look at the DownloadManager system service. it's designed specifically for what you are trying to do:
(from the documentation)
The download manager is a system service that handles long-running
HTTP downloads. Clients may request that a URI be downloaded to a
particular destination file. The download manager will conduct the
download in the background, taking care of HTTP interactions and
retrying downloads after failures or across connectivity changes and
system reboots
While I do agree with Muzikant regarding the download manager,
FileNotFoundException is usually thrown when... the file is not found on the local device...
You need to do the following to make sure it doesnt happen
File dest = new File(finalDest);
try{
File parentDest = dest.getParentFile();
if(!parentDest.exists()){
parentDest.mkdirs(); //make all the directory structures needed
}
if(!dest.exists()){
dest.createNewFile();
}
OutputStream output = new FileOutputStream(dest);
//now you can use your file dest
//write data to it...
}catch (Exception e){
}
working on my first real android app and one part of it is a download manager.
it must download video files that the app uses to teach people Gaelic.
it works fine on all but 3 files, it downloads bigger files and smaller files. but will not download colours.mp4 1.86MB, weekdays 1.53 MB or numbers 1.99 MB all the files between 1MB and 2MB.
it will just stop at the end of the download loop no errors for a few minutes just looking like its waiting to continue downloading then it will give an error "unexpected end of stream"
can anyone suggest what the problem could be please?
I have crated the same app for the iPhone and that app has not got the same problem with these files.
this is the download loop called from inside an asynctask.
protected void download(String where, String file){
try {
//makes output file
OutputStream output = new FileOutputStream(getFilesDir()
.getAbsolutePath() + "/vidos/" +file);
int count=0;
//gets url to download from
URL url = new URL(where);
URLConnection conection = url.openConnection();
conection.connect();
//gets the length of the file to work out percent downloaded
int lengthOfFile = conection.getContentLength();
InputStream input = null;
Log.v("downloading", String.valueOf(showprg));
input = new BufferedInputStream(url.openStream());
byte data[] = new byte[lengthOfFile];
long total = 0;
Log.v("downloading", "size: " + String.valueOf(downloading));
while ((count = input.read(data)) > 0 && downloading) {
total += count;
publishProgress(String
.valueOf((int) ((total * 100) / lengthOfFile)));
output.write(data, 0, count);
//this is where it brakes
};
Log.v("publishProgress", "done");
output.flush();
output.close();
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
}
I changed my URLConnection to a HttpURLConnection and removed the BufferedInputStream and now it downloads without problem.
thanks to Harshit Rathi for his link to Cristian's post
I have this snippet of code in which I want to handle the downlaod of the file being clicked:
else if (url.startsWith("http://rapahh.com/songs2/Music%20Promotion/Download/")) {
}
return false;
Although I have no idea how to handle downloads in Android, so does anyone have a snippet of code I can use to download the file in the background to a folder.. the download folder is fine. Thanks.
What version of android are you building for?
Starting with API lvl 9 there is the DownloadManager that can handle this for you. If at all possible you should use the DownloadManager, because it will automatically handle network interuptions and resume the downloads for you.
If you are aiming for lower API lvl than that you'll have to make the download code yourself. You'll have an inputStream coming from your web source and an outputStream going to your local file and you will loop through the inputStream writing chunks until there are none left.
Something like this:
try {
URL url = new URL(URL); //URL of the video
//Set our file to the correct path and name.
File file = new File(PATH + fileName);
//keep the start time so we can display how long it took to the Log.
long startTime = System.currentTimeMillis();
Log.d(myTag, "download begining");
//Log.d(myTag, "download url:" + url);
Log.d(myTag, "downloaded file name:" + fileName);
/* Open a connection to that URL. */
URLConnection ucon = url.openConnection();
// this will be useful so that you can show a tipical 0-100% progress bar
int lenghtOfFile = ucon.getContentLength();
Log.i(myTag, "Opened Connection");
/************************************************
* Define InputStreams to read from the URLConnection.
************************************************/
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
Log.i(myTag, "Got InputStream and BufferedInputStream");
/************************************************
* Define OutputStreams to write to our file.
************************************************/
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
Log.i(myTag, "Got FileOutputStream and BufferedOutputStream");
/************************************************
* Start reading the and writing our file.
************************************************/
byte data[] = new byte[1024];
long total = 0;
int count;
//loop and read the current chunk
while ((count = bis.read(data)) != -1) {
//Post our progress update back to the UI thread
postProgress((int)(total*100/lenghtOfFile));
//write this chunk
total += count;
bos.write(data, 0, count);
}
//Have to call flush or the video file can get corrupted and won't play correctly.
bos.flush();
bos.close();
Log.d(myTag, "download ready in "
+ ((System.currentTimeMillis() - startTime))
+ " milisec");
} catch (IOException e) {
Log.d(myTag, "Error: " + e);
}
You'll need to implement the postProgress(int progress) method to do whatever is appropriate for your application to inform the user of what percentage complete the download is.
Edit:
you can comment out the logs to get it to work. I leave them on while I am debugging though to make the process easier. Log statements such as Log.i(String tag, String text)
are similar to System.out.println(String txt) The difference is that these statements are printed into the log file ( which you can see in the DDMS perspective in eclipse) And they have an additional parameter called "tag" you can pass it whatever string you like and this string will show up along side of your text in the log file. You can also filter the log output basted on these tags in the DDMS perspective. It is common practice to declare your tag as a static String so that you can just use that reference to it for all of your log statements and you are guaranteed to always have the same tag. So if you add something like this to your class it should fix your error:
final static String myTag = "NameOfYourActivity";
Does anyone know how to save a file from a webserver(local host) to the sdcard through wifi?
I am doing xml parsing to my application and for that I have to download an xml file from localhost to the sdcard and then tag the parsing. I am stuck with downloading an xml file to the sd card. Please guide me on how to do this..
You can use this method to download a file from the internet to your SD card:
public void DownloadFromUrl(String DownloadUrl, String fileName) {
try {
File root = android.os.Environment.getExternalStorageDirectory();
File dir = new File (root.getAbsolutePath() + "/xmls");
if(dir.exists()==false) {
dir.mkdirs();
}
URL url = new URL(DownloadUrl); //you can write here any link
File file = new File(dir, fileName);
long startTime = System.currentTimeMillis();
Log.d("DownloadManager", "download begining");
Log.d("DownloadManager", "download url:" + url);
Log.d("DownloadManager", "downloaded file name:" + fileName);
/* Open a connection to that URL. */
URLConnection ucon = url.openConnection();
/*
* Define InputStreams to read from the URLConnection.
*/
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
/*
* Read bytes to the Buffer until there is nothing more to read(-1).
*/
ByteArrayBuffer baf = new ByteArrayBuffer(5000);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte) current);
}
/* Convert the Bytes read to a String. */
FileOutputStream fos = new FileOutputStream(file);
fos.write(baf.toByteArray());
fos.flush();
fos.close();
Log.d("DownloadManager", "download ready in" + ((System.currentTimeMillis() - startTime) / 1000) + " sec");
} catch (IOException e) {
Log.d("DownloadManager", "Error: " + e);
}
}
You need to add the following permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
The Sourav's answer is OK, but for large file sizes you should implement it on a new thread; because while downloading, the main thread is busy for downloading the file. If the waiting time be more that expected the system will generate "Not responding" error.
In order to do that you can use "TaskAsync" or "IntentService"
I prefer to build soap server and make a call from app to server and by that receiving XML. Or maybe you could just make an URL which generates XML and that just parse URL directly.
Try to read more on this LINK
Hopefully I have answer the question. Otherwise would be pleased to help, but I need more detailed functionality description.
I found this source code on the net and have modified it a little. But I get an error saying: java.io.FileNotFoundException /data/datafile.zip.
What should I do to get it running? Do I have to create the file first?
Thanks, Sigurd
private Thread checkUpdate = new Thread() {
public void run() {
try {
long startTime = System.currentTimeMillis();
Log.d("Zip Download", "Start download");
File file = new File(Environment.getDataDirectory(), "datafil.zip");
Log.d("Zip Download", file.getAbsolutePath());
URL updateURL = new URL("http://dummy.no/bilder/bilder/XML_Item_Expo_01.zip");
URLConnection conn = updateURL.openConnection();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while((current = bis.read()) != -1){
baf.append((byte)current);
}
/* Convert the Bytes read to a String. */
FileOutputStream fos = new FileOutputStream(file);
fos.write(baf.toByteArray());
fos.close();
Log.d("Zip Download", "download ready in" + ((System.currentTimeMillis() - startTime) / 1000) + " sec");
} catch (Exception e) {
Log.d("Zip Download", "Error: " + e);
}
}
};
Seems like permission error. You maybe writing to the wrong place. Check that answer at link below,
Data directory has no read/write permission in Android
Environment.getDataDirectory() does not return a path where you can place files. You should use one of these methods instead:
Environment.getExternalStorageDirectory() gives you a path to external storage (SD card).
getFilesDir() from an Activity or other Context. Gives a path to app's internal file storage
You can also call openFileOutput() with a string file name (no path, just the file), which will open the FileOutputStream and create the file all in one shot for your use.
Hope that Helps!