How to edit views when waiting for a thread? - android

I load my articles from my wordpress webpage. And want to display them in my app.
In order to be allowed to wait for a internet response I had to create a Thread.
Using this method:
private void loadArticles(final String url) {
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
//Get my data and run createArticles();
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
Then in the createArticles function I try to use my function addViewToParent(...) and I get an error that says:
Only the original thread that created a view hierarchy can touch its
views.
How can i work around this problem?
EDIT: I use these networking functions if it matters...
//Connect to the url
URL pageURL = new URL(url);
HttpURLConnection connection = (HttpURLConnection) pageURL.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream())
);

If you want to modify your Views, e.g. show your article, you have to run the code on the UI/main thread. To achieve this, you could call run runOnUiThread() in your Activity:
private void loadArticles(final String url) {
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
//Get my data ...
runOnUiThread(new Runnable() {
public void run() {
// modify Views here
createArticles();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}

You need to use function runOnUiThread. This is function for user interface thread.
private void loadArticles(final String url) {
//Get my data ...
runOnUiThread(new Runnable() {
public void run() {
// modify Views here
createArticles();
}
});
});

Just use a Handler instead, so you'll have access to the UI Thread:
new Handler().post(new Runnable(){
#Override
public void run() {
try {
//Get my data and run createArticles();
} catch (Exception e) {
e.printStackTrace();
}
}
});

Related

Two jsoup scrapers in one Android app doesn't work

I'm developing a simple Android application that has to scrape content of one website and then add this to the URL of another website that I have to scrape. The first scraping is okay, but the second gives me an error: "HTTP error fetching URL". The second URL is fine because when I give it to the first scraper everything is okay (but the URL is changing, so I cannot use it as a constraint). I think that I have to finish the thread of the first scraper somehow, but I don't know how.
My current code:
private void getBodyText() {
new Thread(new Runnable() {
#Override
public void run() {
final StringBuilder builder = new StringBuilder();
try {
String url="http://example.com";
Document doc = Jsoup.connect(url).get();
Element body = doc.body();
builder.append(body.text());
} catch (Exception e) {
builder.append("Error : ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(builder.toString());
token1=builder.toString();
checkPairing();
}
});
}
}).start();
}
private void checkPairing() {
new Thread(new Runnable() {
#Override
public void run() {
final StringBuilder builder = new StringBuilder();
try {
String url="http:example.com/"+token1;
Document doc = Jsoup.connect(url).get();
Element body = doc.body();
builder.append(body.text());
} catch (Exception e) {
builder.append("Error : ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
if (builder.toString()!="Not Found") {
tokenPar = builder.toString();
}
}
});
}
}).start();
}
I've also tried to execute the second function directly from onCreate() after the first scraper is executed but nothing changed.

How to read value from website

I just want to read (-1) value which is the only value in website but I am not able to fetch this value Can any buddy guide me how to do that. I am getting the value of API url when I am pasting it in web browser and android is not fetching it. Link of API is given below.
Link OF API
Code I am trying is:
private void getWebsite() {
new Thread(new Runnable() {
#Override
public void run() {
final StringBuilder builder = new StringBuilder();
try {
Document doc = Jsoup.connect("https://api.thingspeak.com/channels/411172/feeds.json?results=1").get();
String title = doc.title();
Elements links = doc.select("[pre]");
builder.append(title).append("\n");
for (Element link : links) {
builder.append("\n").append("Link : ").append(link.attr("pre"))
.append("\n").append("Text : ").append(link.text());
}
} catch (IOException e) {
builder.append("Error : ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
result.setText(builder.toString());
}
});
}
}).start();
}
Screen shot of web API call in browser
Error I am getting is Error: HTTP error fetching URL
As I see response from your API is JSON formatted you have to modify your code as follow
private void getWebsite() {
new Thread(new Runnable() {
#Override
public void run() {
final StringBuilder builder = new StringBuilder();
try {
Document doc = Jsoup.connect("https://api.thingspeak.com/channels/411172/feeds.json?results=1")
.ignoreContentType(true)
.get();
String json = doc.body().text();
builder.append(json);
} catch (IOException e) {
builder.append("Error : ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
result.setText(builder.toString());
}
});
}
}).start();
}

How to prevent a ProgressBar from sticking?

In my app I'm getting some TEXT from a Website by ion library and I'm using a progressBar to show the progress of downloading that data.
But my main issue is that in onComplete I implemented some methods that work with the TEXT I've got from the website these are some cyclic methdods that use lot's of for and other stuff and actually my progressBar at the beginning works properly, but when it's complete downloading the data the progressBar just sticks until all the methods are complete in onComplete().
I would that the progressBar runs anyway and doesn't get stuck without removing methods from onComplete() is it possible?
Here is my function where I use ion library that I invoke in the onClick() event:
private void getHTML(){
progressDialog = new SpotsDialog(MainActivity.this, R.style.Custom);
progressDialog.show();
Ion.with(getApplicationContext())
.load("IP")
.asString()
.setCallback(new FutureCallback<String>() {
#SuppressLint("SetTextI18n")
#Override
public void onCompleted(Exception e, String result) {
htmlresultart = result;
htmlresultart = htmlresultart.replace("</td>", "\n");
getTable();
getHeader();
getBody();
progressDialog.cancel();
}
});
}
If the methods called in the onCompleted() callback take too much to execute then they need to be run on a background thread. In this situation it doesn't make sense to use a callback with Ion, instead you should synchronously fetch the data and after this do all the other tasks, all on a single background thread, something like below:
private void getHTML(){
progressDialog = new SpotsDialog(MainActivity.this, R.style.Custom);
progressDialog.show();
// start a background thread
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
String htmlresultart = null;
try {
String htmlresultart = Ion.with(getApplicationContext())
.load("IP")
.asString()
.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
// if htmlresultart is null at this point, an exception occured and the string couldn't be fetched so you most likely should abort the following processing.
if (htmlresultart != null) {
htmlresultart = htmlresultart.replace("</td>", "\n");
getTable();
getHeader();
getBody();
progressDialog.cancel();
}
}
});
}

