Passing multiple values to AsyncTask class - java

I am having some problem when trying to pass a String and object to AsyncTask class. So when my button on click, it should pass in a String and an EventReview object into the AsyncTask class:
viewDtlEventBtn.setOnClickListener(new OnClickListener(){
public void onClick(View v){
new GetEventDetailAsyncTask(new GetEventDetailAsyncTask.OnRoutineFinished() {
public void onFinish() {
//Get the values returned from AsyncTask and pass it to another activity
}
}).execute(String.valueOf(eventIDTV.getText()));
}
});
And inside my AsyncTask class, I am getting String as the parameter:
public static class GetEventDetailAsyncTask extends AsyncTask<String, Integer, Double> {
EventController eventCtrl = new EventController();
Context context;
public interface OnRoutineFinished { // interface
void onFinish();
}
private OnRoutineFinished mCallbacks;
public GetEventDetailAsyncTask(OnRoutineFinished callback) {
mCallbacks = callback;
}
public GetEventDetailAsyncTask() {
} // empty constructor to maintain compatibility
public GetEventDetailAsyncTask(Context context){
this.context = context;
}
#Override
protected Double doInBackground(String... params) {
try {
eventCommentModel = eventCtrl.getEventCommentByID(params[0]);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Double result) {
if (mCallbacks != null)
mCallbacks.onFinish(); // call interface on finish
}
protected void onProgressUpdate(Integer... progress) {
}
}
So I wonder is there any possible way to pass in a String and EventReview object to the execute() and then when doInBackground(), each execute each method. Any guides?
Thanks in advance.

You can pass String and your custom class' object in Object[] in asynctask.
Object[] obj = new Object[2];
obj[0] = "my data";
obj[1] = myEventReviewObj;
new GetEventDetailAsyncTask().execute(obj);
AsyncTask:
public static class GetEventDetailAsyncTask extends AsyncTask<Object, Integer, Double> {
#Override
protected Double doInBackground(Object... params) {
String paramStr = "";
EventReview eventReview = null;
if(params[0] instanceof String && params[1] instanceof EventReview) {
paramStr = (String) params[0];
eventReview = (EventReview) params[1];
}
else {
eventReview = params[0];
paramStr = params[1];
}
try {
//perform operation using String and Object as per your need
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
Hope this helps.

You can change the class to accept Objects as input:
public static class GetEventDetailAsyncTask extends AsyncTask<Object, Integer, Double>
and check if the object is an instance of String or of EventReview
#Override
protected Double doInBackground(Object... params) {
if(params[0] instanceof String) // it is String
else if(params[0] instanceof EventReview) // it is EventReview
}

Create custom constructor and save the passed variables in your AsyncTask:
public static class GetEventDetailAsyncTask extends AsyncTask<String, Integer, Double> {
EventReview eventReview;
private OnRoutineFinished mCallbacks;
String string;
Context context;
public GetEventDetailAsyncTask(OnRoutineFinished callback, String str, EventReview review) {
mCallbacks = callback;
string = str;
eventReview = review;
}
...
}
And then call the AsyncTask by passing your vars:
public void onClick(View v){
new GetEventDetailAsyncTask(
new GetEventDetailAsyncTask.OnRoutineFinished() {
public void onFinish() {
// Get the values returned from AsyncTask and pass it to another activity
}
},
String.valueOf(eventIDTV.getText(),
eventReview).execute());
}

Related

How to properly pass context to AsyncTask and then to another class?

I'm working on app that will use biometric as an option to login. Before I use the actual biometric prompt I need to check one thing from server - I use AsyncTask to do it. So, to sum up - I invoke AsyncTask from Parent Activity (login.java), and then AsyncTask uses biometricUtils.java class, that makes biometric prompt. The point is, I keep passing null instead of context to biometricUtils.java:
Attempt to invoke virtual method 'java.util.concurrent.Executor android.content.Context.getMainExecutor()' on a null object reference at biometricUtils.<init>(biometricUtils.java:34)
I have no idea to pass the context correctly.
Here's my code:
login.java
public class login extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
Bundle bundle = getIntent().getExtras();
final boolean flag = false;
final String androidID = bundle.getString("androidID");
final Activity thisActivity = this;
final Context context = getApplicationContext();
// login using biometrics
Button btnBiometricLogin = findViewById(R.id.btnBiometricLogin);
btnBiometricLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
checkAndroidID async = new checkAndroidID(context);
async.getParentActivity(thisActivity);
async.setFlag(flag);
async.execute(androidID);
}
});
}
}
checkAndroidID.java
public class checkAndroidID extends AsyncTask <String, Void, String> {
openHTTP openHTTP = new openHTTP();
requestHTTP requests = new requestHTTP();
Activity parentActivity;
private WeakReference<Context> contextRef;
Boolean flag;
public checkAndroidID(Context context){
contextRef = new WeakReference<>(context);
}
public void getParentActivity(Activity parentActivity){
this.parentActivity = parentActivity;
}
public void setFlag (Boolean flag){
this.flag = flag;
}
#Override
protected String doInBackground(String... strings) {
try {
HttpURLConnection httpConn = openHTTP.prepareConnection("url");
String json = "{ \"androidID\": \"" + strings[0] + "\" }";
requests.sendData(json, httpConn);
return requests.receiveData(httpConn);
} catch (Exception e){
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
String[] result = s.split(";");
Context ctx = contextRef.get();
if (result[0].equals("TRUE")) flag = true;
if (!flag) Toast.makeText(parentActivity, "Biometric authentication is now unavailable." +
" Please login using username and password", Toast.LENGTH_SHORT).show();
else {
biometricUtils biometrics = new biometricUtils(ctx);
biometrics.getParentActivity(parentActivity);
biometrics.getUsername(result[1]);
biometrics.inovkeBiometricPrompt();
}
super.onPostExecute(s);
}
}
and biometricUtlis.java
public class biometricUtils {
Activity parentActivity;
String username;
Context context;
public void getParentActivity(Activity parentActivity){
this.parentActivity = parentActivity;
}
public void getUsername(String s){
this.username = s;
}
public biometricUtils(Context context){
this.context = context;
}
// creating a variable for our Executor
Executor executor = ContextCompat.getMainExecutor(context); // LINE 34
// this will give us result of AUTHENTICATION
final BiometricPrompt biometricPrompt = new BiometricPrompt((FragmentActivity) parentActivity, executor, new BiometricPrompt.AuthenticationCallback() {
#Override
public void onAuthenticationError(int errorCode, #NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
}
// THIS METHOD IS CALLED WHEN AUTHENTICATION IS SUCCESS
#Override
public void onAuthenticationSucceeded(#NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
Intent intent = new Intent(parentActivity.getApplicationContext(), tmp.class);
intent.putExtra("username", username);
parentActivity.startActivity(intent);
}
#Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
}
});
// creating a variable for our promptInfo
// BIOMETRIC DIALOG
final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder().setTitle("Biometrical login")
.setDescription("Place your fingerprint on scanner to proceed").setNegativeButtonText("Cancel").build();
public void inovkeBiometricPrompt() {
biometricPrompt.authenticate(promptInfo);
}
}

