简体   繁体   中英

How do I return a value from onResponse

Basically this it the code structure, I would like to know how i can modify my codes so that I can get the value inside onResponse and returning it. As of now, my mainReply variable return "(blank)" but im expecting it to pass the data in the arraylist called details inside my onResponse segment. Rest assure, there are values returned as I have checked, but i just cant get the value to be passed out of the onResponse segment.

I have checked for alternatives and they mentioned to use interface. However, I do not know how to modify my codes to use the solution that mentioned interface and use of callBacks.

public class MainActivity extends AppCompatActivity {

    EditText et_message;
    FloatingActionButton fab_send;
    API api;
    ListView list_view_conversation;
    List<ChatModel> list_chat = new ArrayList<>();
    RevealDetailsCallbacks callback;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        et_message = (EditText) findViewById(R.id.et_message);
        fab_send = (FloatingActionButton) findViewById(R.id.fab_send);
        list_view_conversation = (ListView) findViewById(R.id.list_view_conversation);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(API.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        api = retrofit.create(API.class);

        fab_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //this method ultimately is to get response and send back to user
                String s = et_message.getText().toString();
                ChatModel model = new ChatModel(s, true);
                list_chat.add(model);
                new retrieveDetails().execute(list_chat);

                et_message.setText("'");
            }
        });

    }

    public class retrieveDetails extends AsyncTask<List<ChatModel>, Void, String> {
        String text = et_message.getText().toString();
        String mainReply = "";
        List<ChatModel> models;
        List<String> details = new ArrayList<String>();

        @Override
        public String doInBackground(List<ChatModel>[] lists) {
            Call<List<Patient>> call = api.getPatients();
            models = lists[0];
            call.enqueue(new Callback<List<Patient>>() {
                public String reply;

                @Override
                public void onResponse(Call<List<Patient>> call, Response<List<Patient>> response) {
                    List<Patient> patients = response.body();

                    for (int i = 0; i < patients.size(); i++) {
                        if (patients.get(i).getNric().equals(text)) {
                            details.add("Name: " + patients.get(i).getName() + "\nNRIC: " + patients.get(i).getNric()
                                    + "\nDOB: " + patients.get(i).getDob() + "\nContact No: " + patients.get(i).getContactno());
                        }
                    }
                    this.mainReply = details.get(0);
                    Log.i("Here Log i", reply);
                }

                @Override
                public void onFailure(Call<List<Patient>> call, Throwable t) {
                    Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
                }
            });
            return mainReply;//I want to reply with the data added into the details arraylist in the onResponse segment
        }


        @Override
        public void onPostExecute(String s) {
            ChatModel chatModel = new ChatModel(s, false);
            models.add(chatModel);
            CustomAdapter adapter = new CustomAdapter(models, getApplicationContext());
            list_view_conversation.setAdapter(adapter);
        }
    }


}

If you wanted to modify your existing code, you would add an interface like the one I added up top (RevealDetailsCallbacks), pass it into the asynctask constructor, and run it. The code would look like this:

public class MainActivity extends AppCompatActivity {

    //Interface callback here
    interface RevealDetailsCallbacks {
        public void getDataFromResult(List<String> details);
    }

    EditText et_message;
    FloatingActionButton fab_send;
    API api;
    ListView list_view_conversation;
    List<ChatModel> list_chat = new ArrayList<>();
    RevealDetailsCallbacks callback;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        et_message = (EditText) findViewById(R.id.et_message);
        fab_send = (FloatingActionButton) findViewById(R.id.fab_send);
        list_view_conversation = (ListView) findViewById(R.id.list_view_conversation);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(API.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        this.callback = new RevealDetailsCallbacks() {
            @Override
            public void getDataFromResult(List<String> details) {
                //Do stuff here with the returned list of Strings
            }
        };

        api = retrofit.create(API.class);

        fab_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //this method ultimately is to get response and send back to user
                String s = et_message.getText().toString();
                ChatModel model = new ChatModel(s, true);
                list_chat.add(model);
                new retrieveDetails(callback).execute(list_chat);

                et_message.setText("'");
            }
        });

    }

    public class retrieveDetails extends AsyncTask<List<ChatModel>, Void, String> {
        String text = et_message.getText().toString();
        String mainReply = "";
        List<ChatModel> models;
        List<String> details = new ArrayList<String>();
        private RevealDetailsCallbacks listener;

        retrieveDetails(RevealDetailsCallbacks listener){
            this.listener = listener;
        }

        @Override
        public String doInBackground(final List<ChatModel>[] lists) {
            Call<List<Patient>> call = api.getPatients();
            models = lists[0];
            call.enqueue(new Callback<List<Patient>>() {
                public String reply;

                @Override
                public void onResponse(Call<List<Patient>> call, Response<List<Patient>> response) {
                    List<Patient> patients = response.body();

                    for (int i = 0; i < patients.size(); i++) {
                        if (patients.get(i).getNric().equals(text)) {
                            details.add("Name: " + patients.get(i).getName() + "\nNRIC: " + patients.get(i).getNric()
                                    + "\nDOB: " + patients.get(i).getDob() + "\nContact No: " + patients.get(i).getContactno());
                        }
                    }
                    this.mainReply = details.get(0);
                    Log.i("Here Log i", reply);
                    if(listener != null) {
                        listener.getDataFromResult(details);
                    }
                }

                @Override
                public void onFailure(Call<List<Patient>> call, Throwable t) {
                    //Don't make a toast here, it will throw an exception due to it being in doInBackground
                    //Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
                }
            });
            return mainReply;//I want to reply with the data added into the details arraylist in the onResponse segment
        }


        @Override
        public void onPostExecute(String s) {
            ChatModel chatModel = new ChatModel(s, false);
            models.add(chatModel);
            CustomAdapter adapter = new CustomAdapter(models, getApplicationContext());
            list_view_conversation.setAdapter(adapter);
        }
    }
}

However, there is no need for asynctask here since you are running Retrofit and calling .enqueue, which runs on a background thread. A simpler version would look like this:

public class MainActivity extends AppCompatActivity {

    //Interface callback here
    interface RevealDetailsCallbacks {
        public void getDataFromResult(List<String> details);
    }

    //Keep your same variables here

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Same setup here

        this.callback = new RevealDetailsCallbacks() {
            @Override
            public void getDataFromResult(List<String> details) {
                //Do stuff here with the returned list of Strings
            }
        };


        fab_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //Same setup here, then call the method
                makeWebCalls();
            }
        });

    }

    private void makeWebCalls(){
        Call<List<Patient>> call = api.getPatients();
        models = lists[0];
        call.enqueue(new Callback<List<Patient>>() {
            @Override
            public void onResponse(Call<List<Patient>> call, Response<List<Patient>> response) {
                //Run your response code here. When done, pass to the callback
            }

            @Override
            public void onFailure(Call<List<Patient>> call, Throwable t) {
                Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }
}

You can just enqueue the Retrofit call immediately in the OnClick and handle its response there

fab_send.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            final String text = et_message.getText().toString();
            // if you're trying to filter data, add a parameter to getPatients() 
            api.getPatients().enqueue(new Callback<List<Patient>>() {
                 @Override
                 public void onResponse(Call<List<Patient>> call, Response<List<Patient>> response) {
                     // Here you have a full list of patients 
                     final List<Patient> patients = response.body();

                     // adapter = new PatientAdapter(MainActivity.this, patients);
                    // mListView.setAdapter(adapter);
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM