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);
}
Related
I know this is duplicate but trust me i have tried many of the available codes and still not getting this worked.
Below are my code
public class LookIn extends AppCompatActivity implements View.OnClickListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
//Initializing properties
}
public void onClick(View v) {
// Event for button click
callHelper();
}
private void callHelper()
{
List result=null;
try {
String jsonResponse=new CallmeGetHelperAsyncTask(this).execute(params).get();
result= RestUtil.getUserList(jsonResponse);
}
catch (InterruptedException e) {
Log.e("Callme", Log.getStackTraceString(e));
} catch (ExecutionException e) {
Log.e("Callme", Log.getStackTraceString(e));
}
catch(JSONException x)
{
Log.e("Callme",Log.getStackTraceString(x) );
}
}
}
Below is my AsyncTask class
public class CallmeGetHelperAsyncTask extends AsyncTask<String,Void,String > {
private AppCompatActivity activity=null;
private ProgressDialog dialog=null;
public CallmeGetHelperAsyncTask(){}
public CallmeGetHelperAsyncTask(AppCompatActivity activity){
this.activity=activity;
//this.dialog= dialog;
}
#Override
protected void onPreExecute() {
if(this.dialog!=null)
{
Log.v("Callme", "Starting Dialog");
dialog = ProgressDialog.show(this.activity, "title", "message");
// this.dialog.setMessage("Looking for Helpers");
this.dialog.show();
}
else
{
dialog = ProgressDialog.show(this.activity, "title", "message");
}
}
#Override
protected void onPostExecute(String s) {
if(this.dialog!=null)
{
Log.v("Callme","Closing Dialog");
this.dialog.dismiss();
}
else
{
Log.v("Callme","Dialog is not initiated in CallmeGethelperAsyncTask");
}
}
#Override
protected String doInBackground(String... params) {
//call to webservice
}
}
I am not able to get what is the problem with above code.
One more bizarre i found(bizarre may be for me only because i am new). I tried printing Thread.currentThread.getId() from both my ActivityClass as well as from my AsyncTask and surprisingly both printed "1".
If i am not wrong then that says both codes are running from the same thread.
About this i have read Running multiple AsyncTasks at the same time -- not possible? which says earlier threadpool contained only 1 thread but i am using Android 5.1 which is supposed to contain 5 threads. So again i am confused over it.
Kindly take some time to explain. Thank you
Replace this:
public CallmeGetHelperAsyncTask(AppCompatActivity activity){
this.activity=activity;
//this.dialog= dialog;
}
with:
private Context context;
public CallmeGetHelperAsyncTask(Context context){
this.context=context;
}
and this:
dialog = ProgressDialog.show(this.activity, "title", "message");
with:
dialog = ProgressDialog.show(this.context, "title", "message");
and this:
String jsonResponse=new CallmeGetHelperAsyncTask(this).execute(params).get();
with:
String jsonResponse=new CallmeGetHelperAsyncTask(LookIn.this).execute(params).get();
Although i would rather not use the static method show of the progress dialog and build an Actual Progress Dialog.
Hope it helps!!!!
I have an AsyncTask class SearchForQuestions that is called from an Activity QuizMap. When looping through an array in SearchForQuestions I can't find the correct context for toast to appear within the AsynTask.
The standard Toast.makeText(getApplicationContext(), "This is Toast!!!", Toast.LENGTH_SHORT).show(); gives error getApplicationContext() undefined.
I have tried some of the solutions to this offerred by SO, most of them are listed here and concern getting UiThread and running on that.
I can't get this to work however. Here's example code snippets of what i have tried. I have put a method in QuizMap and try calling it from SearchForQuestions but SearchForQuestions isn't recognised. How can I get around this? )Still a newbie at java...)
// QuizMap activity
public class QuizMap extends FragmentActivity
implements OnMarkerClickListener {
private GoogleMap map;
private static final String TAG = "QuizMap"; // debugging
...
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quizmap);
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
...
}
// make toast inside AsyncTask
public void showNotNearToast(final String toast) {
QuizMap.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(QuizMap.this, "This is Toast!!!", Toast.LENGTH_SHORT).show();
}});
}
.
// SearchForQuestions class
private class SearchForQuestions extends AsyncTask<String, Void, DataHandler> {
// checks for proximity to question locations
Location location =
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
#Override
protected DataHandler doInBackground(String... pointsList) {
String result = pointsList[0];
...
}
#Override
protected void onPostExecute(DataHandler result) {
ArrayList<String> resultsArray = result.results;
Integer numPoints = resultsArray.size();
for (int i =0;i<numPoints;i++){
String[] pointDetails = resultsArray.get(i).split("::");
...
// we can make use of the Android distanceTo function to calculate the distances
float distance = location.distanceTo(fixedLoc);
if (i > DIST) { // this is UCL
showNotNearToast("My Message"); // showNotNearToast undefined
if (distance < DIST) {
...
}
};
I'm going t close this question. I haven't solved my problem but the number of answers provided that apparently work in other situations suggest there's something else going on. I'm going to re-structure the classes to get around having to call from within AsyncTask.
Just Toast it, why do you want to create a function for it? onPostExecute() is already on UI thread.
You are not able to access because inner Class can not call functions of Outer class unless you pass instance of the outer class.
Call your toast in onPostExecute
Create an interface for a callback.
public interface ToastCallback {
public void invoke(String text);
}
Your AsyncTask constructor
private ToastCallback toastCallback;
public SearchQuestions(ToastCallback callback) {
this.toastCallback = callback;
}
// in doInBackground() {
toastCallback.invoke("Toast from background");
}
In Your Activity,
private void showNotNearToast(String text) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
});
}
public class MyToastCallback implements ToastCallback {
#Override
public void invoke(String text) {
showNotNearToast(text);
}
}
// Asynctask call
new SearchQuestion(new MyTosatCallback()).execute(<Your params here>);
Try this from inside your AsyncTask:
myActivity.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
Where you have your
showNotNearToast("My Message"); // showNotNearToast undefined
Replace myActivity with the name of your Activity.
(Ab)use the publishProgress method
private class ToastAsyncTask extends AsyncTask<Void, String, Void>{
#Override
protected Void doInBackground(Void... voids) {
SystemClock.sleep(1000);
publishProgress("Toast msg string");
SystemClock.sleep(1000);
return null;
}
#Override
protected void onProgressUpdate(String... values) {
Toast.makeText(getApplicationContext(), values[0], Toast.LENGTH_SHORT).show();
}
}
**UPDATE: ** since you are having problems with context for some reason, use this version. Tough the implementation above works for me.
private class ToastAsyncTask extends AsyncTask<Void, String, Void> {
private WeakReference<Context> contextRef;
public ToastAsyncTask(Context context) {
contextRef = new WeakReference<Context>(context);
}
#Override
protected Void doInBackground(Void... voids) {
SystemClock.sleep(1000);
publishProgress("Toast msg string");
SystemClock.sleep(1000);
return null;
}
#Override
protected void onProgressUpdate(String... values) {
if (contextRef.get() != null) {
Toast.makeText(contextRef.get(), values[0], Toast.LENGTH_SHORT).show();
} else {
// The context was destroyed.. check what you are doing
}
}
}
Use it like this
new ToastAsyncTask(MainActivity.this).execute();
Pass the activity into the AsyncTask. See below.
private class SearchForQuestions extends AsyncTask<String, Void, DataHandler> {
Activity activity;
public void SearchForQuestions(Activity activity){
this.activity = activity;
}
//... rest of the code
public class QuizMap extends FragmentActivity implements OnMarkerClickListener {
/*...*/
new SearchForQuestions(this).execute();
/*...*/
/*When calling the toast:*/
Toast.makeText(this.activity, "This is Toast!!!", Toast.LENGTH_SHORT).show();
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);
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.