Passing a variable between functions

I'm new to android studio and Java. My app uses jsoup to pass the contents of a website into an array where each element gets displayed on swipable flashcards (like tinder)
I've got a problem where my app crashes when I try to pass the result of the variable 'words' from onPostExecute() (line 123) to String num on line 49. I want to take the output of the function in onPostExcecute and set it as String num but I'm not sure how to do it.
public class AppHome extends AppCompatActivity implements PopupMenu.OnMenuItemClickListener {
TextView texx;
private ArrayList<String> al;
private ArrayAdapter<String> arrayAdapter;
private int i;
String words;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_home);
texx= findViewById(R.id.text1);
new doit().execute();
String num = words;
String str[] = num.split(",");
final ArrayList al = new ArrayList<String>(Arrays.asList(str));
arrayAdapter = new ArrayAdapter<>(this, R.layout.item, R.id.helloText, al );
SwipeFlingAdapterView flingContainer = (SwipeFlingAdapterView) findViewById(R.id.frame);
registerForContextMenu(flingContainer);
flingContainer.setAdapter(arrayAdapter);
flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener() {
#Override
public void removeFirstObjectInAdapter() {
// this is the simplest way to delete an object from the Adapter (/AdapterView)
Log.d("LIST", "removed object!");
al.remove(0);
arrayAdapter.notifyDataSetChanged();
}
#Override
public void onLeftCardExit(Object dataObject) {
//Do something on the left!
//You also have access to the original object.
//If you want to use it just cast it (String) dataObject
Toast.makeText(AppHome.this, "left", Toast.LENGTH_SHORT).show();
}
#Override
public void onRightCardExit(Object dataObject) {
Toast.makeText(AppHome.this, "right", Toast.LENGTH_SHORT).show();
}
#Override
public void onAdapterAboutToEmpty(int itemsInAdapter) {
// Ask for more data here
al.add("XML ".concat(String.valueOf(i)));
arrayAdapter.notifyDataSetChanged();
Log.d("LIST", "notified");
i++;
}
#Override
public void onScroll(float scrollProgressPercent) {
}
});
}
public class doit extends AsyncTask<Void,Void,Void> {
//String words;
#Override
protected Void doInBackground(Void... voids) {
try {
Document doc = Jsoup.connect("https://screenscrape4top40.000webhostapp.com/").get();
words=doc.text();
}catch(Exception e){e.printStackTrace();}
return null;
}
#Override
public void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
texx.setText(words);
//String str = (words);
//List<String> elephantList = Arrays.asList(str.split(","));
//texx.setText(elephantList.toString());
// texx.setText(elephantList);
}
}
}
public class doit extends AsyncTask<Void, Void, String> {
#Override
protected Void doInBackground(Void... voids) {
String words = "";
try {
Document doc = Jsoup.connect("https://screenscrape4top40.000webhostapp.com/").get();
words = doc.text();
} catch(Exception e) {
e.printStackTrace();
}
return words;
}
#Override
public void onPostExecute(String words) {
super.onPostExecute(aVoid);
texx.setText(words);
//String str = (words);
//List<String> elephantList = Arrays.asList(str.split(","));
//texx.setText(elephantList.toString());
// texx.setText(elephantList);
}
}
It should be fine now.
The problem is, you are not returning anything from the doInBackground method and hence you are not getting anything in the onPostExecute function.
You might consider checking the documentation for AsyncTask here.
In doInBackgroud() return the string(make sure it never beacome null) you want to use it on PostExecute()
also changed the data type of Parameter in onPostExecute method
onPostExecute(String Strs)
Then pass it to supper.OnPostExecute().
then u can use it.

