I'm using DownloadManager to download video files from a url.
The problem is if I use the default folder to download the file I can not see the video in the galery.
Also, If I try to use this method:
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, 'filename');
I need to know the file name before download which in this case, I don't.
And also, I don't have the name of the file in the url.
How can I do to get the file name from the headers and pass the name to the method setDestinationInExternalPublicDir ?
Other alternatives?
In case anyone want an implementation of doing a HEAD request to get the filename:
class GetFileName extends AsyncTask<String, Integer, String>
{
protected String doInBackground(String... urls)
{
URL url;
String filename = null;
try {
url = new URL(urls[0]);
String cookie = CookieManager.getInstance().getCookie(urls[0]);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestProperty("Cookie", cookie);
con.setRequestMethod("HEAD");
con.setInstanceFollowRedirects(false);
con.connect();
String content = con.getHeaderField("Content-Disposition");
String contentSplit[] = content.split("filename=");
filename = contentSplit[1].replace("filename=", "").replace("\"", "").trim();
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e) {
}
return filename;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String result) {
}
}
Small tip, there is a nice helper method in Android
URLUtil.guessFileName(url, contentDisposition, contentType);
So after completing the call to the server, getting the contenttype and contentDisposition from the Headers this will try and find the filename from the information.
I got into the same problem.I used #rodeleon answer but there was no Content-Disposition in response header. Then I analyzed url header from Chrome dev tools and got 'Location' in response header which contained filename at the end, it was like "b/Ol/fire_mp3_24825.mp3". so instead of using
String content = con.getHeaderField("Content-Disposition")
I used
String content = con.getHeaderField("Location")
and at the end in onPostExecute
protected void onPostExecute(String result) {
super.onPostExecute(result);
String fileName = result.substring(result.lastIndexOf("/") + 1);
// use result as file name
Log.d("MainActivity", "onPostExecute: " + fileName);
}
Method URLUtil.guessFileName() (while not yet knowing about the Content-Disposition) and also the meanwhile deprecated class AsyncTask are both kinda problematic approaches these days. To properly enqueue the download with the DownloadManager:
One first has to disable "following redirects" in whatever HTTP client (that's the clue).
Then the first response will be HTTP 302 (with a Location header), instead of HTTP 200.
When fetching that, one will get HTTP 200 with a Content-Disposition header (filename).
Only then one can enqueue with DownloadManager (whilst knowing the filename already).
Here's an example of mine: RepositoryFragment (a GitHub Client).
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_MOVIES, uri.getLastPathSegment());
Related
I have an application created in Android Studio with API 28. I also have a php file (http: //mydomain/receptor.php) that collects data from a url of the type (http: //mydomain/receptor.php? Userid = 23 & points = 123) and saves them in the database. What I want is to know how I can send those urls from my application. I have tried different things but I can not get the application to activate the url. I do not need a response from the server in the application, I just need to activate the url. What is the easiest way to do it? Thank you!!!
You should run the code in a separate thread, paste this in your Activity Class
public class HTTPget extends AsyncTask<String , Void ,String> {
#Override
protected String doInBackground(String... strings) {
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(strings[0]);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(150000); //milliseconds
urlConnection.setConnectTimeout(15000); // milliseconds
urlConnection.setRequestMethod("GET");
urlConnection.connect();
}catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
And you execute the code by calling .execute() whenever you want to execute it
new HTTPget().execute("http://mydomain/receptor.php?Userid=23&points=123");
I am trying to make a POST request in an AsyncTask, but the request method stays as GET all the time.
I have this issue since I moved the HTTP request to AsyncTask, the same code worked before, when it was in the UI thread.
The doInBackground code is below:
protected String doInBackground(String... string) {
httpPostToArduino (string[0]);
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute ();
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute (s);
}
public void httpPostToArduino(String message){
curArd1UrlString="http://myprivateurl.com";
URL url = null;
try {
url = new URL (curArd1UrlString);
} catch (MalformedURLException e) {
e.printStackTrace ();
}
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
StringBuilder result = new StringBuilder (); //test
try {
urlConnection = (HttpURLConnection) url.openConnection ();
//Set header content
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Authorization","password");
urlConnection.setDoOutput(true);
//Set body content
OutputStreamWriter os = new OutputStreamWriter (urlConnection.getOutputStream());
os.write(message.toString ());
os.flush();
InputStream in = new BufferedInputStream (urlConnection.getInputStream ());
reader = new BufferedReader (new InputStreamReader (in));
//Read the first line of the response - just the JSON
result.append (reader.readLine ());
//The below WHILE reads all the content of the response message, but we only need the first line
String ReceivedJSON = result.toString ();
JSONObject parentObject = new JSONObject (ReceivedJSON);
In the debugger, under urlConnection, for method field, it is always GET. Below a snip from debugger mode, to be clearer.
I get a response after each request, but the response depends on the body content of the POST request.
What should I change in the code in order to change the request method to POST?
I had the same Problem, for me it happened, because I did not specify the full URL path.
There are two ways to fix this. The first way is to specify the full url (with file.php at the end) and the second way is to rewrite the url in the web server config.
I fixed it by rewriting the url in my web server. This is for nginx.
This adds .php to the end of the requested URL.
location /api {
rewrite ^(/api/.*)/(\w+) $1/$2.php last;
}
For example you have the Url http://example.com/api/v1/file . After specifying the rewrite this url will be rewritten to http://www.example.com/api/v1/file.php
I'm trying to connect to a web API using a URL. However, I get a 301 error from the server (Moved Permanently), although the provided URL works very well with no errors when I try it in my browser.
Here is the code that builds the URL:
public Loader<List<Earthquake>> onCreateLoader(int i, Bundle bundle) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
String minMagnitude = sharedPrefs.getString(
getString(R.string.settings_min_magnitude_key),
getString(R.string.settings_min_magnitude_default));
String orderBy = sharedPrefs.getString(
getString(R.string.settings_order_by_key),
getString(R.string.settings_order_by_default)
);
Uri baseUri = Uri.parse(USGS_REQUEST_URL);
Uri.Builder uriBuilder = baseUri.buildUpon();
uriBuilder.appendQueryParameter("format", "geojson");
uriBuilder.appendQueryParameter("limit", "10");
uriBuilder.appendQueryParameter("minmag", minMagnitude);
uriBuilder.appendQueryParameter("orderby", orderBy);
Log.i ("the uri is ", uriBuilder.toString());
return new EarthquakeLoader(this, uriBuilder.toString());
}
Here is the code that tries to connect to the resource represented by the URL:
private static String makeHttpRequest(URL url) throws IOException {
String jsonResponse = "";
// If the URL is null, then return early.
if (url == null) {
return jsonResponse;
}
Log.i("The received url is " , url +"");
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// If the request was successful (response code 200),
// then read the input stream and parse the response.
if (urlConnection.getResponseCode() == 200) {
inputStream = urlConnection.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode()); //this log returns 301
}
} catch (IOException e) {
Log.e(LOG_TAG, "Problem retrieving the earthquake JSON results.", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
// Closing the input stream could throw an IOException, which is why
// the makeHttpRequest(URL url) method signature specifies than an IOException
// could be thrown.
inputStream.close();
}
}
return jsonResponse;
}
I could know that the connection returns status code of 301 from the log provided in the case when the status code is not 200. I have also logged the generated URL, I copied it from the logcat and tried it in my browser and it worked well. Here is the built URL: http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&limit=10&minmag=6&orderby=magnitude
I checked this question: Android HttpURLConnection receives HTTP 301 response code but it wasn't clear to me what is the solution for the problem.
Can you please help me identify and solve the problem?
UPDATE: As greenapps indicated in his comment, the connection is done through https. That comment identified the problem and helped me fix the code.
In my code, the string I used to build the basic URL, had the protocol value as http not https, it was:
private static final String USGS_REQUEST_URL =
"http://earthquake.usgs.gov/fdsnws/event/1/query";
After reading greenapps comment, I just changed the protocol part in the string to https, so it became:
private static final String USGS_REQUEST_URL =
"https://earthquake.usgs.gov/fdsnws/event/1/query";
That solved the problem.
Thanks.
If you click your http link here you will see that the browser shows a https page. You better use that url directly as there is redirection now.
This is because the address http to https transferred.
To avoid this, you need to convert the request address to https.
I have a question about the proper syntax and order of code in regards to accessing a REST API.
I am trying to access a database that I made on an mBaas called backendless.com. (The following data information is specific to this mBaas but my question is more about the general process of accessing REST API's in Android)
According to their tutorial to bulk delete (https://backendless.com/documentation/data/rest/data_deleting_data_objects.htm) I need a URL that queries my database for a specific value and then deletes it. I have that value. They also need 3 request headers (application-id, secret key, application type).I have those as well.
I utilized all of this information in an ASyncTask class that technically should open the url, set the request headers, and make the call to the REST API. My only issue is, I have no idea if I'm missing some kind of code here? Is my current code in proper order? Every time my class is executed, nothing happens.
I also get a log cat exception in regards to my URL: java.io.FileNotFoundException: api.backendless.com/v1/data/bulk/...
The URL does not lead to anything when I place it in my browser but I'm told that it shouldn't since the browser sends it as a GET request.
Anyway, here is my ASyncTask Class with all of the info. Does anyone know if this code looks correct or am I missing something here? I'm new to making these type of calls and don't really understand the roll that request-headers play in accessing REST APIs. Please let me know. Thank you!
class DeleteBulkFromBackEnd extends AsyncTask<Void,Void,String>{
final String API_URL = "https://api.backendless.com/v1/data/bulk/LocalPhoneNum?where%3DuserEmailID%3Dmark#gmail.com";
#Override
protected String doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
try {
URL url = new URL(API_URL);
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestProperty( "application-id","12345678" );
urlConnection.setRequestProperty( "secret-key","12345678" );
urlConnection.setRequestProperty( "application-type", "REST" );
urlConnection.connect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
Log.d("Contact","ERROR " + e.toString() );//IO Exception Prints in log cat not recognizing URL
e.printStackTrace();
}finally {
urlConnection.disconnect();
}
return null;
}
}
I recommend you to use okhttp for easy network access.
And check the response code and response body.
In your build.gradle:
compile 'com.squareup.okhttp3:okhttp:3.4.1'
Your AsyncTask will be like this:
class DeleteBulkFromBackEnd extends AsyncTask<Void, Void, String> {
final String API_URL = "https://api.backendless.com/v1/data/bulk/LocalPhoneNum?where%3DuserEmailID%3Dmark#gmail.com";
final OkHttpClient mClient;
public DeleteBulkFromBackEnd(OkHttpClient client) {
mClient = client;
}
#Override
protected String doInBackground(Void... params) {
try {
Request request = new Request.Builder()
.url(API_URL)
.delete()
.header("application-id", "12345678")
.header("secret-key", "12345678")
.header("application-type", "REST")
.build();
Response response = mClient.newCall(request).execute();
Log.d("DeleteBulkFromBackEnd", "Code: " + response.code());
Log.d("DeleteBulkFromBackEnd", "Body: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Execute the AsyncTask like this:
OkHttpClient client = new OkHttpClient();
void someMethod() {
...
new DeleteBulkFromBackEnd(client).execute();
...
}
As I've commented, here's the solution:
class DeleteBulkFromBackEnd extends AsyncTask<Void,Void,String>{
final String API_URL = "https://api.backendless.com/v1/data/bulk/LocalPhoneNum?where%3DuserEmailID%3Dmark#gmail.com";
#Override
protected String doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
try {
URL url = new URL(API_URL);
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestProperty( "application-id","12345678" );
urlConnection.setRequestProperty( "secret-key","12345678" );
urlConnection.setRequestProperty( "application-type", "REST" );
urlConnection.setRequestMethod("DELETE");
urlConnection.connect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
Log.d("Contact","ERROR " + e.toString() );//IO Exception Prints in log cat not recognizing URL
e.printStackTrace();
}finally {
urlConnection.disconnect();
}
return null;
}
}
I need to copy all HTML code on the page.
I do so:
URL url = new URL(testurl);
URLConnection connection = url.openConnection();
connection.connect();
Scanner in = new Scanner(connection.getInputStream());
while(in.hasNextLine())
{
htmlText=htmlText+in.nextLine();
}
in.close();
But if the page is large, it takes a lot of time.
Is there a faster method?
Have you tried a different method of reading the page? Like a buffered reader? Reading the content of web page or
Reading entire html file to String?
I'm just thinking Scanner may be a little slow.
Tim
Try to use use (http://jsoup.org "JSoup") to download and parse the HTML from URL
You can get the HTML as document and read the text on each elements
new AsyncTask<Void, Integer, String>(){
#Override
protected String doInBackground(Void... params) {
try {
final Document doc = Jsoup.connect("http://youturl.com").get();
final String content;
runOnUiThread(new Runnable() {
#Override
public void run() {
// get the required text
content = doc.body().getElementsByTag("bodyTag").text();
}
});
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
}.execute();