I have a problem. When I click a button I have to download a main page from a website (the source). Then I have to parse the source to get other links from it. After that I have to add as many rows to my list view as I have found links in the main page source. And finally I have to download each link (the source again) and parse them. During the downloading / parsing I have to update my list view (the progressbar for example) with the information I get from these sources.
But how do I do that?
I thought I could just create two classes which both extends the AsyncTask. A MainPageDownloader and a PageDownloader. The MainPageDownloader would be started on button click. It downloads the main page and in the onPostExecute method it will parse the source and add the rows to the list. And then it will start the PageDownloaders.
I tried that but the PageDownloaders will start when the list has not even been updated yet. So I cannot update the ProgressBar's in each row.
What am I doing wrong? Is there maybe a whole different and better way?
Here are the two classes :
public class MainPageDownloader extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... params) {
InputStream in = null;
final int BUFSIZE = 1024;
String result = "";
try {
URL url = new URL( params[0] );
URLConnection con = url.openConnection();
con.connect();
in = con.getInputStream();
byte[] data = new byte[BUFSIZE];
while (in.read(data) != -1) {
result += new String(data);
}
} catch (MalformedURLException e) {
cancel(true);
} catch (IOException e) {
cancel(true);
}
return result;
}
#Override
protected void onPostExecute(String result) {
List<String> links = new PageParser(result).getPageLinks();
super.onPostExecute(result);
int rows = listView.getChildCount();
//Add items & update list
for( int i = 0; i < links.size(); i++ )
adapter.add( new Item() );
for( int i = 0; i < links.size(); i++ ){
new PageDownloader(rows+i).execute("http://www.mylink.com/" + links.get(i) );
}
}
}
public class PageDownloader extends AsyncTask<String, Integer, String>{
ProgressBar p;
int row;
public PageDownloader(int row) {
//p is null, I have to comment it out or the program will crash
//p = (ProgressBar) listView.getChildAt( row ).findViewById( R.id.progressBar1 );
this.row = row;
}
#Override
protected String doInBackground(String... params) {
InputStream in = null;
final int BUFSIZE = 1024;
String result = "";
try {
URL url = new URL( params[0] );
URLConnection con = url.openConnection();
con.connect();
in = con.getInputStream();
byte[] data = new byte[BUFSIZE];
while (in.read(data) != -1) {
result += new String(data);
}
} catch (MalformedURLException e) {
cancel(true);
} catch (IOException e) {
cancel(true);
}
return result;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
PageParser parser = new PageParser( result );
//Somehow the list is updated now and the titles will change
listItems.get(row).setTitle( parser.getTitle() );
adapter.notifyDataSetChanged();
//Not Possible because p is always null
//p.setVisibility( ListView.GONE );
}
}
Related
I have a threading issue. When I try to write in TextView percentage of successful download, it doesn't update it at all, until the end (until all content received) and it just show 100 at the end.
Seems like it is not actually running in another thread...
I tried to use logging in console instead of using publishProgress, and it works. It seems like MainActivity is frozen until the download task is done.
public class DownloadTask extends AsyncTask<String, Integer, 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(in);
int count = 0;
int size = 0;
while (reader.read() != -1) {
size++;
}
urlConnection = (HttpURLConnection)url.openConnection();
in = urlConnection.getInputStream();
reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
int progress = (int) (((float) count++ / (float) size) * 100);
publishProgress(progress);
data = reader.read();
}
return result;
}
catch(Exception e) {
e.printStackTrace();
return "Failed";
}
}
#Override
protected void onProgressUpdate(Integer... values) {
textView.setText((values[0]).toString());
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text);
DownloadTask task = new DownloadTask();
String result = null;
try {
result = task.execute("https://stackoverflow.com/").get();
}
catch (Exception e) {
e.printStackTrace();
}
Log.i("Contents Of URL", result);
}
Any help please?
You're using the get method in the ASyncTask, as per the docs.
Waits if necessary for the computation to complete, and then retrieves
its result.
That means you told the async task to run sincronously.
To have it running async, don't use the get method.
task.execute("https://stackoverflow.com/")
And use the onPostExecute to retrieve the result:
protected void onPostExecute(String result) {
}
i want to download the html content of a website using asynctask, and use regex to manipulate the source code to get what i need and finally i want to display those result in a list view. this is my code it doesnt show error but when i run it on my emulator the app crashes
please guys i need assistant this is really important
public class DownloadTask 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(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 null;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView myLV = (ListView)findViewById(R.id.teamLV);
ArrayList<String> clubName = new ArrayList<String>();
DownloadTask task = new DownloadTask();
String result = null;
try {
result = task.execute("https://www.premierleague.com/clubs").get();
//Log.i("Content of URL", result);
System.out.println(result);
Pattern p = Pattern.compile("class=\"clubName\">(.*?)<");
Matcher m = p.matcher(result);
while(m.find()){
System.out.println(m.group(1));
clubName.add(m.group(1));
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_activated_1, clubName);
myLV.setAdapter(arrayAdapter);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
try adding onPostExecute after doInBackground. then remove the part from execute.get(). The get method makes the UI blocking (which kinda makes the asynctask pointless).
also preset your adapter instead of creating a new one each time you do a loop. you might need a custom adapter (depending on what you need).
#Override
protected void onPostExecute(String result) {
//Log.i("Content of URL", result);
System.out.println(result);
Pattern p = Pattern.compile("class=\"clubName\">(.*?)<");
Matcher m = p.matcher(result);
while(m.find()){
System.out.println(m.group(1));
// clubName.add(m.group(1));
adapter.add (m.group(1));
}
}
I have seen one similar question to this, but i couldn't solve my problem like he did.
Here i'm getting data from url:
public class AsyncHttpTask extends AsyncTask<String, Void, Integer> {
#Override
protected void onPreExecute() {
setProgressBarIndeterminateVisibility(true);
}
#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();
// 200 represents HTTP Ok
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);
}
parseResult(response.toString());
result = 1; // Successful
} else {
result = 0; //"Failed to fetch data!";
}
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage());
}
return result; //"Failed to fetch data!";
}
#Override
protected void onPostExecute(Integer result) {
// Download complete. Let us update UI
progressBar.setVisibility(View.GONE);
if (result == 1) {
giftListAdapter = new GiftListAdapter(GiftsActivity.this, gifts);
recyclerView.setAdapter(giftListAdapter);
} else {
SuperActivityToast.create(GiftsActivity.this, getString(R.string.no_internet_connection),
SuperToast.Duration.SHORT, Style.getStyle(Style.RED, SuperToast.Animations.FLYIN)).show();
}
}
}
private void parseResult(String result) {
try {
JSONObject response = new JSONObject(result);
JSONArray posts = response.optJSONArray("gifts");
gifts = new ArrayList<>();
for (int i = 0; i < posts.length(); i++) {
JSONObject post = posts.optJSONObject(i);
GiftItem item = new GiftItem();
item.setThumbnail(post.optString("image"));
item.setTitle(post.optString("title"));
item.setDescription(post.optString("description"));
item.setSource(getString(R.string.source) + " " + post.optString("source"));
item.setTotalRating(post.optInt("rating"));
item.setPrice(post.optDouble("price"));
gifts.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
And here i'm executing that url. I'm trying now to parse this second url and load all items after first data is loaded:
new AsyncHttpTask().execute(url_movies);
new AsyncHttpTask().execute(url_books); // This is the second url i'm trying to get
How could i do that?
I'm trying now to parse this second url and load all items after first
data is loaded:
Then instead of calling execute method just after first, call it inside onPostExecute method when first url all items are loaded successfully.
Also add second call in if-else block to avoid it execute again :
#Override
protected void onPostExecute(Integer result) {
// Download complete. Let us update UI
progressBar.setVisibility(View.GONE);
... your code here
if(params[0].equals(url_movies)){
new AsyncHttpTask().execute(url_books);
}
}
also add
If you want both urls than send them as an String array like this
String urls[] = new String[]{"url1" , "url2"};
new AsyncHttpTask().execute(urls);
and in doinbackground method exec them like
url1 = params[0];
url2 = params[1];
i have create an android application on where the user can select the start and end point of the location.
This application will use the Google-Direction web service and make the HTTPRequest.
I will make this as short, I want to call the asynctask method in the JSONParser class from the main_activity.
The issue is, I don't know how to display the result in the main_activtiy method
here is the asynctask method
public class JSONParser {
InputStream is = null;
JSONObject jObj = null;
String json = "";
public JSONParser() {
}
public void getJSONFromUrl(final String url, final responseListener target) {
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... params) {
HttpURLConnection httpURLConnection = null;
StringBuilder stringBuilder = new StringBuilder();
try {
httpURLConnection = (HttpURLConnection) new URL(url).openConnection();
InputStreamReader inputStreamReader = new InputStreamReader(httpURLConnection.getInputStream());
int read;
char[] buff = new char[1024];
while ((read = inputStreamReader.read(buff)) != -1) {
stringBuilder.append(buff, 0, read);
}
return stringBuilder.toString();
} catch (MalformedURLException localMalformedURLException) {
return "";
} catch (IOException localIOException) {
return "";
} finally {
if (httpURLConnection != null)
httpURLConnection.disconnect();
}
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
target.onResponseComplete(result);
}
}.execute();
}
here is how the main method is calling the method
new JSONParser().getJSONFromUrl(url, new responseListener() {
#Override
public void onResponseComplete(String response) {
try {
ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
JSONArray step = new JSONObject(response).getJSONArray("routes").getJSONObject(0).getJSONArray("legs")
.getJSONObject(0).getJSONArray("steps");
for (int i = 0; i < step.length(); i++) {
HashMap<String,Object> row = new HashMap<String,Object>();
row.put("Distance", step.getJSONObject(i).getJSONObject("distance").getString("text"));
list.add(row);
}
}catch (Exception e){
e.printStackTrace();
}
}
});
}
the issue right know is how i want to display the Arraylist List value and put it into the TextView call jarak
You can change your List to be
ArrayList<HashMap<String, String>>
as you are getting a string from
step.getJSONObject(i).getJSONObject("distance").getString("text")
To get it out you can use (assuming your textview is called jarak)
for(HashMap<String,String> map : list) {
for(Entry<String, String> entry : map.entrySet()) {
jarak.setText(entry.getKey() + ", " + entry.getValue());
}
}
Hope that helps
In my custom ListView contains two textview and one Imageview im using AsyncTask to read the Text from Internet same with the imageView .As im reading and assigning all three view elemnt at the same time it takes to much time . In such case ineed to Convert url to Bitmap in another AsyncTask when the text part is done.
As a logic it recquire some concept of updating my ImageView resource .But i do not
know how to do it....
Thanks In Advance..
private class AsynchTask extends AsyncTask<Void, Integer, Void> {
URLConnection tc;
BufferedReader in;
URL twitter;
int num=0;
#Override
protected void onPreExecute() {
super.onPreExecute();
try {
mProgressBar.setVisibility(View.VISIBLE);
} catch (Exception e) {
Log.e(TAG,""+e.getMessage());
}
}
#Override
protected Void doInBackground(Void... params) {
try{
twitter = new URL("https://twitter.com/statuses/public_timeline.json");
tc = twitter.openConnection();
my = new ArrayList<HashMap<String,Object>>();
in = new BufferedReader(new InputStreamReader(
tc.getInputStream()));
ImageList=new ArrayList<String>();
while ((line = in.readLine()) != null) {
JSONArray ja = new JSONArray(line);
for (int i = 0; i < ja.length(); i++) {
JSONObject jo = (JSONObject) ja.get(i);
/**Data Insert into the HashMap Object*/
hm=new HashMap<String, Object>();
hm.put(TEXT,jo.getString("text"));
hm.put(USER,jo.getJSONObject("user").getString("name"));
// String str=jo.getJSONObject("user").getString("profile_image_url"); hm.put(URL,"http://twitter.com/#!/"+jo.getJSONObject("user").getString("screen_name"));
// hm.put(IMAGEURL,getDrawable_from_url(str));
ImageList.add(jo.getJSONObject("user").getString("profile_image_url"));
Log.e(TAG,""+num);
my.add(hm);
num++;
Log.e("Count",""+num);
publishProgress(num);
}
num++;
publishProgress(num);
}
} catch (Exception e) {
Log.e(TAG,""+e.getMessage());
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
mProgressBar.setProgress(values[0]);
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
mProgressBar.setProgress(0);
mProgressBar.setVisibility(View.GONE);
adapter = new Simpleadapter(HelloWorldActivity.this, my, R.layout.listcontent,
new String[]{TEXT,USER}, new int[]{R.id.text2,R.id.text1});
listView.setAdapter(adapter);
new AsynchTaskForImageLoading().execute();
}
}
/**Method to convert Url to the Bitmap*/
private Bitmap getDrawable_from_url(String url) {
try{
Bitmap x;
HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection();
connection.setRequestProperty("User-agent","Mozilla/4.0");
connection.connect();
InputStream input = connection.getInputStream();
x = BitmapFactory.decodeStream(input);
return x;
}
catch (Exception e) {
Log.e(TAG,""+e.getMessage());
return null;
}
}
I've used this LazyList with great success: https://github.com/thest1/LazyList
For your needs, you can swap out the supplied stub image with the one you'd like to use. I've also used a 1x1 blank png to show no image.
Also, one change that i've made in my code and that I strongly suggest when using this package is to change the code from using the SD card to use the built in cache. You do this by modifying the FileCache.java file from using .getExternalStorageDirectory() to .getCacheDir().
Hope this helps.