Get returned value of interface method

I have implemented this interface:
public interface Callback {
public abstract ArrayList<String> done(ArrayList<Document> docs);
}
Also this method:
public void getNearUsers(Callback callback, LatLng loc) {
new GetNearUsersASyncTask(callback, loc).execute();
}
public class GetNearUsersASyncTask extends AsyncTask<Void, Void, ArrayList<Document>>{
Callback callback;
LatLng loc;
ArrayList<Document> documents;
public GetNearUsersASyncTask(Callback callback, LatLng loc){
this.callback=callback;
this.loc=loc;
documents = new ArrayList<>();
}
#Override
protected ArrayList<Document> doInBackground(Void... params) {
...
return documents;
}
#Override
protected void onPostExecute(ArrayList<Document> docs) {
...
callback.done(docs);
super.onPostExecute(docs);
}
}
And finally this one:
public ArrayList<String> gotoRec() {
final ArrayList<String> finalPostIDs = new ArrayList<>();
serverRequest.getNearUsers(new Callback() {
#Override
public ArrayList<String> done(ArrayList<Document> users){
...
return finalPostIDs;
}
}, loc);
}
});
//return the finalPostIDs of override method;
}
My question is this:
How can i have the finalPostIDs returned ArrayList of Callback interface to return it in gotoRec method ? Is there a way or should i take another road ?

start AsyncTask from one activity, get result in another

