I have called an async task from my button click.In the doInBackground I have called an API and It is returning me a Json object.I want to pass the Json object to another activity on the button click.How can I can get the return Json object value so that I can send it to other activity.
Thanks.
Create Interface
public interface Listener {
void success(BaseModel baseModel);
void fail(String message);
}
Create Base model class
public class BaseModel implements Serializable {
private static final long serialVersionUID = 1L;
}
Call below method inside your onClick mehtod.
protected void userLoginData(final String userName) {
// if you want to pass multiple data to server like string or json you can pass in this constructor
UserLoginLoader userLoginLoader = new UserLoginLoader(LoginActivity.this, userName, "1234567899", new Listener() {
#Override
public void success(BaseModel baseModel) {
// here you got response in object you can use in your activity
UserLoginModel userLoginModel = (UserLoginModel) baseModel;
// you can get data from user login model
}catch(Exception exception){
exception.printStackTrace();
Utils.showAlertDialog(LoginActivity.this, "Server is not responding! Try Later.");
}
}
#Override
public void fail(String message) {
}
});
userLoginLoader.execute();
}
:- User Login Loader class
public class UserLoginLoader extends AsyncTask<String, Void, Boolean> {
private Dialog dialog;
private Listener listner;
private String deviceId;
Activity activity;
String message;
String userName;
boolean checkLoginStatus;
public UserLoginLoader(Activity activity,String userName, String deviceId, Listener listener) {
this.listner = listener;
this.userName =userName;
this.activity = activity;
this.deviceId = deviceId;
}
#Override
protected Boolean doInBackground(String... arg0) {
//User login web service is only for making connection to your API return data into message string
message = new UserLoginWebService().getUserId(userName, deviceId);
if (message != "null" && !message.equals("false")) {
return true;
}
return false;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new Dialog(activity, R.style.CustomDialogTheme);
dialog.setContentView(R.layout.progress);
dialog.setCancelable(false);
dialog.show();
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
BaseModel baseModel = null;
if (!message.equals("null") && (!message.equals("false")) )
baseModel = parseData(message, result);
if (dialog.isShowing()) {
dialog.dismiss();
dialog.cancel();
dialog = null;
}
if (listner != null) {
if (result && baseModel != null)
listner.success(baseModel);
else
listner.fail("Server not responding! Try agian.");
} else
listner.fail("Server not responding! Try agian.");
}
//call parser for parsing data return data from the parser
private BaseModel parseData(String responseData, Boolean success) {
if (success == true && responseData != null
&& responseData.length() != 0) {
UserLoginParser loginParser = new UserLoginParser(responseData);
loginParser.parse();
return loginParser.getResult();
}
return null;
}
}
This is you Login parser class
public class UserLoginParser {
JSONObject jsonObject;
UserLoginModel userLoginModel;
/*stored data into json object*/
public UserLoginParser(String data) {
try {
jsonObject = new JSONObject(data);
} catch (JSONException e) {
Log.d("TAG MSG", e.getMessage());
e.printStackTrace();
}
}
public void parse() {
userLoginModel = new UserLoginModel();
try {
if (jsonObject != null) {
userLoginModel.setUser_name(jsonObject.getString("user_name")== null ? "": jsonObject.getString("user_name"));
userLoginModel.setUser_id(jsonObject.getString("user_id") == null ? "" : jsonObject.getString("user_id"));
userLoginModel.setFlag_type(jsonObject.getString("flag_type") == null ? "" : jsonObject.getString("flag_type"));
} else {
return;
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
/*return ship name list which is stored into model */
public UserLoginModel getResult() {
return userLoginModel;
}
}
Write a callback method in the Activity that takes in the argument that you wish to pass from AsyncTask to that Activity. Send reference to the Activity to AysncTask while creating it. From doInBackground() method make a call to this callback method with the data your API returns.
Code would be something like -
public class TestAsyncTask extends AsyncTask<Integer, Integer, String[]> {
Activity myActivity;
public TestAsyncTask(Activity activity) {
this.myActivity = activity;
}
#Override
protected String[] doInBackground(Integer... params) {
String data = yourApi();
myActivity.callback(data);
}
}
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
new TestAsyncTask(this).execute(someId);
}
public void callback(String data) {
//process data
}
}
Just for the record you can directly get return value from doInBackground() method by calling get() on it.
String data = new TestAsyncTask(this).execute(someId).get();
But note this may block your UI thread as it will wait for the doInBackground() method to complete it's execution.
Related
I have a singleton to handle the registration and elimination of an entity Profilo ( a Profile).
This entity is set by passing an identifier and gathering information on the server in an async way.
My problem is that when I have to return my instance of profilo if it's not still loaded it will return null.
public class AccountHandler {
private static AccountHandler istanza = null;
Context context;
private boolean logged;
private Profilo profilo;
private AccountHandler(Context context) {
this.context = context;
//initialization
//setting logged properly
assignField(this.getName());
}
}
public static AccountHandler getAccountHandler(Context context) {
if (istanza == null) {
synchronized (AccountHandler.class) {
if (istanza == null) {
istanza = new AccountHandler(context);
}
}
}
return istanza;
}
public void setAccount(String nickname, String accessingCode) {
logged = true;
assignField(nickname);
}
//other methods
private void assignField(String nickname) {
ProfiloClient profiloClient = new ProfiloClient();
profiloClient.addParam(Profilo.FIELDS[0], nickname);
profiloClient.get(new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode,
Header[] headers,
JSONArray response) {
JSONObject objson = null;
try {
objson = (JSONObject) response.getJSONObject(0);
} catch (JSONException e) {
e.printStackTrace();
}
AccountHandler accountHandler = AccountHandler.getAccountHandler(context);
// Profilo is created with a JSONObject
// **setProfilo is called in async**
**accountHandler.setProfilo(new Profilo(objson));**
}
});
}
private void setProfilo(Profilo profilo) {
this.profilo = profilo;
}
public Profilo getProfilo() {
if( logged && profilo == null)
//How can I wait that profilo is loaded by the JsonHttpResponseHandler before to return it
return this.profilo;
}
}
Instead of calling getProfilo you could use a callback mechanism in which the AccountHandler class notifies the caller when the profile has been loaded. e.g.
public void setAccount(String nickname, String accessingCode, MyCallback cb) {
assignField(nickname, cb);
}
private void assignField(String nickname, MyCallback cb) {
....
accountHandler.setProfilo(new Profilo(objson));
cb.onSuccess(this.profilo);
}
Create an inner Interface MyCallback (rename it) in your AccountHandler class
public class AccountHandler {
public interface MyCallback {
void onSuccess(Profilo profile);
}
}
Now whenever you call setAccount you will pass the callback and get notified when the profile is available e.g.
accountHandler.setAccount("Test", "Test", new AccountHandler.MyCallback() {
void onSuccess(Profilio profile) {
// do something with the profile
}
}
I added, as #Murat K. suggested, an interface to my Class that will provide a method to be call with the object when it is ready to be used.
public class AccountHandler {
public interface Callback {
void profiloReady(Profilo profilo);
}
}
This method is called in getProfilo in a Handler that makes recursive calls to getProfilo until profilo is ready to be used, then it call the callback method which class is passed as argument of getProfilo.
public void getProfilo(final Callback Callback) {
if( logged && (profilo == null || !profilo.isReady() ) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
getProfilo(Callback);
}
}, 500);
}else
Callback.profiloReady(profilo);
}
Example of getProfilo call
public class ProfiloCall implements AccountHandler.MyCallback {
#Override
public void profiloReady(Profilo profilo) {
//Use profilo as needed
//EXECUTED ONLY WHEN PROFILO IS READY
}
public void callerMethod() {
//useful code
accountHandler.getProfilo(this);
//other useful code
}
}
I am using Parse in order to store my data. During the user 's registration, I create an AsyncTask to set the result in the calling activity if the user's email exists or not. Here is the code to trigger the validation
View.OnClickListener btnNextClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (etEmail == null) {
return;
}
final String email = etEmail.getText().toString();
if (email == null || email.length() == 0) {
etEmail.setError(getResources().getString(
R.string.error_email_is_null)
);
etEmail.requestFocus();
valid = false;
} else {
if (!Common.isValidEmailAddress(email)) {
etEmail.setError(getResources().getString(R.string.error_email_not_valid));
etEmail.requestFocus();
valid = false;
} else {
// validate Email from back end
new CheckEmailAsyncTask(CreateAccountActivity.this, email).execute();
if (emailValid == false) {
etEmail.setError(getResources().getString(R.string.error_email_existed));
etEmail.requestFocus();
valid = false;
}
}
}
if (valid) {
// if valid then going to the next step
Intent intent = new Intent(CreateAccountActivity.this, UpdateUserActivity.class);
intent.putExtra(AppConstant.PARAM_EMAIL, email);
startActivity(intent);
}
}
boolean emailValid;
public void setEmailValid (boolean emailValid) {
this.emailValid = emailValid;
}
};
and this is the code for CheckEmailAysncTask
public class CheckEmailAsyncTask extends AsyncTask<String, Void, Void> {
ProgressDialog progressDialog;
Context context;
CreateAccountActivity createAccountActivity;
String email;
public CheckEmailAsyncTask(CreateAccountActivity createAccountActivity, String email){
this.createAccountActivity = createAccountActivity;
this.context = createAccountActivity;
this.email = email;
progressDialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
this.progressDialog.show();
super.onPreExecute();
}
#Override
protected Void doInBackground(String... params) {
UserDAO userDAO = new UserDAO(context);
try {
int count = userDAO.isUserExists(email);
if (count > 0) {
createAccountActivity.setEmailValid(false);
} else {
createAccountActivity.setEmailValid(true);
}
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
super.onPostExecute(result);
}
}
}
and in UserDAO
public int isUserExists(String email) throws ParseException {
ParseQuery query = new ParseQuery("User");
query.whereEqualTo("email", email);
return query.count();
}
However, in my setup, the code below the AsyncTask will be executed first before the result are returned back to from Parse. How can I just let the rest of the code wait for future return and then continue ? One of the solution that I come up with is to keep looping the calling to the AsyncTask and sleep for while until the result is back
Try this:
if (email == null || email.length() == 0) {
...
}
else if (email != null & email.length() != 0) {
...
}
One solution that I just came up with is sending a callback to the DAO layer function so when the done action is triggered, it will trigger back the callback to move on.
public interface NavCallback {
public void finish();
}
public class MainActivity {
// inside click listener
NavCallback navCallbackError = new NavCallback() {
#Override
public void finish() {
setError();
}
.....
}
and the DAO function will take the callback as the parameters
public void checkExists(String email, NavCallback callback) {
.....
if (callback != null) callback.finish();
}
I have a serious problem which I can't a solution to.
I need to authenticate a token in order to let the user login into my app, the problem is that even though I'm using the AsyncTask, and probably because of it, I can't authenticate it in time. Other problem that sometimes accurs is that I get the NetworkOnMainThreadException error... I'm really hopeless.
Here's the flow -
Check for existsing token -> Validate -> Move to next activity
And here's my code -
public boolean validateToken(TokenAccess token) {
new IsValid().execute(token);
return isValid;
}
private class IsValid extends AsyncTask<TokenAccess, Void, Boolean> {
#Override
protected Boolean doInBackground(TokenAccess... params) {
TokenAccess token = params[0];
switch (token.getSource().getSource()) {
case 'M':
new UrlDownloader(new UrlDownloader.DownloadListener() {
#Override
public void setRequest(HttpRequest request) {}
#Override
public void onRecive(String content) {
if (content.contains("stats")) {
isValid = true;
} else {
isValid = false;
}
}
#Override
public void onError(Exception e) {}
}, UrlDownloader.RequestType.GET)
.execute("https://api.meetup.com/dashboard?access_token="
+ token.getToken());
}
return isValid;
}
}
That's is the URLDownloader class -
public class UrlDownloader extends AsyncTask<String, Void, HttpResponse> {
public static final String TAG = "net.ytsweb.socigo.assests.UrlDownloader";
public enum RequestType {
GET, POST;
}
private RequestType type;
private DownloadListener listener;
public UrlDownloader(DownloadListener listener, RequestType type) {
this.type = type;
this.listener = listener;
}
#Override
protected HttpResponse doInBackground(String... params) {
HttpClient httpClient = new DefaultHttpClient();
HttpUriRequest request;
HttpResponse response;
if (type == RequestType.GET) {
request = new HttpGet(params[0]);
} else {
request = new HttpPost(params[1]);
}
listener.setRequest(request);
try {
response = httpClient.execute(request);
} catch (Exception e) {
listener.onError(e);
return null;
}
return response;
}
#Override
protected void onPostExecute(HttpResponse response) {
try {
Log.d(TAG, response.getAllHeaders()[0].getValue() + "");
listener.onRecive(EntityUtils.toString(response.getEntity()));
} catch (Exception e) {
listener.onError(e);
}
}
public interface DownloadListener {
public void onRecive(String content);
public void onError(Exception e);
public void setRequest(HttpRequest request);
}
}
You need to use onPostExecute for handling the result of the IsValid AsyncTask. What I don't understand: why two AsyncTasks? One would be enough, do everything in there, and handle the result in the one and only onPostExecute.
Whatever happens in doInBackground is in a separate thread, onPostExecute happens on the UI-thread again. One AsyncTask is enough, but don't fetch a result in your validateToken method. In there, just execute your AsyncTask and whatever you need to do with the result you have to initiate in the onPostExecute.
As a basic example of what I mean:
public boolean validateToken(TokenAccess token) {
new YourAsyncTask().execute(token);
// DON'T rely on a result here
}
public class YourAsyncTask extends AsyncTask<?, ?, ?> {
#Override
protected ? doInBackground(?) {
// do networking in background-task
return result;
}
#Override
protected void onPostExecute(? response) {
// handle result here.. call a method in your main class, a listener with the result, or start an Activity directly
}
}
I need to pass the async task result to the calling class. I have created a separate ASync class which is called from other classes. I am passing the response from Async task in "Post Execute" method to calling class method but getting null point exception. Below is my calling method in
public boolean getCategories() {
serUri = "categories.json";
WebServiceAsyncTask webServiceTask = new WebServiceAsyncTask();
webServiceTask.execute(serUri,this);
return true;
}
The method to be executed with result from below aysnc task is
public void writeJSONArray(final JSONArray result)
{
try {
for (int i=0; i<result.length();i++){
JSONObject c = result.getJSONObject(i);
String name = c.getString("catname");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
WebServiceAsyncTask Class:
public class WebServiceAsyncTask extends AsyncTask<Object,Void,JSONArray> {
ROMSjson roms;
private static JSONArray json = null;
private Context context = null;
protected JSONArray doInBackground(Object... params) {
// TODO Auto-generated method stub
String serviceUrl = (String) params[0];
final HTTPHelper httph = new HTTPHelper(serviceUrl,context);
if(serviceUrl.equalsIgnoreCase("categories.json")) {
json = httph.fetch();
}else if(serviceUrl.equalsIgnoreCase("categories/create"))
{
}
return json;
}
#Override
protected void onPostExecute(JSONArray result) { // invoked on the ui thread
roms.writeJSONArray(result);
super.onPostExecute(result);
}
I am getting null point exception when roms.writeJSONArray(result) is called. The result is correctly received before this command. I checked with Log statement. Also if I write the writeJSONArray method in my Async class instead of calling class, all works fine.
I am not sure if I am missing something in passing the result or while calling methods. Please advise. Thanks.
null pointer exception
because roms is null
you are declaring ROMSjson roms; inside WebServiceAsyncTask but not initializing it !
and using it inside `onPostExecute(JSONArray result)
roms.writeJSONArray(result);` // here roms in null
so initialize roms before using it !
Here is the problem:
else if(serviceUrl.equalsIgnoreCase("categories/create"))
{
// if it falls to this condition then your json object appears to be null
}
Hope this helps.
Interface is the best way for passing data between classes.
create a public interface
public interface WebCallListener{
void onCallComplete(JSONArray result);
}
what to do in your class?
public class WebServiceAsyncTask extends AsyncTask<Object,Void,JSONArray> {
ROMSjson roms;
private static JSONArray json = null;
private Context context = null;
//update
private WebCallListener local;
public WebServiceAsyncTask(WebCallListener listener){
local=listener;
}
/////
protected JSONArray doInBackground(Object... params) {
// TODO Auto-generated method stub
String serviceUrl = (String) params[0];
final HTTPHelper httph = new HTTPHelper(serviceUrl,context);
if(serviceUrl.equalsIgnoreCase("categories.json")) {
json = httph.fetch();
}else if(serviceUrl.equalsIgnoreCase("categories/create"))
{
}
return json;
}
#Override
protected void onPostExecute(JSONArray result) { // invoked on the ui thread
//update
super.onPostExecute(result);
local.onCallComplete(result);
}
From Your Calling class.
public class CallingClass extends Activity{
protecte void oncreate(Bundle b){
new WebServiceAsyncTask(new WebCallListener() {
#Override
public void onCallComplete(JSONArray result) {
//play with your response
}
});
}
}
An Activity (SignInActivity) is calling a method in FunkcjeAPI which execute an AsyncTask.
My AsyncTask should show a ProgressDialog using an calling Activity. I don't know how to give it an correct Activity to the constructor. I tried a lot of thing, read a lot of tutorials and questions on SO, but I can't find solution. FunkcjeAPI isn't an Activity so I can't write new Logowanie(this).execute(argumenty);
AsyncTask calling code :
public class FunkcjeAPI {
static String dozwrotu = null;
public static String zalogujSie(final String nick, final String haslo)
{
String[] argumenty = {nick, haslo};
new Logowanie(/* WHAT HERE ? */).execute(argumenty); // HELP ME IN THAT LINE !!!!!!!!!!!!!
return dozwrotu;
}
My AsyncTask class code (it is in FunkcjeAPI class):
private class Logowanie extends AsyncTask<String, Void, String>
{
Activity wywolujaceActivity;
public Logowanie(Activity wywolujaceActivity) {
this.wywolujaceActivity = wywolujaceActivity;
}
#SuppressWarnings("deprecation")
#Override
protected void onPreExecute() {
wywolujaceActivity.showDialog(SignInActivit.PLEASE_WAIT_DIALOG);
}
#Override
protected String doInBackground(final String... argi) {
final JSONParser jParser = new JSONParser();
new Thread(new Runnable() {
public void run() {
final String json = jParser.getJSONFromUrl("http://tymonradzik.pl/THUNDER_HUNTER/thapi.php?q=login&username=" + argi[0] + "&password=" + argi[1] + "&imei=");
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
#Override
public void run() {
JSONObject jObject;
try {
jObject = new JSONObject(json);
Log.wtf("Link", "http://tymonradzik.pl/THUNDER_HUNTER/thapi.php?q=login&username=" + argi[0] + "&password=" + argi[1] + "&imei=");
Log.wtf("Link", json);
String error = jObject.getString("error");
if(error == "You reached daily query limit !") { nadajWartosc("You reached daily query limit !"); }
if(error == "0") {nadajWartosc(jObject.getString("token"));}
if(error == "1") {nadajWartosc("1");}
if(error == "Invalid username") {nadajWartosc("Invalid username");}
if(error == "Invalid password") {nadajWartosc("Invalid password");}
if(error == "This user is already logged in !") {nadajWartosc("This user is already logged in !");}
} catch (JSONException e1) {
e1.printStackTrace();
}
catch (NullPointerException e)
{
e.printStackTrace();
}
}
});
}}).start();
return dozwrotu;
}
#Override
protected void onPostExecute(String result) {
wywolujaceActivity.removeDialog(SignInActivit.PLEASE_WAIT_DIALOG);
}
}
Add one more parameter to zalogujSie() method that takes an Activity, and then use this parameter to start the AsyncTask:
public static String zalogujSie(Activity activity, final String nick, final String haslo)
{
// .....
new Logowanie(activity).execute(argumenty);
return dozwrotu;
}
Then you would call this method from the activity like this:
FunkcjeAPI.zalogujSie(this, "Nick", "Haslo");