I've just gotten into android development, and while trying to create a login form i ran into some problems.
What I want to do is enter username and password and press login, when the login button is pushed I want it to do a JSON request with the account information to my server and get a response with whether or not the user is allowed to log in. If the user is allowed, I want to change to a new view.
My code receives the JSON information correctly, but from what I've understood the UI-code (pushing a new activity) should be done in onPostExecute(). My problem is that onPostExecute is never run, I've looked at other ppl with the same problem, but their solutions hasn't worked for me. What they have said is that i need to have an #Override before onPostExecute, but when I add that i get the compilation error that "the method does not override method from its superclass".
I've read solutions from people having that problem as well, and from what I have read the problem is that the method onPostExecute has to have the same parameters as the result parameter from doInBackground(). My problem is that I feel I already do, and when I try to look in what the superclass has (that is AsyncTask.java) it says that the method onPostExecute() looks like:
protected void onPostExecute(Result result) {
}
But I have no idea what class Result belongs to..
networkingTask is run using this line:
new networkingTask().execute(url);
If anyone could help me I'd be eternally grateful! :)
This is what my code looks like
private class networkingTask extends AsyncTask {
Context context;
private networkingTask(Context context) {
this.context = context.getApplicationContext();
}
public networkingTask() {
}
#Override
protected JSONObject doInBackground(Object... params) {
try {
String urlString = (String) params[0];
System.out.println(urlString);
// Creating JSON Parser instance
JSONParser jParser = new JSONParser();
// getting JSON string from URL
JSONObject json;
json = jParser.getJSONFromUrl(urlString);
String responseLogged = json.getString("logged");
System.out.println("can we log in?: "+ responseLogged);
return json;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(JSONObject result) {
String responseLogged = "";
try {
responseLogged = result.getString("logged");
} catch (JSONException e) {
e.printStackTrace();
}
if(responseLogged.equals("true")){ //Login = true
Intent intent = new Intent(context, ShowListActivity.class);
intent.putExtra(EXTRA_JSON_OBJECT, result.toString());
startActivity(intent);
} else{ //Login = false
System.out.println("wrong password");
}
return;
}
}
In your line:
private class networkingTask extends AsyncTask
just change it to:
private class networkingTask extends AsyncTask<String, Void, JSONObject>
while String is the place for you to pass in the parameters, in your case it is url, the second parameter Void is for showing progress and the last one is the processed result to be passed from doInBackground to onPostExecute
For further explanation & info, please refer to Android Developers: AsyncTask
I think you may need to fill out the generic types for your AsyncTask. See the "Usage" section in the AsyncTask documentation.
Your class signature should look something like this:
private class networkingTask extends AsyncTask<Object, Void, JSONObject>
The types in the brackets here correspond to the argument types for doInBackground, onProgressUpdate, and onPostExecute, respectively, and are necessary if you're going to override these methods such that they are different from the generic method signatures.
Also, as a side note, it's a common convention in Java/Android to use upper CamelCase to start a class name. I'd also change the name of your class to "NetworkingTask" to help other developers looking at your code to better understand it.
The signatures don't match. You're attempting to override:
protected void onPostExecute(Result result)
with the signature
protected void onPostExecute(JSONObject result)
...which doesn't exist in the superclass.
Related
I'm currently studying android on my own and pretty new to java. I'm wondering how AsyncTask works like this: onPreExecute() -> doInBackground() -> onPostExecute(). When I look at others define their AsynTask, it seems like only method is declared in their code with no calls upon the method. I can't figure out how doInBackground() comes after onPreExecute() with no code that links both like:
onPreExecute(){ ~~~~~ call doInBackground()}
My point is that when AsyncTask.execute() is called, onPreExecute() is called, then doInBackground(), finally onPostExecute(). I couldn't find any code in library that actually connects these together. All I could find is this:
#MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
#MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
Here when AsyncTask.execute() is called, onPreExecute() is called. But without any connection to doInBackground the task works just fine. I feel like I'm missing some fundamental logic or process of java or android. Plz, help me with this unsolved question in mind. Sample code is shown below. Thank you in advance.
#Override
protected void onPreExecute() {
super.onPreExecute();
mLoadingIndicator.setVisibility(View.VISIBLE);
}
#Override
protected String[] doInBackground(String... params) {
/* If there's no zip code, there's nothing to look up. */
if (params.length == 0) {
return null;
}
String location = params[0];
URL weatherRequestUrl = NetworkUtils.buildUrl(location);
try {
String jsonWeatherResponse = NetworkUtils
.getResponseFromHttpUrl(weatherRequestUrl);
String[] simpleJsonWeatherData = OpenWeatherJsonUtils
.getSimpleWeatherStringsFromJson(MainActivity.this, jsonWeatherResponse);
return simpleJsonWeatherData;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(String[] weatherData) {
// COMPLETED (19) As soon as the data is finished loading, hide the loading indicator
mLoadingIndicator.setVisibility(View.INVISIBLE);
if (weatherData != null) {
// COMPLETED (11) If the weather data was not null, make sure the data view is visible
showWeatherDataView();
/*
* Iterate through the array and append the Strings to the TextView. The reason why we add
* the "\n\n\n" after the String is to give visual separation between each String in the
* TextView. Later, we'll learn about a better way to display lists of data.
*/
for (String weatherString : weatherData) {
mWeatherTextView.append((weatherString) + "\n\n\n");
}
} else {
// COMPLETED (10) If the weather data was null, show the error message
showErrorMessage();
}
I guess you shouldn't waste time on AsyncTask since it is deprecated.
Instead you should focus on coroutines, recommended by google here , or some other state of the art framework to achive what you want (e.g. rx java)
Yes, you are correct. The logic is onPreExecute() -> doInBackground() -> onPostExecute()
Synchronous VS asynchronous
You can read this article for a better understanding even though it's using Javascript to explain it.
Is there any way to use AsyncTask.execute() multiple times?
Im using AsyncTask to check, if User exist in my Room Database.
My Login.class looks like this:
public class Login extends AsyncTask<String, Boolean, Boolean> {
public Login(Context context, LoginListener listener){
db = ApplicationDatabase.getDatabase(context); //i get Room here
this.context = context; //context of app
this.listener = listener; //my interfece for observe Boolean, works ok
}
#Override
protected Boolean doInBackground(String... body){
try {
user = db.userDao().getUser(body[0], body[1]);
if (user != null)
return Boolean.TRUE; //we find user with credentials
else {
return Boolean.FALSE; //we not find user with that credentials (from body)
}
}
catch(Exception e){
return null;
}
}
protected void onPostExecute(Boolean result) {
listener.onLoginPerformed(result); //Boolen to activity
selfRestart(); //i want to restart task here
}
private void selfRestart(){
//maybe something to do here? its my own method
}
private ApplicationDatabase db;
private User user;
private LoginListener listener;
private Context context;
I call Task in this way (my Activity.class):
login = new Login(getApplicationContext(), this);
//this is an interface that i implements in Activity definition
loginButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//execute() here, i cuted some not necesery code from here
try {
// im using get because i want to get valu from AsyncTask
login.execute(email, password).get();
}
catch(Exception e){ }
}
I Read, that we can reset AsyncTask by making new AsyncTask (Task = new Login()) StackOverflow Thread but it dont work for me. When i try to make something like this in my Login class:
private void selfRestart(){
Login task = new Login(context, listener);
task.execute("");
//im calling it in onPostExecute()
}
My android app crashes. My question is, what is the best way to reset AsyncTask that is implemented in diffrent file then my Activity class? Or maybe there is better way to make Login activity than implemented whole logic for login in AsyncTask?
EDIT:
Logcat:
2019-01-24 15:45:31.407 1048-1048/com.example.admin.keystroke_dynamics E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.admin.keystroke_dynamics, PID: 1048
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Boolean.booleanValue()' on a null object reference
at com.example.admin.keystroke_dynamics.Activities.LoginActivity.onLoginPerformed(LoginActivity.java:62)
at com.example.admin.keystroke_dynamics.Login.onPostExecute(Login.java:38)
at com.example.admin.keystroke_dynamics.Login.onPostExecute(Login.java:14)
at android.os.AsyncTask.finish(AsyncTask.java:692)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:709)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
You say,
I call Task in this way (my Activity.class):
login = new Login(getApplicationContext(), this);
//this is an interface that i implements in Activity definition
loginButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//execute() here, i cuted some not necesery code from here
try {
// im using get because i want to get valu from AsyncTask
login.execute(email, password).get();
}
catch(Exception e){ }
}
, but no, you are not "calling" your task that way. You are creating a single instance of the task, and setting up an event handler that executes that task -- that specific instance -- whenever the loginButton is clicked. Since each AsyncTask instance may be executed only once, that will fail the second time the login button is clicked (if not sooner, for some other reason).
You also say,
I Read, that we can reset AsyncTask by making new AsyncTask (Task = new Login())
, but no, that does not reset anything, and indeed AsyncTask objects cannot be reset. The advice you read was to replace the used AsyncTask with a fresh instance. Instantiating a new AsyncTask has no particular effect on others. If you want to pursue that approach then it might look something like this:
loginButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
Login myLoginTask = login; // keep a reference to the current task
login = new Login(... arguments ...); // create a new task for the next click
try {
// use the original task
myLoginTask.execute(email, password).get();
}
catch(Exception e){ }
}
That specific implementation requires login to be non-final, so probably an instance variable of the containing class, not a local variable of the method from which your code was excerpted.
HOWEVER, your best way forward might very well be to ditch AsyncTask altogether. When you use it like this:
login.execute(email, password).get();
... you defeat the entire purpose. You are making the thread in which that runs block until the task completes (that's what AsyncTask::get is for), so the task is effectively synchronous. If that's what you require then you should just do the wanted work more directly instead of wrapping it up in an AsyncTask.
I am using the an asynchronous task to run a JSON downloader as thus: (abridged)
public class JSONDownloader extends AsyncTask<Object, Object, Object>{
#Override
protected Object doInBackground(Object... params) {
if(JSONstate == false){
try {
final URL url = new URL([REDACTED]);
final URLConnection urlConnection = url.openConnection();
urlConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
urlConnection.connect();
final InputStream inputStream = urlConnection.getInputStream();
final StringBuilder sb = new StringBuilder();
while (inputStream.available() > 0) {
sb.append((char) inputStream.read());
}
String result = sb.toString();
JSONObject jsonOrg = new JSONObject(result);
String ok = "ok";
Response = jsonOrg.getString("response");
System.out.println(Response);
if(Response.equals(ok)){
Settingsresponse = true;
orgName = jsonOrg.getString("orgName");
System.out.println("orgName" + orgName);
accessPointName = jsonOrg.getString("attendanceRecorderName");
System.out.println("accessPointName" + accessPointName);
lat = jsonOrg.getString("latitude");
System.out.println("lat" + lat);
longi = jsonOrg.getString("longitude");
System.out.println("longi" + longi);
floor = jsonOrg.getString("floor");
System.out.println("floor" + floor);
orgId = jsonOrg.getString("orgId");
System.out.println("orgId" + orgId);
}
else{
System.out.println("Data sent was erroneous");
Settingsresponse = false;
}
} catch (Exception e) {
System.err.print(e);
}
}
else if(JSONstate == true){
try {
[redacted]
}
else{
System.out.println("Data sent was erroneous");
Settingsresponse = false;
}
} catch (Exception e) {
System.err.print(e);
}
}
return null;
}
protected void onPostExecute(Void result){
if(JSONstate == false){
System.out.println("This piece of code is definitely being run");
setfields();
}
else if(JSONstate == true){
settestfields();
//This method does not run upon the completion of the JSON request, as it supposedly should
}
}
}
Once the JSONRequest has been completed, the 'onPostExecute' method doesn't run. I have been attempting to use this method so that a set of fields can be updated as soon as the request is complete, instead of having to set a definite wait time. Am I simply utilizing the code wrong? Or is there something I've missed?
You aren't overriding the correct method for onPostExecute.
You have:
protected void onPostExecute(Void result)
You need:
protected void onPostExecute(Object result)
Notice the third generic parameter you supplied was of type Object. That's the type that onPostExecute uses as an argument. So, the method signature for onPostExecute needs to accept an Object, not Void.
You should probably use a result type of boolean here rather than object, and remove the Json state class variable. This keeps your AsyncTask more flexible, and could allow you to display some indication the operation completed to the user after execution.
I have to say you codes in AsyncTask is nothing matches the point.
AsyncTask is designed as another thread running out from the UI-thread. So you should either use it as a inner class which is in a running UI-thread, then the onPostExecute() part can do something to show the result, or you as your codes, if you leave it as a stand alone class. You should design an interface, other class, like activity or fragment, which run new AsyncTask.execute() should implements that interface.
Also, java is not javascript. Your variables in doInBackground() is only limited in the function. So what you did in onPostExecute() will get nothing.
You should either use
JSONObject jsonOrg
as a class variable or you should return that at the end of doInBackground() and gain it back in onPostExecute()
After all, I suggest you look at the api document's example. Although it is a little complex, but it shows everything perfect.
try to use override methods
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Log.i("in on ", "entered");
hideProgress();
}
As suggested by william the type should match with the override methods. I have edited the answer below
public class JSONDownloader extends AsyncTask<Object, Object, Object>
#Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
}
my goal is to insert to a certain db 2 values, id and pass.
I have a registeration page which asks for that data and a button to complete the action.
So on the button listener what should I do?many told me to use AsyncTask (which I don't know to use) instead of Thread.
Remember that this class needs to get 2 parameters id and pass .. and as far as I know threads starts after using the start() method which invoke the run method, and the run method has no parameters.. so how can I pass those 2 parameters?
Anyway I'm very confused.
Another thing is that if I get any kind of error on the catch block I will put the error on a certain string something like : String error = exceptionInstance.toString(); and then I can take see that string from the registeration page and print the error.
myThreadInstance.start();
textViewInstance.setText(myThreadInstance.getError());
It's some kind of a marathon.. I'M CONFUSED!!!!!!!
According to me use AsyncTask instead of an Thread because it's easy to use and you have better control on Background thread without doing extra code for creating separate logic for updating Ui when Thread execution complete, calculate progress units to so user how much time take by an operation to done etc
Your First question how you send username and password to AsyncTask on button click .for this use AsyncTask Constructor as:
LoginOperation loginopertion=new LoginOperation(strusername, strpassword);
loginopertion.execute("");
Your Second answer how we receive username and password in AsyncTask and update Ui when Task complete for this use onPostExecute of AsyncTask to update Ui when doInBackground execution complete for example :
public class LoginOperation extends AsyncTask<String, Void, String> {
String strusername,strpassword;
public LoginOperation(String strusername, String strpassword){
this.strusername=strusername;
this.strpassword=strpassword;
}
#Override
protected void onPreExecute() {
//show progressbar here
}
#Override
protected String doInBackground(String... params) {
string result="";
try
{
result=="success or fail";
//do your network opertion here
}
catch(SQLException e)
{
result="ERROR";
}
return result;
}
#Override
protected void onPostExecute(String resultmsg) {
// show error here and update UI
//or other opertion if login success
textViewInstance.setText(resultmsg);
}
}
For more information about AsyncTask method's see
http://developer.android.com/reference/android/os/AsyncTask.html
I have a an activity with AsyncTask sub-classed. I lose all my variables once the async task is executed. I am stepping through my code in debug mode. As soon as "MyAsync().execute()" finishes the "formatedURL" variable (and all the others) have no values. before that, they have the correct values. Then, for some odd reason, they lose the values. Am i making a simple OO mistake or is garbage collection doing something i am not aware of.
public class NearbyList extends Activity {
double lat;
double lng;
String restName;
GPSHandling gps;
String formatedURL;
JSONObject jobject;
ArrayList<HashMap<String, String>> listOfHM;
ArrayList<String> listOfValues;
String currentName;
ListView lv;
Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nearby_places_list);
context = getApplicationContext();
gps = new GPSHandling(this);
lat = gps.getMyLatitude();
lng = gps.getMyLongitude();
restName ="";
formatedURL = GooglePlacesStuff.placesURL(lat, lng, 16000, "food", restName, true); //make a proper url. next step is to get a JSON object from this.
new MyAsync().execute();// in order to run networking it must not be done in the UIthread. I use async task to take care of this in order to
//reduce the code of doing complex threading since this is a simple calculation
}
class MyAsync extends AsyncTask<Void, Integer, Boolean>{
#Override
protected Boolean doInBackground(Void... params) {
try {
jobject = GooglePlacesStuff.getTheJSON(formatedURL);
listOfHM = JSONextractor.getJSONHMArrayL(jobject);
// iterate through and get the names of the nearby restaurants from the array of hasmap strings
for(int i =0 ; i < listOfHM.size() ;i++ ){
currentName = listOfHM.get(i).get(JSONextractor.TAG_NAME);
listOfValues.add(currentName);
}
return true;
} catch (Exception e){
Log.e("Nearby List Activity", "exception", e);
return false;}
}
#Override
protected void onPostExecute(Boolean result){
super.onPostExecute(result);
if (result){
ListAdapter adapter = new SimpleAdapter(context, listOfHM, R.layout.nearby_places_list, new String[]{JSONextractor.TAG_NAME,
JSONextractor.TAG_VICINITY, JSONextractor.TAG_GEO_LOC_LAT}, new int[]{ R.id.name, R.id.vicinity, R.id.phone});
// adding data to listview
lv.setAdapter(adapter);
} else{
Toast.makeText(getApplicationContext(), "Need Internet & GPS access for this to work", Toast.LENGTH_LONG).show();
}
gps.stopUsingGPS(); // stop using the gps after i get the list to save on resource
}
}
}
Edit1:
looks like it is trying to run "super.onCreate(Bundle savedInstanceState)" multiple times in the doinbackground() method
Edit2: if i make the values static they don't get lost. Its weird, even the variable "jobject" which is assigned inside the async task wont take an assignment unless its a static variable.... never seen anything like this
When you say they have no values, are you checking them inside the AsyncTask? If so, this might be the reason (from AsyncTask):
Memory observability
AsyncTask guarantees that all callback calls are synchronized in such a way that the following operations are safe without explicit synchronizations.
Set member fields in the constructor or onPreExecute(), and refer to them in doInBackground(Params...).
Set member fields in doInBackground(Params...), and refer to them in onProgressUpdate(Progress...) and onPostExecute(Result).
Basically, you shouldn't access your instance variables from doInBackground() because it's not thread-safe. Like the function says, it runs in a separate (background) thread. You can work around it by making them static (which you tried) or synchronize them, but it's probably better to use AsyncTask the way it's intended.
So I think you should do the following:
Pass in formatedURL as a parameter to the AsyncTask
return ArrayList<HashMap<String, String>> from doInBackground() (listOfHM)
Use the passed in ArrayList<HashMap<String, String>> in onPostExecute()
I would also additionally set the ListAdapter in onCreate, and just update the data backing the ListAdapter onPostExecute(). But I won't discuss that here since it's probably a separate question. This one is optional.
Code:
class MyAsync extends AsyncTask<String, Integer, ArrayList<HashMap<String, String>>> {
#Override
protected ArrayList<HashMap<String, String>> doInBackground(String... urls) {
ArrayList<HashMap<String, String>> listOfHM = null;
if (urls != null && urls.length > 0 && urls[0] != null) {
String formattedUrl = urls[0];
try {
JSONObject jobject = GooglePlacesStuff.getTheJSON(formattedURL);
listOfHM = JSONextractor.getJSONHMArrayL(jobject);
} catch (Exception e) {
// log error
}
}
return listOfHM;
}
#Override
protected void onPostExecute(ArrayList<HashMap<String, String>> listOfHM){
if (listOfHM != null && !listOfHM.isEmpty()) {
// iterate through and get the names of the nearby restaurants from the array of hasmap strings
for(int i =0 ; i < listOfHM.size() ;i++ ){
String currentName = listOfHM.get(i).get(JSONextractor.TAG_NAME);
listOfValues.add(currentName);
}
// do your adapter stuff
}
gps.stopUsingGPS(); // stop using the gps after i get the list to save on resource
}
}
And in your onCreate() you would do
new MyAsync(formattedUrl).execute();
Hope it helps!
Try to separate the functionality and the responsibilities, make a constructor in your async class and pass the activity as a parameter, just like maintain the context in the thread to avoid any memory leak, define some function in the activity to make the post execution task with the data just "living" in the activity (define the adapter, assign the adapter to the list view, stop the gps use, etc) and in the onpostexecute just call the mActiviy.doAfterTaskFinish(). The point is to separate the responsibilities, that could help you to find where the thing is going wrong.
So it turns out, I asked a question about something that wasn't actually happening in my application. Evidently, when you use Async Task class, all of the variables from the on create method and all the variables inside the onPostExecute() and doInBackground() (pretty much all the variables inside of the file) will not show a value (unless you make them static) even though they in fact do have values while you are stepping though those methods. I have no idea why this is. I'm just too dependent on using the debugger for checking what my variables are. Sorry for the confusion.