I'm new to Android programming, and I'd like to create a central database service class which will take care of user data exchange with an external database. For this, I created a service which is started after successful login. I created another class that extends AsyncTask to do the data retrieval.
Now, I wanted the methods for the data retrieval to be stored in the service. I would fire intents to the service from different activities, and with .setAction() I would determine which method to call, or which data to retrieve.
I also created an interface class for handling the AsyncTask results.
Now, from this question I thought that it would be possible to have multiple listeners to one and the same AsyncTask result. But now this seems impossible to achieve: I'd like to retrieve the AsyncTask results in the MainMenuActivity, but I can't create an instance of AsyncUserData there as a delegate for the UserData class. In my example below, the missing piece is a valid instance of AsyncUserData for the UserData class to work with. How could I do it?
Here's the example:
MainMenuActivity
public class MainMenuActivity extends ActionBarActivity implements AsyncUserData {
TextView tvUsername;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
tvUsername =
(TextView) findViewById(R.id.tvUsername);
TelephonyManager tManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
getDataFromUserSessionService(this, uid);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void retrieveResult(String result) throws JSONException {
JSONObject jsonObject = new JSONObject(result);
String joName;
joName = jsonObject.getJSONObject("name").toString();
user.setName(joName);
tvUsername.setText(joName);
}
public void getDataFromUserSessionService(Context context, String uid) {
Intent intent = new Intent(context, UserSession.class);
intent.setAction(UserSession.ACTION_FETCH_USER_DATA);
intent.putExtra(UserSession.UID, uid);
context.startService(intent);
}
UserSession Service
public class UserSession extends IntentService {
public static final String ACTION_FETCH_USER_DATA = "com.example.blahblah.services.action.read_user_data";
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
utils = new Utils(this);
final String action = intent.getAction();
uid = intent.getStringExtra(UID);
if (ACTION_FETCH_USER_DATA.equals(action)) {
handleUserDataFetch(uid);
}
}
}
private void handleUserDataFetch(String uid) {
String[] parameters = new String[2];
parameters[0] = uid;
parameters[1] = Constants.USER_DATA_FETCH;
UserData userData = new UserData(this);
userData.execute(parameters);
}
UserData AsyncTask Class (the Utils class just has another post method):
public class UserData extends AsyncTask < String, Void, String > {
public AsyncUserData delegate = null;
private Context myContext;
public UserData(Context context) {
myContext = context;
}
#Override
protected String doInBackground(String...params) {
String serverResponse = "";
String uid = params[0];
Utils utils = new Utils(myContext);
String phpName = params[1];
List < NameValuePair > nameValuePairs = new ArrayList < NameValuePair > ();
nameValuePairs.add(new BasicNameValuePair("uid", uid));
try {
serverResponse = utils.passDataToServer(phpName, nameValuePairs);
} catch (IOException e) {
e.printStackTrace();
}
return serverResponse;
}
protected void onPostExecute(String result) {
try {
delegate.retrieveResult(result);
} catch (JSONException e) {
e.printStackTrace();
}
}
};
And the AsyncUserData interface:
public interface AsyncUserData {
void retrieveResult(String result) throws JSONException;
}
You can use a Singleton that stores a reference to the activity
public class ServiceToActivity
{
public ActionBarActivity mainactivity = null;
private static ServiceToActivity singleton = null;
public Class<?> cl = null;
private ServiceToActivity()
{
}
public static ActionBarActivity getSingleton()
{
if(singleton==null)
return null;
return singleton.mainactivity;
}
public static Class<?> getSingletonClass()
{
if(singleton==null)
return null;
return singleton.cl;
}
public static void setSingleton(ActionBarActivity mainactivity, Class<?> cl)
{
if(singleton==null)
singleton = new ServiceToActivity();
singleton.mainactivity = mainactivity;
singleton.cl = cl;
}
}
Then create the singleton before the service is started
public void getDataFromUserSessionService(Context context, String uid) {
Intent intent = new Intent(context, UserSession.class);
intent.setAction(UserSession.ACTION_FETCH_USER_DATA);
intent.putExtra(UserSession.UID, uid);
ServiceToActivity.setSingleton(this,this.getClass()); //create Singleton to store a reference to the activity
context.startService(intent);
}
In UserData retrieve data to the main activity by:
protected void onPostExecute(String result) {
try {
Class<?> cl = ServiceToActivity.getSingletonClass();
Method met = cl.getMethod("retrieveResult", String); //String because result is of type String: you can use result.getClass() instead
met.invoke(cl.cast(ServiceToActivity.getSingleton()), result); // compare it to this ServiceToActivity.getSingleton().retrieveResult(result);
} catch (JSONException e) {
e.printStackTrace();
}
}
It sounds like you might want to use an event bus such as otto

