I am doing an Udacity course (https://classroom.udacity.com/courses/ud851/lessons/e5d74e43-743c-455e-9a70-7545a2da9783) and I have to implement the following code:
public class GithubQueryTask extends AsyncTask<URL, Void, String> {
// TODO (26) Override onPreExecute to set the loading indicator to visible
#Override
protected String doInBackground(URL... params) {
URL searchUrl = params[0];
String githubSearchResults = null;
try {
githubSearchResults = NetworkUtils.getResponseFromHttpUrl(searchUrl);
} catch (IOException e) {
e.printStackTrace();
}
return githubSearchResults;
}
#Override
protected void onPostExecute(String githubSearchResults) {
// TODO (27) As soon as the loading is complete, hide the loading indicator
if (githubSearchResults != null && !githubSearchResults.equals("")) {
// TODO (17) Call showJsonDataView if we have valid, non-null results
mSearchResultsTextView.setText(githubSearchResults);
}
// TODO (16) Call showErrorMessage if the result is null in onPostExecute
}
}
At the line "githubSearchResults = NetworkUtils.getResponseFromHttpUrl(searchUrl);" I get an cannot resolve error for NetworkUtils. What to do?
Kindly check if NetworkUtils class is there in your project. Or if it is imported via gradle depedancy, check if the class is imported.
Related
I want to check if a user is registered or not in a database, and if it is get the information of the user.
Normally, when I retrieve the information from the server, I put in the Json a variable saying if the user exists or not. Then in onPostExecute(Void result) i treat the Json, so i don't need the AsyncTask to return any value.
Before I was calling the AsyncTask as follows:
task=new isCollectorRegistered();
task.execute();
But now i'm trying a different approach. I want my asynktask to just return a boolean where i called the AsyncTask.
the AsyncTask looks as follows:
public class isCollectorRegistered extends AsyncTask<Void, Void, Void> {
private static final String TAG_SUCCESS = "success";
int TAG_SUCCESS1;
private static final String TAG_COLLECTOR = "collector";
public String collector;
JSONArray USER = null;
JSONObject jObj = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// Checks on the server if collector is registered
try {
jObj = ServerUtilities.UserRegistered(context, collector);
return null;
} finally {
return null;
}
}
#Override
protected void onPostExecute(Void result) {
try {
String success = jObj.getString(TAG_SUCCESS);
Log.d(TAG_COLLECTOR, "Final Info: " + success);
//This if sees if user correct
if (Objects.equals(success, "1")){
//GOOD! THE COLLECTOR EXISTS!!
}
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG_COLLECTOR, "JSON parsing didn't work");
}
}
}
I have checked several posts, but I still havent found out the way to retrieve the boolean where I call the Asynktask, something like this :
task=new isCollectorRegistered();
task.execute();
boolean UserRegistered = task.result();
What would be the right approach? Any help would be appreciated
To use AsyncTask you must subclass it. AsyncTask uses generics and varargs. The parameters are the following AsyncTask <TypeOfVarArgParams , ProgressValue , ResultValue> .
An AsyncTask is started via the execute() method.
The execute() method calls the doInBackground() and the onPostExecute() method.
TypeOfVarArgParams is passed into the doInBackground() method as input, ProgressValue is used for progress information and ResultValue must be returned from doInBackground() method and is passed to onPostExecute() as a parameter.
In your case you are passing Void to your AsyncTask : isCollectorRegistered extends AsyncTask<Void, Void, Void> so you can't get your result from the thread.
please read this tutorial to a deep understand of the AsyncTask in Android
I think the following is exactly what you were looking for, Alvaro...NOTE: I tweaked your code to make it more sensible, but I tried to stick to as much of your original code as possible...
public class RegisterCollector extends AsyncTask<String, Void, Boolean> {
private static final String TAG_SUCCESS = "success";
private static final String TAG_COLLECTOR = "collector";
int TAG_SUCCESS1;
String[] strArray;
JSONArray USER = null;
JSONObject jObj = null;
public String collector;
private AppCompatActivity mAct; // Just incase you need an Activity Context inside your AsyncTask...
private ProgressDialog progDial;
// Pass data to the AsyncTask class via constructor -> HACK!!
// This is a HACK because you are apparently only suppose to pass data to AsyncTask via the 'execute()' method.
public RegisterCollector (AppCompatActivity mAct, String[] strArray) {
this.mAct = mAct;
this.strArray = strArray;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// AHAH!! - So we do need that Activity Context after all...*TISK* *TISK* # Google **sigh**.
progDial = ProgressDialog.show(mAct, "Please wait...", "Fetching the strawberries & cream", true, false);
}
#Override
protected Boolean doInBackground(String... params) {
// Checks on the server if collector is registered
try {
jObj = ServerUtilities.UserRegistered(context, collector);
return true; // return whatever Boolean you require here.
} finally {
return false; // return whatever Boolean you require here.
}
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
progDial.dismiss();
try {
String success = jObj.getString(TAG_SUCCESS);
Log.d(TAG_COLLECTOR, "Final Info: " + success);
// This 'if' block checks if the user is correct...
if (Objects.equals(success, "1")){
//GOOD! THE COLLECTOR EXISTS!!
}
// You can then also use the Boolean result here if you need to...
if (result) {
// GOOD! THE COLLECTOR EXISTS!!
} else {
// Oh my --> We need to try again!! :(
}
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG_COLLECTOR, "JSON parsing didn't work");
Toast.makeText(mAct, "JSON parsing FAILED - Please try again.", Toast.LENGTH_LONG).show();
}
}
}
...then if you want to use the generated Boolean data outside the AsyncTask class try the following:.
RegisterCollector regisColctr = new RegisterCollector((AppCompatActivity) this, String[] myStrArry);
AsyncTask<String, Void, Boolean> exeRegisColctr = regisColctr.execute("");
Boolean isColctrRegistered = false;
try {
isColctrRegistered = exeRegisColctr.get(); // This is how you FINALLY 'get' the Boolean data outside the AsyncTask...-> VERY IMPORTANT!!
} catch (InterruptedException in) {
in.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
if (isColctrRegistered) {
// Do whatever tasks you need to do here based on the positive (i.e. 'true') AsyncTask Bool result...
} else {
// Do whatever tasks you need to do here based on the negative (i.e. 'false') AsyncTask Bool result...
}
There you go - I think this is what you were looking for (originally). I always use this approach whenever I need Async data externally, and it has yet to fail me....
I extended the Application class in order to create singleton-like object in android.
in this object I have all the HTTP work with my server, and all the other activities can access it and call methods to GET, POST etc.
Code:
public class HttpManagerInstance extends Application {
private HttpClient httpClient;
private HttpGet get;
#Override
public void onCreate() {
httpClient = new DefaultHttpClient();
get = new HttpGet("http://10.100.102.9:8000/users/");
super.onCreate();
}
public Void getUsers() throws Exception {
new executeRequest().execute(get);
return null;
}
private class executeRequest extends AsyncTask<HttpRequest, Void, Integer> {
#Override
protected Integer doInBackground(HttpRequest... params) {
// TODO Auto-generated method stub
HttpRequest request = params[0];
HttpResponse response;
String result="";
try {
response = httpClient.execute((HttpUriRequest) request);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return responseCode;
}
#Override
protected void onPostExecute(Integer result) {
// TODO Auto-generated method stub
switch (result) {
case HttpStatus.SC_OK:
// request was fine
// Here I want to updated the GUI of the activity that called this method.
break;
}
}
}
}
This is how I call the method from the Activity:
HttpManagerInstance sampleApp = (HttpManagerInstance)getApplicationContext();
sampleApp.getUsers();
Again - I want to access the UI of the Activity that called the method to put an REQUEST ACCEPTED message.
Maybe pass a context? any ideas?
I'd create a listener:
public class HttpManagerInstance extends Application {
private HttpClient httpClient;
private HttpGet get;
public interface ResponseListener{
public void onSuccess(Object data);
}
#Override
public void onCreate() {
httpClient = new DefaultHttpClient();
get = new HttpGet("http://10.100.102.9:8000/users/");
super.onCreate();
}
public Void getUsers(ResponseListener listener) throws Exception {
new executeRequest(listener).execute(get);
return null;
}
private class executeRequest extends AsyncTask<HttpRequest, Void, Integer> {
private ResponseListener mListener;
public executeRequest(ResponseListener listener){
this.mListener = listener;
}
#Override
protected Integer doInBackground(HttpRequest... params) {
// TODO Auto-generated method stub
HttpRequest request = params[0];
HttpResponse response;
String result="";
try {
response = httpClient.execute((HttpUriRequest) request);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return responseCode;
}
#Override
protected void onPostExecute(Integer result) {
// TODO Auto-generated method stub
switch (result) {
case HttpStatus.SC_OK:
// request was fine
// Here I want to updated the GUI of the activity that called this method.
if(this.mListener != null) mListener.onSuccess(whatEverDataYouWant);
break;
}
}
}
}
Then, in your activity:
HttpManagerInstance sampleApp = (HttpManagerInstance)getApplicationContext();
sampleApp.getUsers(new ResponseListener(){
public void onSuccess(Object data){
//update your ui!
}
});
The short answer is you can't directly reference to the UI from another activity. My advice would be for you to set up a callback on your Application class and call in on executeRequest#onPostExecute then implement that callback on your Activity and update your UI from there.
If you need help to implement the callback check this question
If you need to show message is good option the Dialog Class or the Toast Class, you can see more info are here:
Dialogs: http://developer.android.com/guide/topics/ui/dialogs.html
Toasts: http://developer.android.com/guide/topics/ui/notifiers/toasts.html
But if you want to access or modify a control in your actual activity, then use Runnable class, and context.runOnUiThread() method if you work inside AsyncTask. The real problem is that you can't change UI in a AsyncTask using declaration of the controls. You need to throw a Runnable process to communicate with activity!!. For example:
context.runOnUiThread(new Runnable() {
public void run() {
//Declaration of variables
TextView MyTextView = (TextView) context.findViewById(R.id.txtvMyControl);
MyTextView.setText("My title");
}
}
If I can helps you say me, good luck!
my code will crash if i not comment statement else if (message.equals("holiday")) on postexecute tell me why is not go further if not euqal this line (message.equals("holiday")) why not print "School is off today. Reason: if i comment else if (message.equals("holiday")) this code app work fine check my if else stateement please
String message;
public class getDataTask extends AsyncTask<Void, Void, Void> {
getDataTask() {
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
yourBoolean=false;
}
#Override
protected Void doInBackground(Void... arg0) {
// TODO Auto-generated method stub
displayData();
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
yourBoolean=true ;
if ((Category_ID.size() > 0) ) {
listCategory.setAdapter(cla);
cla.notifyDataSetChanged() ;
listCategory.invalidateViews();
menu_nametxt.setText(mVal2);
}
else if (message.equals("holiday"))
{
menu_nametxt.setText("No menu available .");
listCategory.setVisibility(View.GONE);
}
else
menu_nametxt.setText("School is off today. Reason: "+mVal3);
listCategory.setVisibility(View.GONE);
}
private void displayData() {
Cursor mCursor3 = db.selectQuery("SELECT * FROM uss_vacation WHERE calendar_id);
if (mCursor3.moveToFirst()) {
do {
Vacation_Date.add(mCursor3.getString(mCursor3.getColumnIndex("date")));
if(mCursor3.getString(mCursor3.getColumnIndex("date")).equals(mydate))
{
message = "holiday";
String mVal ;
mVal = (mCursor3.getString(mCursor3.getColumnIndex("title")));
mVal2 = mVal.toString();
mCursor3.close();
return;
}
} while (mCursor3.moveToNext());
}
mCursor3.close();
}
if i comment this code application print "School is off today. Reason: text
else if (message.equals("holiday"))
// {
// menu_nametxt.setText("No menu available .");
// listCategory.setVisibility(View.GONE);
// }
Since message is null when the app is run for the first time, when the if-else statement reaches else if (message.equals("holiday"), it will throws NullPointerException instead of false and crashing the app.
see SO: Java null String equals result
Consider initialize the message with empty string instead. (i.e. message = "";).
OR
Change the order of checking to else if ("holiday".equals(message)).
I want to display a Progress Dialog while I have two threads running one after the other, but my data structure that I use gets populated via the threads, becomes null. Thus I used thread.get() method to wait for the thread to be finished....not sure how I can get around this here is an example of one of my Async Threads:
private void performDetailSearch(String reference) {
String addplus = searchterm.replace(" ", "+");
RestClientDS restpSd = new RestClientDS();
String url = PLACES_DETAILS_URL +"reference="+ reference + "&sensor=false&key=" + API_KEY;
Log.d("url",url);
String[] URL = {url};
restpSd.execute(URL);
try {
restpSd.get();
}
catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
Use AsyncTask instead of Thread and call another task after one gets completed.
AsyncTask can be called this way new FetchData().execute();
private class FetchData extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog = new ProgressDialog(HomeActivity.this);
/** progress dialog to show user that the backup is processing. */
/** application context. */
protected void onPreExecute() {
this.dialog.setMessage(getResources().getString(
R.string.Loading_String));
this.dialog.show();
}
protected Boolean doInBackground(final String... args) {
try {
//do your background work
return true;
} catch (Exception e) {
Log.e("tag", "error", e);
return false;
}
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
if (success) {
//call the another asynctask from here.
// new FetchData2().execute();
}
}
}
I have a problem with updating my table-layout from my async class.
MY async class is fetching XML data so I don't block the main thread. My logs show the XML data is coming through but I don't know how to update my view with the data.
So I am attempting to put the data in tablerows and add the rows to the TableLayout but the logs show errors suggesting the Async class is not allowed to update my TableLayout view.
My code is as follows:
public class RemotePrimary extends Activity {
private static String SERVER_PATH = "http://test2.icerge.com/";
private static String XML_FILE1 = "samplexml";
//private static String SERVER_PATH = "http://tqs.mamlambo.com/";
//private static String XML_FILE1 = "scores.jsp";
private String[] data = new String[10];
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TableLayout datatable = (TableLayout)findViewById(R.id.TableLayout_data);
Downloader downloader = new Downloader();
downloader.execute(SERVER_PATH + XML_FILE1, datatable);
}
private class Downloader extends AsyncTask<Object, String, Boolean>{
TableLayout table;
#Override
protected Boolean doInBackground(Object... params) {
// TODO Auto-generated method stub
String path = (String)params[0];
table = (TableLayout)params[1];
XmlPullParser xmldata = null;
try {
URL serverPath = new URL(path);
xmldata = XmlPullParserFactory.newInstance().newPullParser();
xmldata.setInput(serverPath.openStream(), null);
addRecord(xmldata, table);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
#Override
protected void onProgressUpdate(String... values) {
// TODO Auto-generated method stub
//super.onProgressUpdate(values);
}
private boolean addRecord(XmlPullParser data, TableLayout table){
int eventType = -1;
boolean bFoundScores = false;
//find some records from xml
while(eventType != XmlResourceParser.END_DOCUMENT){
if( eventType == XmlResourceParser.START_TAG ){
//get the name of the tag(eg scores or score)
String strName = data.getName();
if( strName.equals("node") ){
bFoundScores = true;
String scoreValue = data.getAttributeValue(null, "Title");
String scoreRank = data.getAttributeValue(null, "Type");
String scoreUserName = data.getAttributeValue(null, "Nid");
Log.e("ADDING: ", scoreValue);
//Log.e("RETRIEVED", "collected : "+scoreValue+", "+scoreRank+", "+scoreUserName);
//publishProgress(scoreValue, scoreRank, scoreUserName);
TableRow newRow = new TableRow(RemotePrimary.this);
TextView rowText = new TextView(RemotePrimary.this);
rowText.setText(scoreValue);
newRow.addView(rowText);
table.addView(newRow);
}
}
try {
eventType = data.next();
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return true;
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}//close Downloader class
}//close RemotePrimary class
It's a bit much I know but I'll appreciate any help.
Thanks a great deal :-)
You can only make changes from the UI on the UI thread. The AsyncTask gives you an easy place to do this via onPostExecute. As it says in the docs, onPostExecute is always performed on the UI thread.
In doInBackground, do all of the hard work of building up the structured data that wish to display. Return that data so that it will be passed into onPostExecute, then in there add the appropriate table rows.