Android - How to pass interface to AsyncTask - java

I'm trying to figure out how to create an AsyncTask that runs my php API code in the background then alerts my MainActivity once it completes. I've been reading tutorials and trying things for hours now and I'm just frustrated at this point as I can't find anywhere that answers my question.
I create the AsyncTask and it runs successfully and I can log the returned information from my API in the onPostExecute but I cannot figure out how to alert the MainActivity that the task was completed. I do not know what to pass into the creation of the APICall. Every tutorial I read shows that the AsyncTask constructor takes the interface as an argument as shown in my code below, but how do you pass an interface as an argument?
MainActivity.java (implements OnTaskCompleted)
myButton4.setOnClickListener(new OnClickListener(){
public void onClick(View v){
APICall api = new APICall( ???What do I put here?? );
api.execute("users");
}});
....
#Override
public void onTaskCompleted() {
Log.v("Play","Main Activity ON Task completed!");
OnTaskCompleted.java
public interface OnTaskCompleted {
public void onTaskCompleted();
}
APICall.java (extends AsyncTask)
public APICall(OnTaskCompleted listener){
this.listener = listener;
}
....
protected void onPostExecute(JSONObject j)
{
listener.onTaskCompleted();
}

You should pass the reference of your listener to the APICall class:
APICall api = new APICall(MainActivity.this);

Simple you can use anonymous interface instance like this.
myButton4.setOnClickListener(new OnClickListener(){
public void onClick(View v){
APICall api = new APICall(new OnTaskCompleted() {
#Override
public void onTaskCompleted() {
}
});
api.execute("users");
}});
OR you can Implement interface at class level like this
public class MainActivity extends Activity implements MainActivity.OnTaskCompleted {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButton4.setOnClickListener(new OnClickListener(){
public void onClick(View v){
APICall api = new APICall(MainActivity.this);
api.execute("users");
}});
}
#Override
public void onTaskCompleted() {
// Do your code on task complete
}
}

APICall api = new APICall( ???What do I put here?? );
What do I put here??
The one that implements your listener in this case your MainActivity
APICall api = new APICall(MainActivity.this);

Related

Class A function calls a function in Class B , Once it's completed how to get notification to Class A (Android Java)

Here is the thing that I need to do.
When the user click on a button on an activity , the app must call a function in different class and sent back a notification to the activity. Then the activity shows those information in the main screen.
(Let's say the function is to receive firebase data and add it to a sqlite database. Once the data retrieval is complete ,I want to populate those information in the activity )
Is there any way to do this without using Room database
Currently I am writing the method in the activity class and redirect from there to populate data. Here is a example how I currently use it
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("server/saving-data/fireblog/posts");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int counter = dataSnapshot.size();
for(int i =0; i<counter;i++){
Post post = dataSnapshot.getValue(Post.class);
// Add to sqlite data
if(i=counter) {
// Populate Data in activity
}
}
}
The Thing i want to do it ,I want to take this function code to a sepeate class and run from the activity and get a callback.
I am a newbie and don't have a idea how to do this. Thank you
I found a solution myself.
first you need to create interface , as an example let's take this >
public interface ActionListenerCallback {
public void onActionSuccess(String successMessage);
public void onActionFailure(Throwable throwableError);
}
After that you need to implement this in the activity where you called the function
public class Act_Reps extends AppCompatActivity implements ActionListenerCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
RealtimeDB RDB= new RealtimeDB(this,Id);
RDB.setCallback(this);
RDB.callingFunction();
}
#Override
public void onActionSuccess(String successMessage) {
Log.d("Log", "Message "+ successMessage);
}
#Override
public void onActionFailure(Throwable throwableError) {
}
}
Here is the class where the function is called
public class RealtimeDB {
ActionListenerCallback callback;
public void setCallback(ActionListenerCallback callback) {
this.callback = callback;
}
public void callingFunction(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
callback.onActionSuccess("Done");
}
}, 5000);
}
}

use OnClick from different class android