Android - Get object from AsyncTask result

I want to create 10 Employee objects in an AsyncTask and return the result back to the MainActivity class to print it on a ListView with the 3 attributes of an Employee object.
This is what i have so far, but it just crashes after running
Menu class
public class Menu
{
public Employee person;
public void onButtonClick(View v) {
new setEMPInfo() {
protected void onPostExecute(Employee person)
{
doSomething(person);
}
}.execute();
}
public void doSomething(Employee person) {
//use person object to print on TextView
}
}
setEMPInfo class
public class setEMPInfo extends AsyncTask<Void, Void, Employee>
{
Public Employee person;
protected Bus doInBackground(String... params) {
String id = "100A";
String Fname = "John";
String Lname = "Smith";
for (int i = 0; i < 10; i++) {
person = new Employee(id, Fname, Lname);
}
return person;
}
}
Try this :
public class TestActivity extends Activity {
ListView list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
list = (ListView) findViewById(R.id.list_item);
setEMPInfo task = new setEMPInfo().execute();
}
private class setEMPInfo extends AsyncTask<Void, Void, ArrayList<Employee>> {
#Override
protected ArrayList<Employee> doInBackground(Void... params) {
String id = "100A";
String Fname = "John";
String Lname = "Smith";
ArrayList<Employee> employees = new ArrayList<>();
for (int i = 0; i < 10; i++) {
person = new Employee(id, Fname, Lname);
employees.add(person);
}
return employees;
}
#Override
protected void onPostExecute( ArrayList<Employee>result)
//print it on a ListView
list.setAdapter(new YourAdapret(getApplicationContext(), result));
}
}
}
when your doInBackground done , its return some value to onPostExecute . then you can do anything (save in database , save in SDcard , etc) in this method .
You have here an example of a complete asyncTask (by google docs).
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
You can create a static object in your caller class and change it in onPostExecute for example.
The problem is that your class setEMPInfo extends AsyncTask<Void, Void, Employee> and not AsyncTask<String, Void, Bus>
The fix is to change (inside your setEMPInfo class)
protected Bus doInBackground(String... params) { ... }
to
protected Employee doInBackground(String... params) { ... }
and
public class setEMPInfo extends AsyncTask<Void, Void, Employee>
to
public class setEMPInfo extends AsyncTask<String, Void, Employee>
Also, don't forget the #Override annotation.
Finally, I recommend you use an IDE to automatically fix your code spelling and other common mistakes. This problem wouldn't happen in Android Studio or Eclipse. :)
So basically, your code should look like that :
SetEMPInfo.java
public class SetEMPInfo extends AsyncTask<String, Void, Employee>
{
public Employee person;
#Override
protected Employee doInBackground(String... params)
{
String id = "100A";
String Fname = "John";
String Lname = "Smith";
person = new Employee(id, Fname, Lname);
return person;
}
}
Menu.java
public class Menu
{
public Employee person;
public void onButtonClick(View v)
{
new SetEMPInfo()
{
#Override
protected void onPostExecute(Employee employee)
{
doSomething(employee);
}
}.execute();
}
public void doSomething(Employee person)
{
//use person object to print on TextView
}
}
Try this
btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new setEMPInfo() {
protected void onPostExecute(Employee person) {
doSomething(person);
}
}.execute();
}
}
);
here just for testing add all employee to list-
public void doSomething(Employee person) {
eList.add(person);
Log.e("Emp->", eList.toString());
}
Your AsyncTask should look like this-
class setEMPInfo extends AsyncTask<Employee, Void, Employee> {
Employee person;
#Override
protected Employee doInBackground(Employee... params) {
String id = "100A";
String Fname = "John";
String Lname = "Smith";
for (int i = 0; i < 10; i++) {
person = new Employee(id, Fname, Lname);
}
return person;
}
}

Categories