I have a text file on my server. I want to open the text file from my Android App and then display the text in a TextView. I cannot find any examples of how to do a basic connection to a server and feed the data into a String.
Any help you can provide would be appreciated.
Try the following:
try {
// Create a URL for the desired page
URL url = new URL("mysite.com/thefile.txt");
// Read all the text returned by the server
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
while ((str = in.readLine()) != null) {
// str is one line of text; readLine() strips the newline character(s)
}
in.close();
} catch (MalformedURLException e) {
} catch (IOException e) {
}
(taken from Exampledepot: Getting text from URL)
Should work well on Android.
While URL.openStream will work, you would be better off using the Apache HttpClient library that comes with Android for HTTP. Among other reasons, you can use content encoding (gzip) with it, and that will make text file transfers much smaller (better battery life, less net usage) and faster.
There are various ways to use HttpClient, and several helpers exist to wrap things and make it easier. See this post for more details on that: Android project using httpclient --> http.client (apache), post/get method (and note the HttpHelper I included there does use gzip, though not all do).
Also, regardless of what method you use to retrieve the data over HTTP, you'll want to use AysncTask (or Handler) to make sure not to block the UI thread while making the network call.
And note that you should pretty much NEVER just use URL.openStream (without setting some configuration, like timeouts), though many examples show that, because it will block indefinitely if you the server is unavailable (by default, it has no timeout): URL.openStream() Might Leave You Hanging.
Don't forget to add internet permissions to the manifest when taking net resources: (add in manifest).
Related
I am getting an OutOfMemoryException when processing a very long JSON response
returned by the code below:
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpGETRequest = new HttpGet(url);
HttpResponse response = httpclient.execute(httpGETRequest);
return EntityUtils.toString(response.getEntity());
Even though I use System.gc() before I call the http request, the exception still occurs.
I tried to look for the cause of the problem by saving the response on a notepad and check its size, just to find out that it is a 5mb file.
What are the things that should be done in order to avoid the exception?
Thanks for your help in advance.
In this cause, we should avoid large data responses from server. I requested a pagination functionality from the server and problem solved.
I don't recommend that you use System.gc() on Android. What you would need to do is use streaming and avoid loading the whole content in memory if it can be avoided.
https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/JsonStreamParser.html
If you need to access parts of the JSON data more readily rather than doing it one chunk at at time, you can transform the data as it is being read and store it in a SQL database that you can query later.
http://developer.android.com/training/basics/data-storage/databases.html
However, if you have embedded binary data such as an image as part of the JSON object you can't do anything about it anymore because it will read the embedded binary data into memory as one chunk. There's no easy way around this aside from writing your own JSON streamer.
Generally
This general technique can be applied not just to Android, but even application servers dealing with large input data such as XML as well.
Calling System.GC() is not guaranteed to run GC. In fact its not a good practice to programmatically invoke GC. For parsing large json data, use streaming APIs in whichever library you use to encode/decode json. One such popular library is Jackson processor.
5mb is not that big data to cause out of memory, maybe dump the memory of the app and analyze for memory leaks. You could sump using adb dumpsys
Tool. Find more about how to use that in What's the Android ADB shell "dumpsys" tool and what are its benefits?
try {
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
inputStream = entity.getContent();
// json is UTF-8 by default
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
result = sb.toString();
inputStream.close();
} catch (Exception e) {
Log.d(TAG, "String was to large" + e.toString());
}
I think if you have problem to load 5Mb string into memory (totally reasonable size), streaming JSON parser will probably not help, because you need to have the result of parsing in memory, which will not necessarily be much smaller. I'd suggest you to do the memory profiling using Android Studio built-in memory monitor, to check how much free memory you have and how you're using it in general.
Background: I have a working application which populates webview data by reading the response from an HttpURLConnection, running some processing on the markup, and then feeding the complete string to WebView.loadDataWithBaseUrl to display the page. This approach works, but has the performance drawback of eliminating concurrent processing of the partially loaded document which happens by default when loading a page normally in any browser or webview.
Goal: I'd like to change my application to a streaming model instead of a two-step serial process. In short, I'm investigating whether I can move from this:
Open the response stream from the server.
Block and read everything from the server until end of document.
Hand the whole thing to the webview at once.
to this:
Open the response stream from the server.
Read any available data and hand it immediately to the webview.
Repeat 2 until end of document.
For an additional wrinkle, the webview pages use both http:// and file:///android_asset requests, which work fine in my current setup. My main difficulty preserving access to both of these. Sidenote: I'm supporting API v14+.
Here's a simplified code summary of my current attempt.
// -- Setup --
WebView webview = makeWebView(); // WebSettings, JS on, view setup, etc
String url = "http://mywebsite.com";
InputStream is = getResponseStreamFromNetwork(url);
// -- Current data injection code --
String completeMarkup = readEverythingAtOnce(is);
webview.loadDataWithBaseUrl(url, completeMarkup, "text/html", "UTF-8", url);
// -- Ideal future data injection code --
webview.loadDataWithBaseUrl(url, "", "text/html", "UTF-8", url);
String line = null;
while ((line = is.readLine()) != null) {
appendToWebView(webview, line);
}
finishWebView(webview);
// -- The hard bits --
void appendToWebView(WebView webview, String line) {
// Inject a partial markup string to the end of the webview's content.
webview.loadUrl("javascript:document.write('" + line.replace("'", "\\'") + "\\n');");
}
void finishWebView(WebView webview) {
// We're done injecting data. Tell the webview we're finished if needed.
webview.loadUrl("javascript:document.write('\\n\\n');");
webview.loadUrl("javascript:document.close();");
}
As written, this successfully streams markup to the webview via document.write, and the page is properly displayed, but my file:///android_asset data requests all get denied access. Changing the base URL of loadDataWithBaseUrl to file:///android_asset fixes those but breaks access to http:// requests via XmlHttpRequest. I assume that this is by-design same origin policy specifically for content introduced via document.write. If that's the case, is there an alternative method for injecting this content piece by piece?
In short, is there a way to reimplement appendToWebView and finishWebView or change something elsewhere to stream data into the webview while avoiding this access problem?
So yes, mixing http(s) and file:// scheme is going to break due to the same origin policy.
This should work instead:
host your entire contents under a 'virtual' http(s) URL (ideally one that you own, or use androidplatform.net),
use WebViewClient.shouldInterceptRequest to intercept the requests to the 'virtual' URL and provide either the network InputStream or an InputStream associated with the asset.
Edit: The relevant bit of code the WebView uses to handle file://android_asset URLs is here.
This is my very first thread so please bear with me. :)
I want to create an Android Service that searches a specific string on a website. To do this I have tried to download that site and search within the html code but the application always crashes when trying to download it.
Does anybody have any idea how to do this?
Thanks in advance
I had a similer problem when i started making an android app that scans imdb.com for movie information. After a lot of searching the internet and testing things out i came up with this:
import java.net.*;
import java.io.*;
URL url = new URL("websiteToLookAt");
InputStreamReader isr = new InputStreamReader(url.openStream());
BufferedReader bufferedReader = new BufferedReader(isr);
String lineThatIsBeingRead = null;
String theString;
while((lineThatIsBeingRead = bufferedReader.readLine()) != null){
if(lineThatIsBeingRead.contains("StringYouAreLookingFor")){
theString = lineThatIsBeingRead;
break;
}
}
The first line sets up the URL of the website you are scanning
The second line opens a the internet to allow you to access the html source directly
The third line makes a Buffered reader that is able to read the source the InputStreamReader gives it
The fifth line is the string that the current line of HTML source is being held in while the buffered reader is checking if it contains the right string. (string1.contains(string2) looks at wether or not string2 is in string1. example: String myName = "john"; if you were to test if myName.contains("oh"); it would return true)
The Sixth line is the string that you will put the string you are looking for from the HTML source(like if you were looking for the name of a movie, this would be the string you would assign the name to)
The while loop reads the next line of the html source code every time the loop starts over and sets the line it just read to the String variable lineThatIsBeingRead. it will keep doing this as long as there is a new line to read. When the buffered reader comes to the end of the HTML source the conditions for the while loop return false and it breaks the loop.
The if statment checks to see if lineThatIsBeingRead has the string StringYouAreLookingFor in it. if it does, it sets theString(the string you are looking for) to lineThatIsBeingRead(the string that is in the buffered reader) then it breaks the while loop. otherwise, it resets the while loop and it starts all over again.
I have the variable theString in there because i was looking for several strings, but if you only need to find one string you can delete lines 6 & 11 and just have lineThatIsBeingRead as the string you assign the string you are looking for to.
Another thing to keep in mind is java doesn't allow you to connect to the internet through the UI thread(the way java wants you to do it is with an intent so when you publish the app remember to take this out and make it run on an intent). but if you add
if(BuildVERSION.SDK_INT >= 9){
StrickMode.ThreadPolicy Policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(Policy);
}
to the onCreate() method and it will bypass that rule.
Hope this was helpful, and good luck with your project!
How do I get text from a basic HTML page and show it in a TextView.
I want to do it this way because it will look better than having a webview showing the text.
There is only one line on the html page. I can change it to a txt file if needed.
Could you also provide a quick example?
You would need to download the HTML first using something like HttpClient to retrieve the data from the Internet (assuming you need to get it from the Internet and not a local file). Once you've done that, you can either display the HTML in a WebView, like you said, or, if the HTML is not complex and contains nothing other than some basic tags (<a>, <img>, <strong>, <em>, <br>, <p>, etc), you can pass it straight to the TextView since it supports some basic HTML display.
To do this, you simply call Html.fromHtml, and pass it your downloaded HTML string. For example:
TextView tv = (TextView) findViewById(R.id.MyTextview);
tv.setText(Html.fromHtml(myHtmlString));
The fromHtml method will parse the HTML and apply some basic formatting, returning a Spannable object which can then be passed straight to TextView's setText method. It even supports links and image tags (for images, though, you'll need to implement an ImageGetter to actually provide the respective Drawables). But I don't believe it supports CSS or inline styles.
How to download the HTML:
myHtmlString in the snippet above needs to contain the actual HTML markup, which of course you must obtain from somewhere. You can do this using HttpClient.
private String getHtml(String url)
{
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
try
{
HttpResponse response = client.execute(request);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line;
StringBuilder builder = new StringBuilder();
while((line = reader.readLine()) != null) {
builder.append(line + '\n');
}
return builder.toString();
}
catch(Exception e)
{
//Handle exception (no data connectivity, 404, etc)
return "Error: " + e.toString();
}
}
It's not enough to just use that code, however, since it should really be done on a separate thread (in fact, Android might flat out refuse to make a network connection on the UI thread. Take a look at AsyncTasks for more information on that. You can find some documentation here (scroll down a bit to "Using Asynctask").
I have problems with getting the html source code with an url. I am trying to develop an application which takes in an url and upon the button submit by the user, it takes in the url and make calls to the url provided to retrieve the html source code.
I have looked up on various methods of doing it, but have always been presented with errors using the codes provided.
Listed below is one of the codes which I have used but it doesn't seem to work for me, it will throw a Error: null in the exception when I use logcat to debug.
please pardon me if the question sounds simple, I'm new to programming. thanks in advance.
String htmlCode = "";
try {
URL url = new URL("http://www.google.com/");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
htmlCode += inputLine;
in.close();
} catch (Exception e) {
Log.d(LOG_TAG, "Error: " + e.getMessage());
}
That code seems to be functional and works for me. Can you post the exception/error you are getting when you run the code?
At a glance, the code looks fine. Make sure you add the Internet permission in your AndroidManifest.xml.
<uses-permission android:name="android.permission.INTERNET" />
I just ran this code and its working fine. The error must be coming from somewhere else?
Are you running this in the emulator? The emulator has DNS problems sometimes. It's possible the emulator can't find www.google.com, see this post:
Upgraded to SDK 2.3 - now no emulators have connectivity
a background process or use AsyncTask to perform your network transaction on a background thread will be required.
http://developer.android.com/resources/articles/painless-threading.html