this is probably simple but i am still a beginner
i have a button in class MainActivity and i want to use the onclick method in another class(another activity) i am aware that it could be easily achieved by making it public static and accessing it as instance but in my case i can not make it public static for some good reason
button xml:
<Button
android:id="#+id/googledrivemain"
android:layout_width="78dp"
android:layout_height="77dp"
android:layout_marginTop="149dp"
android:background="#drawable/google"
android:onClick="onClickOpenFile"
android:paddingTop="6dp"
android:textColor="#fff"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/imageView3"
app:layout_constraintHorizontal_bias="0.51" />
MainActivity button:
public void onClickCreateFile(View view) {
fileOperation = true;
// create new contents resource
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(driveContentsCallback);
}
second class button:
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity main = new MainActivity();
use onclick from mainactivity...??
}
});
Do it like this
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity) getActivity()).onClickCreateFile(v);
}
});
i think it will work.
Simply wrap the code you invoke from the MainActivity.onClickCreateFile() into another class and call it from wherever you want
And never, NEVER, do something like new MainActivity(). Activities are managed by the system
You can create a handler class, something like this:
public static class ClickHandler {
private ClickHandler mInstance;
public static ClickHandler getInstance(){
if(mInstance == null){
mInstance = new ClickHandler();
}
return mInstance;
}
public void onClickCreateFile(View view) {
fileOperation = true;
// create new contents resource
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(driveContentsCallback);
}
}
Then wherever you need it:
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ClickHandler.getInstance().onClickCreateFile(view);
}
});
The reason you can't make a click method static is that 1) The android:onClick XML action requires public void and 2) The view that you are clicking belong to the instance of the activity, not the class.
You could make a static method like this.
public static void createDriveContents(GoogleApiClient apiClient, ResultCallback callback) {
Drive.DriveApi.newDriveContents(apiClient)
.setResultCallback(callback);
}
But, then you still need a reference to the GoogleApiClient object.
Since no client is bound to any one Activity, you could move it into a singleton in order to access one client instance from everywhere.
For example,
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity.createDriveContents(
GoogleClientWrapper.getInstance().getClient(), // A GoogleApiClient instance
new ResultCallback() {
// TODO: Implement
});
}
});
If you have access to the GoogleClient in the second class, just pass in the API client object directly.
Or, abstracting up one level, you can instead provide a Context, and re-build the client.
public static void createDriveContents(Context context, ResultCallback callback) {
GoogleApiClient client = new GoogleApiClient.Builder(context);
// TODO: add scopes to client
Drive.DriveApi.newDriveContents(apiClient)
.setResultCallback(callback);
}
With this method, we assume the second class is another activity without it's own GoogleClient
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity.createDriveContents(
SecondClass.this, // A Context instance
new ResultCallback() {
// TODO: Implement
});
}
});

How to pass onClick function to Intent

I want to modularize the usage of my class but I have problem in passing function. I want to be able to pass an OnClickListener from 1 activity to this CoachmarkActivity.
I tried 2 different method:
1. Passing an OnClickListener to Intent
2. Passing a class, FollowUpClass, implements Serializable, which has method onClick.
You can see the code below. It is not complete code, but you should be able to comprehend this.
public class CoachmarkActivity extends Activity {
public static final String RES_LAYOUT = "RES-LAYOUT";
public static final String LISTENER = "LISTENER";
public static final String FOLLOW_UP = "FOLLOW-UP";
#Override protected void onCreate(Bundle savedInstance) {
setContentView(getIntent.getIntExtra(RES_LAYOUT, R.layout.activity_default))
Button button1 = (Button) findViewById(R.id.button1);
Button button2 = (Button) findViewById(R.id.button2);
// 1ST ATTEMPT
// I want to modularize this
OnClickListener onClickPassedFromIntent = (OnClickListener) getIntent().getSerializableExtra(LISTENER);
button1.setOnClickListener(onClickPassedFromIntent);
// 2ND ATTEMPT
final FollowUpListener folllowup = (FollowUpListener) getIntent().getSerializableExtra(FOLLOW_UP);
button2.setOnClickListener(new OnClickListener() {
#Override void onClick() {
// !! Here is error, exception thrown
folllowup.onClick();
}
});
}
/**
* Public method to be used in other activity.
* Invocation wanna be:
* CoachmarkActivity.startThisActivity(getActivity(), R.layout.coachmark1, new OnClickListener() {
* #Override void onClick() {
* // Do something
* }
* });
*/
public static void startThisActivity(Context context, int resId, OnClickListener listener) {
Intent intent = new Intent(context, CoachmarkActivity.class);
intent.putExtra(RES_LAYOUT, resId);
// !! Line below is error, onClickListener is not serializable, no method can accomadate below
intent.putExtra(LISTENER, listener);
context.startActivity(intent);
}
/**
* Public method to be used in other activity.
* Invocation wanna be:
* CoachmarkActivity.startThisActivity(getActivity(), R.layout.coachmark1, new FollowUpListener() {
* #Override void onClick() {
* // Do something
* }
* });
*/
public static void startThisActivity(Context context, int resId, FollowUpListener folllowup) {
Intent intent = new Intent(context, CoachmarkActivity.class);
intent.putExtra(RES_LAYOUT, resId);
intent.putExtra(FOLLOW_UP, followup);
context.startActivity(intent);
}
}
The abstract class:
public abstract class FollowUpListener implements Serializable {
public abstract void onClick();
}
The problems are stated in the comment in source code above, with tag "!!" (Just CTRL+F "!!"). What I want to do is like passing a Delegate object (function in form of variable) in C#, but in Android Java.
Any idea? Thanks.
You are trying to add a Serializable extra to your Intent, but OnClickListener does not implement that interface. You can achieve what you want by creating a class that implements both of the interfaces you need.
private class SerializableClickListener implements View.OnClickListener, Serializable {
#Override public void onClick() {
// TODO handle click
}
}
However, just because you can doesn't mean you should. Sending a click listener to another activity is a horrible code smell, and you should really rethink how you could do this via Intents/Broadcasts.
I tried to pass the OnlclickListener and I couldn't. then I tried this solution.
I made a static click listener variable in a GlobalData class
public static View.OnClickListener btn;
Then when I call the startactivity to go to another activity I did this.
GlobalData.btn = new View.OnClickListener() {
#Override
public void onClick(View v) {
//Listern action
}
};
c.startActivity(new Intent(c, DialogActivity.class));
Then in the second activity, I can set the static listener reference which I used to assign a listener object in the first activity.
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(GlobalData.btn!=null){
GlobalData.btn1.onClick(v);
}
finish();
}
});
I didn't use it directly as a parameter so I can do other stuff in the second activity listener. this worked for me.
But you have to think more because you are using a static reference. this is not a 100% solution. but it's worth trying.

