Data leakage through loop - android

I am trying to download an html of a webpage via AsyncTask and then, show that html in the LOGs.
This is my code. However, when I run the code, loop never stops.
public class MainActivity extends AppCompatActivity {
public class DownloadTask extends AsyncTask<String,Void,String>{
#Override
protected String doInBackground(String... urls) {
String result = "";
HttpURLConnection connection = null;
URL myUrl;
try{
myUrl = new URL(urls[0]);
connection = (HttpURLConnection) myUrl.openConnection();
InputStream in = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while(data != -1){
char current = (char) data;
result += current;
data = reader.read();
}
return result;
}
catch(Exception e){
e.printStackTrace();
return "Failed";
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadTask task = new DownloadTask();
try {
String result = task.execute("http://www.posh24.com/celebrities").get();
Log.i("asd",String.valueOf(result));
}
catch(Exception e){
e.printStackTrace();
}
}
}
My Logs get filled with:
D/dalvikvm: GC_FOR_ALLOC freed 297K, 20% free 2582K/3200K, paused 4ms, total 4ms
Any Idea whats wrong with the code?

The problem with your code is data will not change after you initialized it with a single read() call, so it will never be -1 (hence the infinite loop).
You need to call read() inside the loop.
Replace the following:
int data = reader.read();
while(data != -1){
// ...
With something like this:
int data;
while ((data = reader.read()) != -1) {
// ...
To make things faster you could use a BufferedReader:
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
StringBuilder builder = new StringBuilder();
while((line = reader.readLine()) != null) {
builder.append(line);
}
String data = builder.toString();

Probably because of creating a new string on every character received. Do NOT do this:
result += current;
Instead, create a StringBuilder and append to it.
Or, better yet, do not read one character at a time, but create a BufferedReader and read into a buffer of a considerable size, e.g. 1024 bytes.

I am able to get the data with your code. I believe you already add internet permission when testing.
But your code blocks UI thread because of task.execute().get(). I changed it a bit:
public class DownloadTask extends AsyncTask<String, Void, String> {
private Listener mListener;
DownloadTask(Listener listener) {
mListener = listener;
}
#Override
protected String doInBackground(String... urls) {
String result = "";
HttpURLConnection connection = null;
URL myUrl;
try {
myUrl = new URL(urls[0]);
connection = (HttpURLConnection) myUrl.openConnection();
InputStream in = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
} catch (Exception e) {
e.printStackTrace();
return "Failed";
}
}
#Override
protected void onPostExecute(String s) {
mListener.deliverResult(s);
}
public interface Listener {
void deliverResult(String result);
}
}
And the code in Activity looks like:
DownloadTask task = new DownloadTask(new DownloadTask.Listener() {
#Override
public void deliverResult(String result) {
Log.i("asd",String.valueOf(result));
}
});
task.execute("http://www.posh24.com/celebrities");

Related

HttpURLConnection crashes application

I want to receive and send data with a web server but the code does not work
What do I do for this code to work?
Note this code inside onCreate
try {
URL url = new URL("http://myweb.com/");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream Stream = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(Stream);
BufferedReader b = new BufferedReader(reader);
StringBuilder s = new StringBuilder();
String str ="";
while ((str = b.readLine())!=null) {
s.append(str);
}
String data = s.toString();
TextView myText = (TextView) findViewById(R.id.Text);
myText.setText(data);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Make sure that you do network-related tasks on a separate thread in Android. Also, check that you have the INTERNET permission set.
If you want to then update the UI from another thread, you have to use
runOnUiThread (new Runnable () {
public void run() {
//update ui in here
}
}
All your code runs in Main thread which should be always used for setting up the UI and to listen for UI events such as on click listeners.
Network calls are not allowed on this thread as they might take long time. Use AsyncTask API of android which is designed for running code in separate thread.
Create a class like one below for all GET request tasks.
public class DownloadTask extends AsyncTask<String, Void, Integer> {
private String TAG = "InDownloadTask";
private DownloadCallback callback;
private String data;
public DownloadTask(DownloadCallback cb){
callback = cb;
}
#Override
protected Integer doInBackground(String... params) {
Integer result = 0;
HttpURLConnection urlConnection;
try {
URL url = new URL(params[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int statusCode = urlConnection.getResponseCode();
if (statusCode == 200) {
BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
response.append(line);
}
data = response.toString();
result = 1;
} else {
result = 0;
}
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage());
}
return result;
}
#Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
callback.onFinishDownload(data, integer);
}
}
Create a callback interface that we use for the above class.
public interface DownloadCallback {
public void onFinishDownload(String data, Integer result);
}
Now from your activity onCreate
String url = "http://myweb.com/";
new DownloadTask(new DownloadCallback() {
public void onFinishDownload(String data, Integer result) {
if(result == 1)
myText.setText(data);
else
myText.setText("Error");
}
}).execute(url);
If you have many network related operations, use a Network library such as Volley which will take care of this.

App not able to extract json data

I am trying to extract Json data, but somehow the code is not working.
Can somebody please help me ? Can't seem to understand what i am doing wrong.
(I dont really hav any more details to add)
public class MainActivity extends AppCompatActivity{
TextView t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
t=(TextView)findViewById(R.id.exchangeRate);
Anindya task = new Anindya();
task.execute("xyz");
}
public class Anindya extends AsyncTask<String,Void,String>
{
#Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpURLConnection urlConnection=null;
try {
url = new URL(urls[0]);
urlConnection = (HttpURLConnection)url.openConnection();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(System.in);
int data = reader.read();
while (data!= 0)
{
char current = (char)data;
result += current;
data = reader.read();
}
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.i("website content",result);
}
}
}
Try replacing InputStreamReader reader = new InputStreamReader(System.in) with InputStreamReader reader = new InputStreamReader(in)
If it still doesn't solve your problem then try to check the value of data and post details about returned value.

ArrayAdapter is changed but not reflected in UI

I have been working on ListView and ArrayAdapter. Now I got Stuck while making change in my ArrayAdapter.
I'm using an AsyncTack to update the UI element i.e. ListView, an adapter to the ListView is set in onCreate() method initially, but I'm about to change the array adapter in onPostExecute() method of AsyncTask.
Here is the code bellow
ListView mListView = (ListView)findViewById(R.id.dataListView);
vAdapter = new ArrayAdapter(getActivity(), R.layout.list_item_data,strings);
mLisstView.setAdapter(vAdapter);
AsyncTask
public class getDataFromServer extends AsyncTask<String,Void,String[]>{
public getDataFromServer() {
super();
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String[] doInBackground(String... parm) {
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
if(parm.length == 0){
return null;
}
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String getJsonStr = null;
try {
final String FORECAST_BASE_URL="http://myUrlToServer?";
final String QUERY_PARAM ="query";
final String FORMAT_PARAM ="mode";
final String UNITS_PARAM ="units";
Uri baseUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM,parm[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM,units)
.build();
Log.v("build Url: ",baseUri.toString());
URL url = new URL(baseUri.toString());
// Create the request and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
getJsonStr = buffer.toString();
} catch (IOException e) {
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("Found in trouble", "Error closing stream", e);
}
}
}
try {
return getWeatherDataFromJson(getJsonStr,numDays);
}catch(JSONException ex){
ex.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String[] strings) {
super.onPostExecute(strings);
for(String s : strings)
Log.v("# onPostExecute",s);
vAdapter = new ArrayAdapter(getActivity(), R.layout.list_item_data,strings);
vAdapter.notifyDataSetChanged();
/*if(strings != null){
vAdapter.clear();
for(String dayForecast : strings){
vAdapter.add(dayForecast);
}
}*/
}
}
NOTE: the commented code in onPostExecute() method is also correct by means of logic but generating exception as UnsupportedOperationException while vAdapter.clear()
You can do this way:
onPostExecute() should looks like below:
#Override
protected void onPostExecute(String[] strings) {
super.onPostExecute(strings);
for(String s : strings)
Log.v("# onPostExecute",s);
vAdapter.clear();
vAdapter.addAll(strings);
vAdapter.notifyDataSetChanged();
}
That's it.
finally I found the solution.
I have used array while creating adapter in onCreate() method and trying to clear the adapter as vAdapter.clear() which is not possible. so to do this I just change the array with the List
at onCreate() method
String[] mArray = {"element1","element2",.....};
List<String> mList = new ArrayList<String>(Arrays.asList(mArray));
vAdapter = new ArrayAdappter(getActivity(),R.layout.list_item_data,mList);
at onPostExecute() method
vAdapter.clear();
vAdapter.addAll(strings);
thank you to all.

android async task return type and lockdown

I have the following assynctask implemented. Its usage is pretty simple, and so works as intended so far. get a url, post to it, get its contents, write them to a file. the hard part begins now
QUESTION:
I require reusage of this piece of code multiple times for multiple different files. How can i pass the file as a variable on assynctask call alongside the url?
//class to call a url and save it to a local file
private class url_to_file extends AsyncTask<String, Integer, String> {
protected String[] doInBackground(String... input) {
//function to call url and postback contents
return callpost(input[0]);
}
protected void onProgressUpdate(Integer... progress) {
//Yet to code
}
protected void onPostExecute(String result) {
//function to write content to text file
writeStringAsFile( result, "file.xml" ,getApplicationContext());
}
}
EDIT:
Purelly as reference, the function i use to read, write from file and call url
//saves a txt (etc, xml as well) file to directory,replacing previous. if directory is left empty, save to assets
public static void writeStringAsFile(final String fileContents, String fileName ,Context context) {
try {
FileWriter out = new FileWriter(new File(context.getFilesDir(), fileName));
out.write(fileContents);
out.close();
} catch (IOException e) {
}
}
//read file, returns its contents
public static String readFileAsString(String fileName,Context context) {
StringBuilder stringBuilder = new StringBuilder();
String line;
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(new File(context.getFilesDir(), fileName)));
while ((line = in.readLine()) != null) stringBuilder.append(line);
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
return stringBuilder.toString();
}
//calls a page. Returns its contents
public String callpost (String... strings)
{
StringBuilder content = new StringBuilder();
try
{
// create a url object
URL url = new URL(strings[0]);
// create a urlconnection object
URLConnection urlConnection = url.openConnection();
// wrap the urlconnection in a bufferedreader
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line;
// read from the urlconnection via the bufferedreader
while ((line = bufferedReader.readLine()) != null)
{
content.append(line + "\n");
}
bufferedReader.close();
}
catch(Exception e)
{
e.printStackTrace();
}
return content.toString();
}
EDIT:
Removed second question as it had nothing to do with the rest and would just confuse people to see the thread
Kudos #FirstOne for his help up at comments
this made it for me
//class to call a url and save it to a local file
private class url_to_file extends AsyncTask<String, Integer, String> {
protected String file;
public void setFile(String input)
{
file=input;
}
protected String[] doInBackground(String... input) {
//function to call url and postback contents
return callpost(input[0]);
}
protected void onProgressUpdate(Integer... progress) {
//Yet to code
}
protected void onPostExecute(String result) {
//function to write content to text file
writeStringAsFile( result, file ,getApplicationContext());
}
}

Android show the percentage progress of RESTful API

I am trying to call an Restful api using following code. Now I want to show the progress(% of download). Is it at all possible? If, what change in code is needed for that?
BufferedReader reader=null;
try{
URL mUrl = new URL("http://dev.amazaws.com/formservice/rest/v1/registrationreports/registrationsbyproduct/132866/");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
writer.write( data );
writer.flush();
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line = null;
while((line = reader.readLine()) != null)
{
sb.append(line);
}
String res = sb.toString();
}catch(Exception ex){
}finally{
try{
reader.close();
}catch(Exception ex) {}
}
Try this code, i have implemented this code in one of my application! You can get the idea how to show the percentage! and well This code actually download the JSON from server and saves it on mobile device.
public class LoginActivity extends Activity {
private ProgressDialog prgDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_layout);
}
// Button Click function, on which you want to make restApi call
public void buttonClicked(View view){
new PrefetchData().execute();
}
private class PrefetchData extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// before making http calls
prgDialog = new ProgressDialog(LoginActivity.this);
prgDialog.setMessage("Downloading Data. Please wait...");
prgDialog.setIndeterminate(false);
prgDialog.setMax(100);
prgDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
prgDialog.setCancelable(false);
prgDialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL("http://xyz/testJSON");
connection = (HttpURLConnection) url.openConnection();
connection.connect();
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
// Show ERROR
}
int fileLength = connection.getContentLength();
input = connection.getInputStream();
String extPath = Environment.getExternalStorageDirectory() + "/" + FILE_PATH;
// Environment.
File file = new File(extPath);
if(!file.exists()){
file.createNewFile();
}
output = new FileOutputStream(extPath);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
if (fileLength > 0){
// only if total length is known
// publishing the progress....
publishProgress((int) (total * 100 / fileLength));
}
output.write(data, 0, count);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// After completing http call
// will close this activity and lauch main activity
Intent i = new Intent(LoginActivity.this, MainActivity.class);
startActivity(i);
// close this activity
finish();
}
//Update the progress
#Override
protected void onProgressUpdate(Integer... values)
{
prgDialog.setProgress(values[0]);
}
}
As stated in this question you most often wont know the size of the stream in advance https://stackoverflow.com/a/1119346/2122552
The stated answer also links to an api to get Filesizes. But with a RESTful API you usually dont know the exact size of the Inputstream.
But, however, if you know the size you can break it down to use 100 as 100% and calculate the progress as (downloadedBytes/fileSizeInBytes * 100). Otherwise just use an indeterminate ProgressBar.
You can check the case and make the progressbar indeterminate when you dont know the size of the answer, and otherwise calculate the progress and update it like shown in the official documentation

Categories

Resources