I'm trying to write my first Android application and need to get a webpage's text as string to display it in a TextView. I found a few samples on StackOverflow but none of them seems to work for me for some reason. When I click the button to retrieve the text the app crashes. Here's what I've got now (based on the code from Get text from web page to string):
The MainActivity.java file
public class MainActivity extends ActionBarActivity {
Button testbutton;
Button btnReset;
TextView serverMsgViewComponent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addListenerOnButton();
}
public void addListenerOnButton() {
testbutton = (Button) findViewById(R.id.btnClickme);
btnReset = (Button) findViewById(R.id.btnResetText);
serverMsgViewComponent = (TextView) findViewById(R.id.serverMsgView);
serverMsgViewComponent.setText("Custom text");
final ReadWebpageAsyncTask readpage = new ReadWebpageAsyncTask();
btnReset.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
serverMsgViewComponent.setText("Server message placeholder");
}
});
testbutton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
serverMsgViewComponent.setText("Retrieving message from server...");
readpage.readWebpage();
}
});
}
//some default code here
}
And ReadWebpageAsyncTask.java
public class ReadWebpageAsyncTask extends Activity {
private TextView textView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.serverMsgView);
}
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result) {
textView.setText(Html.fromHtml(result));
}
}
public void readWebpage() {
DownloadWebPageTask task = new DownloadWebPageTask();
task.execute(new String[] { "http://hglstudio.com/workspace/server.htm" });
}
}
So, I said I copied code from another SO discussion and this code didn't work for me and I needed help figuring out why. Instead I got my question marked as a duplicate of the other one from which I took my code and my question was also downvoted. Thank you, StackOverflow!
Now, I found the problem myself (happily!). And problem was with the domain name which was not getting resolved to the IP address for some reason and then threw an error. The solution was to first "initialize" the domain by accessing the url once, and then try downloading the text in the second attempt.
So I'm calling this function first:
private void initializeDns(String url) {
try {
InetAddress address = InetAddress.getByName(url);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
Related
Whenever I execute data function it stores the correct value of QUERY but when i get the JSON back. It gives me the result of last value rather than giving me the result of new value. Something is wrong in function data or function async.
There is no error which that I give you my error log.The QUERY string holds the right value but result is of last string.
public class MainActivity extends AppCompatActivity{
public static String QUERY = null;
public static String DATA = null;
SpeechRecognizer speechRecognizer;
Intent speechIntent;
TextView textView;
Button button;
TextView textView1;
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
textView = (TextView) findViewById (R.id.text);
textView1 = (TextView) findViewById (R.id.text1);
requestPermissions (new String[]{Manifest.permission.INTERNET, Manifest.permission.RECORD_AUDIO}, 10);
speechRecognizer = SpeechRecognizer.createSpeechRecognizer (this);
speechRecognizer.setRecognitionListener (new RecognitionListener () {
#Override
public void onReadyForSpeech(Bundle bundle) {
}
#Override
public void onBeginningOfSpeech() {
}
#Override
public void onRmsChanged(float v) {
}
#Override
public void onBufferReceived(byte[] bytes) {
}
#Override
public void onEndOfSpeech() {
}
#Override
public void onError(int i) {
}
#Override
public void onResults(Bundle bundle) {
ArrayList<String> arrayList = bundle.getStringArrayList (SpeechRecognizer.RESULTS_RECOGNITION);
if(arrayList!=null){
textView.setText (arrayList.get (0));
QUERY = arrayList.get (0);
}else {
Toast.makeText (MainActivity.this, "Array List is null", Toast.LENGTH_SHORT).show ();
}
}
#Override
public void onPartialResults(Bundle bundle) {
}
#Override
public void onEvent(int i, Bundle bundle) {
}
});
speechIntent = new Intent (RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
speechIntent.putExtra (RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
speechIntent.putExtra (RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault ());
}
public void start(View v) {
speechRecognizer.startListening (speechIntent);
}
public void data(View v){
Toast.makeText (this, QUERY, Toast.LENGTH_SHORT).show ();
Async async = new Async ();
async.execute ();
if(DATA!=null){
textView1.setText (DATA);
}
} }
class Async extends AsyncTask<Void, Void, Void>{
String line = "";
String data = "";
#Override
protected Void doInBackground(Void... voids) {
try {
data=null;
Log.e("Query in url", MainActivity.QUERY);
URL url = new URL ("https://api.dialogflow.com/v1/query?v=20150910&contexts=[]&lang=en&query="
+ MainActivity.QUERY +"&sessionId=bee67580-d05c-47f6-8d64-a6218c3913e1");
URLConnection httpURLConnection = url.openConnection ();
httpURLConnection.setRequestProperty ("Authorization", "Bearer
CONFIDENTIAL KEY");
InputStream inputStream = httpURLConnection.getInputStream ();
BufferedReader bufferedReader = new BufferedReader (new
InputStreamReader (inputStream));
while ((line = bufferedReader.readLine ()) != null) {
data += line;
}
} catch (MalformedURLException e) {
Log.i ("PROBLEM", "URL");
} catch (IOException e) {
Log.i ("PROBLEM", "IOEXCEPTIONe");
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
MainActivity.DATA = data;
super.onPostExecute (aVoid);
} }
Problem is you are calling a AsyncTask and right after it access same Variable which is modifying inside AsynCtask.
Async async = new Async ();
async.execute ();
if(DATA!=null){
textView1.setText (DATA);
}
Here async will execute on background thread but Main thread continues So last DATA value will set each time .
Solution
You better move setText() code to onPostExecute().onPostExecute()
runs on Main Thread so you can easily access Ui element inside it .
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute (aVoid);
MainActivity.DATA = data;
if(DATA!=null){
textView1.setText (DATA);
}
}
You are setting the text before async finishes to execute. You are calling
async.execute ();
if(DATA!=null){ textView1.setText (DATA);
async.execute returns right away, so DATA still has the old value.
What you have to do is set the textView text in onPostExecute function.
So i got a project with the following activities : MainActivity/GetJson/ TimerActivity.
GetJson activity :
public class GetJson extends AppCompatActivity {
String JSON_STRING;
String json;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void getJSON(View view){
new BackgroundTask().execute();
}
public class BackgroundTask extends AsyncTask<Void,Void,String> {
String json_url;
#Override
protected void onPreExecute() {
json_url="http://10.10.103.36/projet/php/fichier.php";
}
#Override
protected String doInBackground(Void... params) {
try {
URL url=new URL(json_url);
HttpURLConnection httpURLConnection=(HttpURLConnection)url.openConnection();
InputStream inputStream=httpURLConnection.getInputStream();
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder=new StringBuilder();
while ((JSON_STRING= bufferedReader.readLine())!=null){
stringBuilder.append(JSON_STRING+"\n");
}
bufferedReader.close();
inputStream.close();;
httpURLConnection.disconnect();
return stringBuilder.toString().trim();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
json=result;
}
}
}
Timer Activity
public class TimerActivity extends Activity {
private TextView test;
String msg = "Hey";
private Handler mHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
test = (TextView) findViewById(R.id.compteur);
Timer timer = new Timer();
TimerTask tt = new TimerTask()
{
#Override
public void run()
{
test.setText(msg);
}
};
timer.scheduleAtFixedRate(tt,5000,1000); // Delay 5 seconds on the first run
// then run every second
test.setText(msg);
setContentView(R.layout.activity_main);
}
}
In my xml main activity i got 2 textview :
- compteur : to display a text from my timeractivity
- textViewJson : to display my json
I think my methods to get json( from GetJson) and display text(from TimerActivity) are correct. But the problem is that i can't setText from others activities to my main activity.
I don't have any compilation problem bu my textView aren't getting updated.
I tried both in GetJson and TimerActivity to just do :
TextView test;
test = (TextView) findViewById(R.id.compteur);
test.setText(msg);
In order to check if i can change the textview text without even using the returned values and nothing happens.
Any ideas ?
Have a good day !
Once you have the information you want to show in your TVs you should save it somewhere and load it when your Activity is created. You can't change the state of Views in a destroyed Activity. Use Intents (putExtra();) to pass data between your Activies or use SharedPreferences
I know this is a duplicate question but please hold on. I have read some similar questions and answer but none of them seems working for me.
What to do:
I have to do a search which will send a request to a web service and receive a response.
As i can't consume network on UI thread, I used AsyncTask.
What i tried:
I tried using task.execute() this returns immediately without even showing progressdialog box and i receive response as null (set in onPostExecute)
if i use task.execute.get() then it freezes screen and again no dialog box shows up (but i receive response correctly).
Below is my code with task.execute. Kindly correct me.
public class LookIn extends AppCompatActivity implements View.OnClickListener{
private Button btn=null;
private TextView txtPinCode=null;
private Service service=null;
private final static int timeout=20;
private String jsonResponse;
//private ProgressBar helperSearchProgressBar;
private String pincode="";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_look_in);
btn=(Button)findViewById(R.id.button);
btn.setOnClickListener(this);
txtPinCode=(TextView) findViewById(R.id.txtPinCode);
this.service=(Service) ParamFactory.getParam(ConstantLabels.SELECTED_SERVICE_ID);
// this.helperSearchProgressBar=(ProgressBar)findViewById(R.id.helperSearchProgressBar);
}
#Override
public void onClick(View v) {
String pincode= txtPinCode.getText().toString();
if(pincode==null || pincode.isEmpty() || pincode.length()!=6)
{
this.txtPinCode.setError("Please enter a 6 degit pin code from 700000 to 700200");
return;
}
ParamFactory.setParam(ConstantLabels.PINCODE_ID,pincode);
this.pincode=pincode;
loadHelper();
Intent intent= new Intent(LookIn.this,SearchResult.class);
startActivity(intent);
}
public void setJsonResponse(String jsonResponse)
{
this.jsonResponse=jsonResponse;
}
private void loadHelper()
{
Log.v("Callme", "Running thread:" + Thread.currentThread().getId());
ArrayAdapter<User> adapter=null;
String params=this.pincode+","+this.service.getId();
List<User> result=null;
try {
new CallmeGetHelperAsyncTask().execute(params); //my task.execute()
result= RestUtil.getUserList(jsonResponse);
adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, result);
ParamFactory.setParam("getHelperForService", adapter);
}
catch(JSONException x)
{
Log.e("Callme", Log.getStackTraceString(x));
}
}
class CallmeGetHelperAsyncTask extends AsyncTask<String,Void,String > {
// private Context context=null;
private ProgressDialog dialog=null;
private String jsonResponse;
private LookIn activity;
public CallmeGetHelperAsyncTask(){}
public CallmeGetHelperAsyncTask(LookIn activity)
{
this.activity=activity;
}
#Override
protected void onPreExecute() {
this.dialog= new ProgressDialog(LookIn.this);
this.dialog.setMessage("Loading...");
this.dialog.show();
Log.v("Callme","Dialog Shown");
}
#Override
protected void onPostExecute(String s) {
if(s!=null)
{
this.activity.setJsonResponse(s);
}
else
{
Log.v("Callme","kill me");
}
if(this.dialog.isShowing())
{
Log.v("Callme","Closing Dialog");
this.dialog.dismiss();
}
}
#Override
protected String doInBackground(String... params) {
Log.v("Callme","From Background:"+Thread.currentThread().getId());
String pincode=params.clone()[0].split(",")[0];
String serviceId=params.clone()[0].split(",")[1];
String url=String.format(URL.GET_HELPER,serviceId,pincode);
jsonResponse= null;
try {
jsonResponse = RestUtil.makeRestRequest(url);
} catch (IOException e) {
e.printStackTrace();
}
return jsonResponse;
}
}
}
Note: I haven't tried using while loop to waiting for the asynctask, because i think that will also end up freezing my screen. Please correct me if i am wrong
I haven't tried using while loop to waiting for the asynctask
No need to use loop for waiting AsyncTask Result.
Because onPostExecute method execute after doInBackground so instead of using jsonResponse just after call of execute method, do it inside setJsonResponse method, because this method called from onPostExecute which always run on Main UI Thread:
public void setJsonResponse(String jsonResponse)
{
this.jsonResponse=jsonResponse;
//Create adapter object here
result= RestUtil.getUserList(jsonResponse);
adapter = new ArrayAdapter(...);
ParamFactory.setParam("getHelperForService", adapter);
}
I've just started development with Android and I have little experience in Java. I've got a button listener in my main Activity but I want to do a background task that updates an TextView in my UI. See the following code.
btnJSON.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
new BGTask().execute();
}
class BGTask extends AsyncTask<Void, Void, String> {
protected String doInBackground(Void... params) {
Thread.sleep(2000);
String x = "test";
return (String) x;
}
protected void onPostExecute(String result) {
tvData.setText(result);
}
}
});
This code works, however, when I move the code for the BGTask code to a seperate class file, its no longer possible to update the UI component tvData. How do a pass a reference to that object to the BGTask class?
Thanks!
What you need to do, if you want to move your task class to another file, is this:
Add a TextView field to BGTask and a constructor that takes a TextView.
Pass in the TextView you want to update.
Here is the code:
public class BGTask extends AsyncTask<Void, Void, String> {
private TextView tvData = null;
public BGTask(TextView tv) {
this.tvData = tv;
}
protected String doInBackground(Void... params) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String x = "test";
return (String) x;
}
protected void onPostExecute(String result) {
if (tvData != null)
tvData.setText(result);
}
}
And your activity will look like:
Button button = (Button) findViewById(R.id.button);
TextView tv = (TextView) findViewById(R.id.textview);
final BGTask task = new BGTask(tv);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
task.execute();
}
});
Basically I'm wondering how I'm able to do what I've written in the topic. I've looked through many tutorials on AsyncTask but I can't get it to work. I have a little form (EditText) that will take what the user inputs there and make it to a url query for the application to lookup and then display the results.
What I think would seem to work is something like this: In my main activity i have a string called responseBody. Then the user clicks on the search button it will go to my search function and from there call the GrabUrl method with the url which will start the asyncdata and when that process is finished the onPostExecute method will use the function activity.this.setResponseBody(content).
This is what my code looks like simpliefied with the most important parts (I think).
public class activity extends Activity {
private String responseBody;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initControls();
}
public void initControls() {
fieldSearch = (EditText) findViewById(R.id.EditText01);
buttonSearch = (Button)findViewById(R.id.Button01);
buttonSearch.setOnClickListener(new Button.OnClickListener() { public void onClick (View v){ search();
}});
}
public void grabURL(String url) {
new GrabURL().execute(url);
}
private class GrabURL extends AsyncTask<String, Void, String> {
private final HttpClient client = new DefaultHttpClient();
private String content;
private boolean error = false;
private ProgressDialog dialog = new ProgressDialog(activity.this);
protected void onPreExecute() {
dialog.setMessage("Getting your data... Please wait...");
dialog.show();
}
protected String doInBackground(String... urls) {
try {
HttpGet httpget = new HttpGet(urls[0]);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
content = client.execute(httpget, responseHandler);
} catch (ClientProtocolException e) {
error = true;
cancel(true);
} catch (IOException e) {
error = true;
cancel(true);
}
return content;
}
protected void onPostExecute(String content) {
dialog.dismiss();
if (error) {
Toast toast = Toast.makeText(activity.this, getString(R.string.offline), Toast.LENGTH_LONG);
toast.setGravity(Gravity.TOP, 0, 75);
toast.show();
} else {
activity.this.setResponseBody(content);
}
}
}
public void search() {
String query = fieldSearch.getText().toString();
String url = "http://example.com/example.php?query=" + query; //this is just an example url, I have a "real" url in my application but for privacy reasons I've replaced it
grabURL(url); // the method that will start the asynctask
processData(responseBody); // process the responseBody and display stuff on the ui-thread with the data that I would like to get from the asyntask but doesn't obviously
}
Ignore this answer, I didn't read the comments before posting, but I'll leave the original content here, for reference someone might find useful, maybe.
setResponseBody(String content) should call runOnUiThread():
public void setResponseBody(String content) {
runOnUiThread(new Runnable() {
public void run() {
//set the content here
}
}
}
On Android (and a lot of other GUI toolkits (QT, WinForms, iirc)) you can only modify Views on the thread that created them (the UI thread). Calling runOnUiThread() runs the supplied runnable on this UI thread.