Callback inside anonymous functions, not getting the syntax propely

I am trying to implement a void method callback inside an anonymous class and I am a bit lost with the syntax since I working on a large android code-base. I have set a listener to and image button like so:
MyImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
OnFollowingClick click;
click = new OnMyClick(param1, param2); // irrelevant for this thread
click.onClick(view); // irrelevant for this thread
// my problem is here!
click.setCallback( what do I pass in here? and where can define my callback?);
}
});
Here is the OnMyClick class and the void callback interface I defined:
public interface CallbackInterface {
public void Callback();
}
public class OnMyClick implements View.OnClickListener {
// I added this
CallbackInterface mCallBack;
public void setCallback(CallbackInterface callback) {
this.mCallBack = callback;
}
// Please call my callback
public void onFollowingChanged() {
if (mCallBack != null) {
mCallBack.Callback();
}
}
// a bunch of code in here that does not matter
// ...
I have to create callback somewhere, so I am guessing I need something like:
public class SomeClass implements CallbackInterface {
#Override
public void Callback() {
System.out.println("Hey, you called.");
}
}
The problem is that listener is an anonymous function, so I don't want to define a separate class somewhere just to serve as a callback.
I looked at this thread but did not give me much info:
How can an anonymous class use "extends" or "implements"?
is there a way to make the anonymous function implement my interface inside the scope, like:
MyImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void Callback() {
// please call me!
}
Not sure if it made sense, buy any help is greatly appreciated.
thx!
Just define the callback anonymously like you are already doing with the View.OnClickListener.
MyImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
OnFollowingClick click;
click = new OnMyClick(param1, param2); // irrelevant for this thread
click.onClick(view); // irrelevant for this thread
// your solution is here!
click.setCallback(new CallbackInterface() {
#Override
public void Callback() {
System.out.println("Hey, you called.");
}
});
}
});
If this is not what you meant then please clarify and I will try and help further.

Calling method from another class in onPostExecute causing nullPointerException

This might help someone also: How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?
I am calling method from another class in onPostExecute().
I assume that onPostExecute() is called after doInBackground(String... params) and that is right, according to documentation and debugger.
Calling the method:
protected void onPostExecute(String result) {
CreateHangOut crtHO = new CreateHangOut();
crtHO.createHangOut(result);
}
Part of method called, causing NPE (first line of method):
public void createHangOut(String location) {
String city=autocompleteTV.getText().toString();
}
Autocomplete TextView(autocompleteTV) is initialized onCreate of the activity.
Here is how I call AsyncTask:
create.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new
HTTPRequest().execute((autocompleteTV.getText()).toString());
}
});
Method called onCreate (of activity from where button is clicked) :
private void initialize() {
gAPI= new GoogleAPIAutocomplete();
autocompleteTV = (AutoCompleteTextView)
findViewById(R.id.crtHOLocOptionsTV);
setUpAutocomplete();
create = (Button) findViewById(R.id.crtHOCreateBtn);
name =(EditText) findViewById(R.id.crtHONameET);
create.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new
HTTPRequest().execute((autocompleteTV.getText()).toString());
}
});
}
Because createHangOut method is in CreateHangOut Activity so no need to create new object for accessing method just call it using method name if class which extends AsyncTask class is inner class of CreateHangOut :
protected void onPostExecute(String result) {
CreateHangOut.this.createHangOut(result);
}

Categories