I am authenticating an external system via a REST API. The http authentication request is of the Basic Authorization form. The response is in JSON format.
I am running this code under an AsyncTask.
url The GET url of the API.
credentials is the authentication credentials. It is a string.
response is the text view.
getmessage is a string variable.
connection = (HttpURLConnection)new URL(url).openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Basic" + Base64.encode(credentials.getBytes(), Base64.DEFAULT ));
// I am reading the response here,
InputStreamReader in = new InputStreamReader(connection.getInputStream());
buf = new BufferedReader(in);
getmessage = buf.readLine();
// After making the request, I am updating the response to a text view on the UI thread
runOnUiThread(new Runnable() {
#Override
public void run() {
response.setText(getmessage);
}
});
I am unable to write the whole JSON data to the text view. I know that buf.readline returns the response till the end of a line. Right now I am only getting a part of the JSON response, "Not Authenticated:", but I need the whole response.
How do I update the whole JSON response to the text view (response)? If I loop the data using buf.readline in a loop then where can I use it? In which thread?
If there is anything unusual in my code. Please let me know.
I would suggest you to go trough AsyncTask
private class GetDataFromUrl extends AsyncTask<URL, Integer, String> {
protected String doInBackground(URL... urls) {
connection = (HttpURLConnection)new URL(url).openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Basic" + Base64.encode(credentials.getBytes(), Base64.DEFAULT ));
InputStreamReader in = new InputStreamReader(connection.getInputStream());
buf = new BufferedReader(in);
StringBuilder sb = new StringBuilder();
while ((getmessage = buf.readLine()) != null) {
sb.append(getmessage);
}
getmessage = sb.toString();
return getmessage;
}
protected void onPostExecute(String result) {
// Result will be available here (this runs on main thread)
// Show result in text view here.
response.setText(result);
}
}
To understand better, as you call AsyncTask, doInBackground runs on the new thread created. Where the network call in placed and data is parsed. Now, we need to access the data on the main thread to update the TextView so override onPostExecute inside AsyncTask that is taking result as a parameter, from doInBackground. Also if you notice..
private class GetDataFromUrl extends AsyncTask<URL, Integer, String>
Here URL is the type we are passing to our AsyncTask for doInBackground
String is what we passing from doInBackground to onPostExecute
and Integer is used to show progress for another method you can override i.e onProgressUpdate .. You can read more in the documentation liked above. Hope it was helpful.
You're only reading the first line of the response with readLine(). Call that in a loop until all lines are read, and append each new line to the previous.
If i understood correcly, you are trying to read all response data line by line. Can you try the following?
#Override
protected String doInBackGround(...){
. . .
BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream), 8 * 1024);
String line = "";
StringBuilder sb = new StringBuilder();
while ((line = rd.readLine()) != null) {
sb.append(line);
}
String response = sb.toString();
return response;
}
#Override
protected void onPostExecute(String response){
Textview tv = your_textview;
your_textview.settext(whatever_part_you_get_from_response);
}
Hope this helps.
Try this:
StringBuilder sb = new StringBuilder();
while ((getmessage = buf.readLine()) != null) {
sb.append(getmessage);
}
getmessage = sb.toString();
EDITED
In your code:
getmessage = buf.readLine();
in variable getmessage reads only first line of JSON. You need to read all lines and concatenate it. How to know did you read all lines or not?
Here is what documentation says about it:
public String readLine()
throws IOException
Returns:
A String containing the contents of the line, not including any
line-termination characters, or null if the end of the stream has been
reached
As you can see, you should invoke this method, save result of it into variable, and check, if variable is not null, then you have read line of JSON. If variable is null, then you have read all JSON into variable and you have completely JSON String.
StringBuilder used to avoid creating unnecessary objects, read more about it here
Related
I am a newbie in android and java. I want to get a url request (result is JSON) and parsing it (for example get JSON weather from yahoo api's).
I copy getStringFromUrl Function and I know error for my function (setWeather). please help me.
public static String getStringFromURL(String urlString) throws IOException {
HttpURLConnection urlConnection;
URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setDoOutput(true);
urlConnection.connect();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
char[] buffer = new char[1024];
String outputString;
StringBuilder builder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line).append("\n");
}
bufferedReader.close();
outputString = builder.toString();
return outputString;
}
public void setWeather (View view) throws IOException, JSONException {
String json = getStringFromURL("https://query.yahooapis.com/v1/public/yql?q=select * from weather.forecast where woeid in (select woeid from geo.places(1) where text='Esfahan')&format=json");
JSONObject jso = new JSONObject(json);
JSONObject query = jso.getJSONObject("query");
JSONObject result = query.getJSONObject("results");
JSONObject channel = result.getJSONObject("channel");
JSONObject windI = channel.getJSONObject("wind");
JSONObject location = channel.getJSONObject("location");
String last = "";
last = location.getString("city");
TextView tv = (TextView) findViewById(R.id.textView);
tv.setText(last);
}
When I run this app on device app crash.
It's error that write on Android Monitor:
All the network requests should be made on a separate worker thread or else you will get NetworkOnMainThread exception. For your use case use an Asynctask which has method doInBackground() to handle your request on background thread and post results back to main Ui thread inside onPostExecute() method. So call below method in in doInBackground() method.
getStringFromURL("https://query.yahooapis.com/v1/public/yql?q=select * from weather.forecast where woeid in (select woeid from geo.places(1) where text='Esfahan')&format=json");
and use ui components like textview in onPostExecute() method
tv.setText(last);
which runs on ui thread. All this management is done by Asnyctask so you don't need to worry about thread management just know which method to use.
Asynctask Android documentation
In case of android there is one notion you have to follow, all time taking tasks need to go on a separate thread that is not blocking your UI thread. And all IO calls or heavy operation call should go onto a seperate thread.
For more about how to make network operations refer Android developer guide
here (https://developer.android.com/training/basics/network-ops/connecting.html) and follow this document.
Okay so I'm trying to make an app that is able to retrieve data from a web server and then show it on a textView and constantly update it if the data changes from the web server. And what I got so far after many rounds of trying is this as shown
public class HttpTest extends AppCompatActivity {
TextView text = (TextView) this.findViewById(R.id.textView3);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_http_test);
HttpURLConnection urlConnection = null;
try {
URL url = new URL("http://IPGOESHERE/");
HttpURLConnection urLConnection = (HttpURLConnection) url.openConnection();
InputStream in = urLConnection.getInputStream();
BufferedReader data = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
String line;
while ((line = data.readLine()) != null) {
total.append(line).append('\n');
}
String result = total.toString();
text.setText(result);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
}
I don't think what i have written allows for constant update, but I at least want to be able to show some kind of data on a textView and make sure it doesn't crash first. So if someone could point out what I'm doing wrong it will be much appreciated.
The app crash because you are making HTTP request on main thread. Use an AsyncTask instead
you need to this kind of work on a different thread. try using an AsyncTask.
you create a class that extends AsyncTask, than make the url connection in the doInBackground method (a method that gets called on a worker thread). you can then update the textview in the onPostExecute method which is called on the ui thread. good luck :)
I've been going over various Asynctask tutorials and examples, but I'm still a little confused. If I want to issue 3 web requests and return their response
like:
//example
String[] response = new String[3];
response[0] = webrequest("http://www.google.com"); //simple HTTP GET request
response[1] = webrequest("http://www.bing.com"); //simple HTTP GET request
response[2] = webrequest("http://www.aj.com"); //simple HTTP GET request
//sample results from request
response[0] = "blah";
response[1] = "arg";
response[2] = "meh";
To do this with an AsyncTask, would I need to implement 3 different ATs? Should I be using something else?
String[] response = new String[3];
webCreate sample = new webCreate();
try{
response[0] = sample.execute("http://www.google.com").get().toString();
response[1] = sample.execute("http://www.google.com").get().toString();
response[2] = sample.execute("http://www.google.com").get().toString();
}
catch (Exception sampleMsg)
{}
public class webCreate extends AsyncTask<String, String, String> {
}
protected String doInBackground(String... params) {
// String url=params[0];
String webRequestResponse = null; //the
// web request
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
return reponse;
}
I know I could access the response data by using .get(), but then my "Async" would become "sync" lol. I feel like I should be using something other than AsyncTask, but I have no idea what that is. Please help.
Your approach is okay, from doInBackground of your AsyncTask call a function that initiates the webrequests and wait for the result with . get(). Due to the fact, that the request are then, not running on the mainUi and blocking it, I see no problem in doing so.
I have this three different projects. Project1(isLibrary), Project2 and Project3 set the Project1 as Library. Now, my problem is that Im sending a request to the server but I cant get to pass the String from my Project2 to Project1. Project 3 will also use Project1 and will send a different request. Any Ideas?
In my Project1, I have an TestAsyncTask Class.
public class TestAsyncTask extends AsyncTask<String, Void, String> {
TextView textView1[], textView2[];
TextView textView;
private LinearLayout linearLayout;
//It's just a sample, not a valid soap header
String string1 = "http://soapactionheaderline"; //Provides the value for the SOAPAction header line.
//It's just a sample, not valid server
String string2 = "https://server.com"; //This is the target URL/Server that we will be connecting to.
Context context;
int resultInt;
//Constructor
public TestAsyncTask(Context cContext){
context = cContext; //Pass Context to constructor
}
//Getter for LinearLayout.
public LinearLayout getLinearLayout(){
return linearLayout;
}
//Setter for LinearLayout.
public void setLinearLayout(LinearLayout lLinearLayout){
this.linearLayout = lLinearLayout;
}
//Getter for String.
public String getString(){
return string2;
}
//Setter for String.
public void setString(String sString){
this.string2 = sString;
}
#Override
protected String doInBackground(String... aServerConnectionString) {
String resultString = null;
try {
// Uses URL and HttpURLConnection for server connection.
URL uRL = new URL(string2);
HttpURLConnection httpURLConnection = (HttpURLConnection) uRL.openConnection();
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
httpURLConnection.setUseCaches(false);
httpURLConnection.setChunkedStreamingMode(0);
//.addRequestProperty - Adds the given property to the request SOAPAction header
httpURLConnection.addRequestProperty("SOAPAction", string1);
httpURLConnection.addRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpURLConnection.addRequestProperty("Content-Length", "" + "THIS IS WHERE I NEED TO PASS THE STRING VARIABLE FROM MY Project2".length());
httpURLConnection.setRequestMethod(HttpPost.METHOD_NAME);
// Using OutputStream and Writer to send a request to the server.
OutputStream outputStream = httpURLConnection.getOutputStream();
Writer writer = new OutputStreamWriter(outputStream);
writer.write("THIS IS WHERE I NEED TO PASS THE STRING VARIABLE FROM MY Project2");
writer.flush();
writer.close();
// Using InputStream to get the response of the request from the server.
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);
int aint = httpURLConnection.getResponseCode();
while ((aint = bufferedReader.read()) != -1) {
byteArrayBuffer.append(aint); //Read bytes to the Buffer until there is nothing more to read.
}
resultString = new String(byteArrayBuffer.toByteArray());
// Use SAXParser(Simple API for XML) to handle the parsing of XML(Response).
SAXParserFactory sAXParserFactory = SAXParserFactory.newInstance();
SAXParser sAXParser = sAXParserFactory.newSAXParser();
XMLReader xMLReader = sAXParser.getXMLReader();
// Create handler to handle XML Tags
TestXMLHandler xMLHandler = new TestXMLHandler();
xMLReader.setContentHandler(xMLHandler);
InputSource inputSource = new InputSource(new StringReader(resultString));
xMLReader.parse(inputSource);
} catch (Exception exception) {
resultString = exception.getMessage(); in the created String and display it to UI.
}
return resultString;
}
//This step is the return-value from doInBackground.
protected void onPostExecute(String aReturnValueString) {
// Create an object/instance of GBData Class and get results from GBXMLHandler.
TestGetterSetter data = TestXMLHandler.testdata;
int sizeInt = data.getOperatorName().size();
textView1 = new TextView[sizeInt];
textView2 = new TextView[sizeInt];
//The for statement provides a compact way to iterate over a range of values.
for (resultInt = 0; resultInt < sizeInt; resultInt++) {
textView1[resultInt] = new TextView(context.getApplicationContext());
textView1[resultInt].setText("OperatorName = " + data.getOperatorName().get(resultInt));
linearLayout.addView(textView1[resultInt]);
textView2[resultInt] = new TextView(context.getApplicationContext());
textView2[resultInt].setText("type = " + data.getType().get(resultInt));
linearLayout.addView(textView2[resultInt]);
}
}
}
In my Project2, I have TestActivity1 class which extends the activity, it's the UI
public class TestActivity1 extends Activity{
TestAsyncTask asyncTask = new TestAsyncTask(this);
//This is just a sample soap
String requestString = "<soapenv---------------------------------------------------------------->";
#Override
public void onCreate(Bundle aBundle) {
super.onCreate(aBundle);
asyncTask.execute(asyncTask.getString());
LinearLayout linearLayout = asyncTask.getLinearLayout();
linearLayout = new LinearLayout(this);
linearLayout.setOrientation(1);
asyncTask.setLinearLayout(linearLayout);
// Set the ContentView to layout for display
setContentView(linearLayout);
}
}
I dont really know what you are trying to achieve in your code. Anyhow, come to the problem, I think you are already passing a string value to your AsyncTask. All you need to do is to make use of it in its doInBackground method. For example:
protected String doInBackground(String... aServerConnectionString) {
String yourValue = aServerConnectionString[0];
...
...
...
writer.write(yourValue); //pass your value to writer
...
...
...
}
P.S. I believe your code will not run as it doesn't seem logical at certain places
Firstly, I think its very important that you read up on AsyncTask because your implementation does not correctly utilize how it is designed to work. You've caused yourself more issues if I'm honest :)
To solve your problem based on your current implementation its important you see how the execute() function works in combination with doInBackground().
Execute takes a string array for its arguments, so in Project2 you could do something like this:
String url = "";
String request = "";
asyncTask.execute(url, request);
Then in your ASyncTask, the doInBackground method receives the arguments you used for the execute method. As your passing the values you require between classes, your doInBackground method could look something like this:
#Override
protected String doInBackground(String... aServerConnectionString) {
String url, request;
if (aServerConnectionString[0] != null) {
url = aServerConnectionString[0];
}
if (aServerConnectionString[1] != null) {
request = aServerConnectionString[1];
}
This way your ASyncTask can remove all its string related stuff as it will rely on Project2/3 to pass through the strings.
keep the strings in strings.xml in your library projects as well as target projects..always top priority for resources is given to targeted project..so you can reference that same id and send the staring to server without any issues
I have a ProgressDialog running in a AsyncTask.
I`m trying to achive that as soon as the Length of a buffer is bigger then lets say 10000, the message from the ProgressDialog changes.
Can somebody help me please, is this possible?
Thank you in advance.
#Override
protected void onProgressUpdate(Integer... progUpdate) {
if (progUpdate[0] >= 10000){
progress.setMessage("Informatie wordt opgehaald....");
}
}
The buffer is created in a AsyncTask doInBackGround:
try {
HttpResponse response = httpClient.execute(request);
System.out.println("Response: " + response.getEntity().getContentLength());
/******* READ CONTENT IN BUFFER *******/
InputStream inputStreamActivity = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStreamActivity));
StringBuilder sb = new StringBuilder();
String line = null;
int count = sb.length();
while ((line = reader.readLine()) != null) {
sb.append(line);
publishProgress(sb.length());
}
/******* CLOSE CONNECTION AND STREAM *******/
System.out.println(sb);
inputStreamActivity.close();
kpn = sb.toString();
httpClient.getConnectionManager().shutdown();
}
To change your dialog's message, you'll want to use the onProgressUpdate method of the AsyncTask and define the 2nd paramater of your AsyncTask as an Integer. The onProgressUpdate will look something like:
protected void onProgressUpdate(Integer... progUpdate) {
if (progUpdate[0] >= 10000){ // change the 10000 to whatever
progress.setMessage("The new message");
}
}
To call this, you'll want to update these lines in your doInBackground method of your AsyncTask:
while ((line = reader.readLine()) != null) {
sb.append(line);
publishProgress(sb.length());
}
And get rid of that Runnable. You don't need it. Take a look at the official android documentation for AsyncTask here: http://developer.android.com/reference/android/os/AsyncTask.html There's a great example for you on that page.