Android : How to set image with url by a subroutine

I'm creating a subroutine to get an image using a url. Here is a similar subroutine that I used to parse text from an XML into my UI:
public void loading(int index) {
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
try {
arrayList = XMLPullParser.parse("http://localhost/news.xml", "news", 1, 2, 3);
//URL url = new URL("http://localhost/"+arrayList2.get(1).toString());
//final Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
handler.post(new Runnable() {
public void run() {
chk1.setText(arrayList.get(0).toString());
chk2.setText(arrayList.get(1).toString());
chk3.setText(arrayList.get(2).toString());
try {
img1.setImageBitmap(bitmap("http://localhost/1.jpg"));
img2.setImageBitmap(bitmap("http://localhost/2.jpg"));
img3.setImageBitmap(bitmap("http://localhost/3.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
});
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}).start();
}
Here is the change I made to load the images:
static Bitmap bmp;
public Bitmap bitmap(String url_input) throws IOException {
final String get_url = url_input;
new Thread(new Runnable() {
#Override
public void run() {
try {
final URL url = new URL(get_url);
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
return bmp;
}
The subroutine works when parsing text but doesn't work properly when loading the bitmaps. I need to set images to 3 image buttons and want to use a subroutine to do it.
I know it should not use static for my bmp variable, it's just a test to let me know if it works.
Your bitmaps are not displayed because your threading setup is incorrect. Your bitmap method returns before thread it started has finished. Also you are using static variable used by all threads.
I recommend to use AsyncTask and do all your background work there - there is no need to spawn separate threads for every image. Also pay attention to assign values to your checkboxes and images in onPostExecute method because these can be assigned only in main (gui) thread.
You could do it something like this. This asserts that you have the code in an activity. But the thread handling should probably be changes to use an AsyncTask instead.
bitmap(img1, "http://localhost/1.jpg");
.
.
.
public void bitmap(final ImageView imageView, String url_input) throws IOException {
final String get_url = url_input;
new Thread(new Runnable() {
#Override
public void run() {
try {
final URL url = new URL(get_url);
final Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
if (bmp != null) {
runOnUiThread(new Runnable() {
#Override
public void run() {
imageView.setImageBitmap(bmp);
}
});
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}

Using view elements inside thread

I'm trying to do a simple HTTP request in Android. It has to be in separate theread. But how can I operate on the view controls inside the thread?
Here's what I have now:
public void saveData(final View v)
{
Button btn = (Button) v.findViewById(R.id.button);
btn.setText("Saving...");
new Thread() {
public void run()
{
HttpURLConnection connection = null;
try {
URL myUrl = new URL("http://example.com");
connection = (HttpURLConnection)myUrl.openConnection();
InputStream inputStream = connection.getInputStream();
final String fResponse = IOUtils.toString(inputStream);
}
catch (MalformedURLException ex) {
Log.e("aaa", "Invalid URL", ex);
}
catch (IOException ex) {
Log.e("aaa", "IO Exception", ex);
}
finally {
if (connection != null) {
connection.disconnect();
}
}
// How can I access v and btn here?
// btn.getText("Saved, thanks.");
// btn.setText("Saved, thanks.");
}
}.start();
}
To elaborate what I'm trying to achieve:
I have a text box and a button. Once the button is clicked, I want to get the text from text box, use in the URL, wich returns a value, then update the button text with this value.
Here's an example on how you could do it.
public class YourClass extends Activity {
private Button myButton;
//create an handler
private final Handler myHandler = new Handler();
final Runnable updateRunnable = new Runnable() {
public void run() {
//call the activity method that updates the UI
updateUI();
}
};
private void updateUI()
{
// ... update the UI
}
private void doSomeHardWork()
{
//update the UI using the handler and the runnable
myHandler.post(updateRunnable);
}
private OnClickListener buttonListener = new OnClickListener() {
public void onClick(View v) {
new Thread(new Runnable() {
doSomeHardWork();
}).start();
}
};
}
As you can see, you need to update the UI with yet another Runnable object. This is one way of doing it.
Another option is via the runOnUiThread function
runOnUiThread(new Runnable()
{
#Override
public void run() {
updateActivity();
}
});
If you try to access your Views directly from another thread like that, you will get an exception because all UI operations must be performed on the main thread.
One method that the Android SDK provides for performing background tasks that need to update the UI is the AsyncTask.
The onPostExecute() method of an AsyncTask is called after doInBackground() returns, and is run on the UI thread.
Your AsyncTask might look something like this:
public class MyBackgroundTask extends AsyncTask<URL, Void, String> {
protected String doInBackground(URL... urls) {
URL myUrl = new URL("http://example.com");
connection = (HttpURLConnection)myUrl.openConnection();
InputStream inputStream = connection.getInputStream();
return IOUtils.toString(inputStream);
}
protected void onPostExecute(String result) {
// Call back to your Activity with the result here
}
}

Categories

Resources