Here I've given a small example of the problem I'm facing with global variables and AsyncTasks. I've gone and read in data from a file and assigned that data to a string and in the onPostExecute() method I assigned that string to the global variable. However when I assign the TextView with the "aString" variable, the output is still "nothing".
I know that if you do the TextView assigning in the onPostExecute() method it works however what if I want to use the data in methods outside of the AsyncTask.
Can someone please help with this, I think I'm not getting something?
public class GoodAsync extends Activity{
TextView tv;
String aString = "nothing";
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.asynctasks);
new AsyncTasker().execute();
tv = (TextView) findViewById(R.id.async_view);
tv.setText(aString);
}
private class AsyncTasker extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... arg0) {
AssetManager am = GoodAsync.this.getAssets();
String string = "";
try {
// Code that reads a file and stores it in the string variable
return string;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
aString = result;
}
}
}
Perhaps you want to do it like this:
public class GoodAsync extends Activity{
TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.asynctasks);
tv = (TextView) findViewById(R.id.async_view);
new AsyncTasker().execute();
}
public void setTextView (String text) {
tv.setText(text);
}
private class AsyncTasker extends AsyncTask<String, Integer, String>{
....
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
setTextView(result);
}
}
}
Are you sure your AsyncTask is executing in time?
e.g You are doing this:
new AsyncTasker().execute();
tv = (TextView) findViewById(R.id.async_view);
tv.setText(aString);
This sets the task going but then immediately sets the value of the TextView to the aString variable.
The AsyncTask is most likely still executing at this point so aString only gets a value other than "nothing" after the code has executed.
You are not waiting for your asynctask to finish..you can do it like this..
new AsyncTasker().execute().get();
tv = (TextView) findViewById(R.id.async_view);
tv.setText(aString);
Related
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
First of all I must say I'am new at Android but not at Java.
I did HttpRequest With AsyncTask.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread th = new Thread(new Runnable() {
#Override
public void run() {
new RequestTask().execute("http://www.url.com/ajaxrequest/?kategori=27");
}
});
th.start();
}
Created Another Class ( Name : RequesTask )
class RequestTask extends AsyncTask<String, String, String>{
private void RequestTask(String URL){
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
// Some Codes Here...
return responseString;
}
#Override
protected String doInBackground(String... uri) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String responseString = null;
// Some Codes Here...
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// My Result is 'result'
}
I want to send and write this string value to TextView In MainActivty. How can i send 'result' ?
Thanks in advance..
Don't open a new thread to run the async task from this thread. It won't work (will fail on internal handler). The async task by himself open for you a new thread.
This is the right code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.your_text_view);
new RequestTask().execute("http://www.url.com/ajaxrequest/?kategori=27");
}
And in your RequestTask
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
Edit: To your question, how to access TextView from AsyncTask
You can do it in many ways. These are part of them:
Define AyncTask as an inner class inside your Activity. You can access members of Activity within AsyncTask. This option is very coupled, means async task which apparently the logic of your app is part of your ui. Like this:
class YouActivity extends Activity {
TextView textView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.your_text_view);
new RequestTask().execute("http://www.url.com/ajaxrequest/?kategori=27");
}
class RequestTask extends AsyncTask<String, String, String> {
...
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
}
}
Deliver the TextView to AsyncTask by constructor or setter method. This option is less coupled, since this AsyncTask can be used by many consumers who want to update their TextView, but the is still coupling by holding reference from AsyncTask to your views.
Your AsyncTask:
class RequestTask extends AsyncTask<String, String, String> {
TextView textView = null;
public void setTextView(TextView textView) {
this.textView = textView;
}
...
#Override
protected void onPostExecute(String result) {
if (textView != null) {
textView.setText(result);
}
}
}
And your activity:
class YouActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.your_text_view);
RequestTask requestTask = new RequestTask();
requestTask.setTextView(textView);
requestTask.execute("http://www.url.com/ajaxrequest/?kategori=27");
}
}
To make your program more loosely coupled and to make better separation of controller from your views, use Handlers:
class RequestTask extends AsyncTask<String, String, String> {
Handler handler = null;
public void setHandler(Handler handler) {
this.handler = handler;
}
...
#Override
protected void onPostExecute(String result) {
if (handler != null) {
Message message = new Message();
message.obj = result;
handler.sendMessage(message);
}
}
}
And your activity:
class YouActivity extends Activity {
TextView textView;
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
String value = (String) msg.obj;
textView.setText(value);
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.your_text_view);
RequestTask requestTask = new RequestTask();
requestTask.setHandler(handler);
requestTask.execute("http://www.url.com/ajaxrequest/?kategori=27");
}
}
Handlers cave tons of options. You can 'send message' from any thread and you can decouple your app very good with this tool.
You can either pass the TextView to RequestTask's constructor or make it a global member. And in your onPostExecute method:
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
yourTextView.setText(result);
}
That's it :)
Edit: Whoops. As sromku correctly pointed out, AsyncTask already performs the doInBackground() method in a separate thread (in background) so you should not be wrapping it in another thread. So, remove that Thread-ception.
best solution
Instead of using so many classes for different types of asynctask , I suggest you use this library
you can have a look at here
http://loopj.com/android-async-http/
your code will become very very less , instead of declaring so may asynctask seperately writing bulk of code , you can just use 4 lines of code
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
System.out.println(response);
}
});
I is very efficient in geting the response very quickly.
I hope this will help you out. :)
Hey i have a problem with my android application.I'm trying to download text from given url to Editable box but when i'm running application and hit the button it suddenly stops working.I am using asynctask to download, also eclipse tells me that class DownloadTask is not used locally
public void sendMessage(View view) throws IOException {
new DownloadTask().execute();
}
private class DownloadTask extends AsyncTask{
protected Object doInBackground(Object... params) {
// TODO Auto-generated method stub
try {
EditText tf = (EditText) findViewById(R.id.editText1);
String kupa = tf.getText().toString();
Document doc;
doc = Jsoup.connect(kupa).get();
String title = doc.text();
TextView tv = (TextView) findViewById(R.id.textView1);
tv.setText(title);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
TextView tv = (TextView) findViewById(R.id.textView1);
tv.setText(result);
}
}
Also i added two lines of code to my onCreate method
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
If this helps min api is 10,target is 16
cheers guys
you can't run UI code in doInBackground.
you try run bellow code on doInBackground, delete that or move it to onPostExecute
tv.setText(title);
and you don't need following line:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
if you need value in AyncTask you can pass data, if you need tf.getText().toString() you can change your code with following code:
new DownloadTask().execute(tf.getText().toString());
and change AsyncTask class with:
public static class DownloadTask extends AsyncTask<String, Void, Void>
{
#Override
protected Void doInBackground(String... params)
// use params array, in this example you can get tf.getText().toString() with params[0]
String kupa = params[0] // if you pass more data you can increase index
}
for more info see documentation of AsyncTask
:( Now, we can talk about Thread.
hmm...
You are using AsyncTask to download text from url.
It mean you are using another thread to do.
And another thread could not change UI. You must change UI in main thread. But if you want to change UI in other thread you can use runOnUIThread method.
I can give you a solution for your issue.
A child of AsyncTask
public class AsyncLoadData extends AsyncTask<String, Void, String> {
private Context mContext;
private ILoadDataListener mListener;
public AsyncLoadData(Context context, ILoadDataListener listener) {
this.mContext = context;
this.mListener = listener;
}
#Override
protected String doInBackground(String... params) {
String url = params[0];
String result = doGetStringFromUrl(url); // You can write your own method;
return result;
}
#Override
protected void onPostExecute(String result) {
mListener.complete(result);
}
#Override
protected void onPreExecute() {
mListener.loading();
}
public interface ILoadDataListener {
void loading();
void complete(String result);
}
}
In your activity
public class MainActivity extends Activity implements AsyncLoadData.ILoadDataListener {
/// Something...
public void getData() {
new AsyncLoadData(this, this).execute(url);
// or new AsyncLoadData(getBaseContext(), this).execute(url);
}
#Override
public void loading() {
// Do something here when you start download and downloading text
}
#Override
public void complete(String result) {
TextView mTextView = (TextView) findViewById(R.id.your_text_view);
mTextView.setText(result);
// EditText is the same.
}
}
My basic question is how do you update the GUI with AsyncTask. I am setting a String in onPostExecute that the GUI thread references. Using logging, I can see the String getting set in the onPostExecute method, but it never gets set on my GUI under my onClickListener to update the GUI. Any help is appreciated.
Main Program:
public class Main extends Activity {
/** Called when the activity is first created. */
Arduino.ToAndroid.Temperature.GetJSON jsonHttpClass = new Arduino.ToAndroid.Temperature.GetJSON();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new GetJSON().execute(url_to_Http);
}
View.OnClickListener temperatureListener = new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
// buttonTemperature = json.getTemp();
tempView.setText(jsonHttpClass.value);
Log.i("ROSS LOG", "Button Clicked");
}
}; }
Async Task:
class GetJSON extends AsyncTask {
public String value;
#Override
protected String doInBackground(String... url) {
String result = this.getHttpJson(url[0]);
return result;
}
#Override
protected void onPostExecute(String result) {
value = new String(result);
Log.i("ROSS LOG", value);
}
}
In onCreate(), you should be using the handle for the already created object of the AsyncTask and not create a new object.
Use
jsonHttpClass.execute(url_to_Http);
instead of
new GetJSON().execute(url_to_Http);
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();
}
});