Задать вопрос
Sanu0074
@Sanu0074

Как правильно реализовать callback в java?

Я недавно начал для себя изучать Android и собственно java, до этого всегда писал на nodeJS, и за долгое время очень привык к js.

И вот, в процессе изучения, настал момент, когда я решил написать один единственный класс который будет отправлять запросы, и в результате ошибки или успеха будет выполнять соответствующие методы класса из которого мы и шлем этот запрос.

Есть класс MainActivity в котором по клику на кнопку шлем запрос на сервер и ответ вставляем в TextView. Сейчас я реализовал коллбэки таким образом:

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {

protected void onCreate(Bundle savedInstanceState) {


sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DoRequestClass doRequestClass = new DoRequestClass(){

                    @Override
                    public void onOK(JSONObject response) {
                        successReq(response);
                    }

                    @Override
                    public void onError(VolleyError error) {
                        errorReq(error);
                    }
                };
            doRequestClass.execute("http://myserver.local", MainActivity.this);
        }
    });


public void successReq(JSONObject response){
    txtDisplay.setText("Response => "+response.toString());
}

public void errorReq(VolleyError error){
    txtDisplay.setText("Error => "+error.toString());
}

// other methods


Такой вот для теста абстрактный класс DoRequestClass

public abstract class DoRequestClass implements DoRequestInterface {

    @Override
    public void execute(String url, Context context) {
        RequestQueue queue = Volley.newRequestQueue(context);

        JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {

            @Override
            public void onResponse(JSONObject response) {
                DoRequestClass.this.onOK(response);
            }

        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                DoRequestClass.this.onError(error);
            }

        });

        queue.add(jsObjRequest);
    }
}


С интерфейсом DoRequestInterface

interface DoRequestInterface {
    void execute(String url, Context context);

    void onOK(JSONObject response);

    void onError(VolleyError error);
}


Все описанное выше работает, но можно ли как-то передать successReq и errorReq в DoRequestClass таким образом, как бы мы это делали это на javascript, о то что я имею ввиду, о желанном результате, смотрите как бы я хотел примерно чтоб они передавались:

sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DoRequestClass doRequestClass = new DoRequestClass();
                doRequestClass.setSuccessCallback(successReq);
                doRequestClass.setErrorCallback(errorReq);
                doRequestClass.execute("http://lessons.flexiblejs.ru/test.php", MainActivity.this);
            }
        });


Как вы поняли из кода выше, setSuccessCallback и setErrorCallback это методы которые будут говорить классу DoRequestClass какие методы класса MainActivity нужно выполнить после успешного или не успешного запроса.

Такое или подобное прекрасно работало бы в javascript'e, но такой java-код работать не будет. Вопрос в том, как создать что-то такое или приближенное к этому? И возможно ли вообще? Суть в том чтобы не писать лишний код и создавать лишнее методы типа как в моем рабочем примере onOK и onError.

Прошу вас по возможности дать как можно более развернутый ответ с пояснениями, т.к. мои познания в java совсем не велики.
  • Вопрос задан
  • 9933 просмотра
Подписаться 1 Оценить Комментировать
Решения вопроса 1
VYakushev
@VYakushev
Разработчик Android в Nowtaxi
Callback надо реализовать в виде отдельного интерфейса и сказать, что наше активити реализует этот интерфейс. В результате мы в DoRequestInterface просто передаем ссылку на нашу активити. А в активити реализуем нужные два метода для Callback. Во избежание утечек, рекомендую callback оборачивать в мягкую ссылку.
interface DoRequestInterface {
    void execute(String url, DoRequesCallback callback);
}

interface DoRequesCallback {
    void successReq(JSONObject response);
    void errorReq(VolleyError error);
}

public abstract class DoRequestClass implements DoRequestInterface {
	@Override
  public void execute(String url, DoRequesCallback callback) {
      RequestQueue queue = Volley.newRequestQueue(context);
			final WeakReference<DoRequesCallback> weakCallback = new WeakReference<DoRequesCallback>(callback);
      JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
          @Override
          public void onResponse(JSONObject response) {
							DoRequesCallback callback = weakCallback.get();
							if (callback != null) {
              	callback.successReq(response);
							}
          }
      }, new Response.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError error) {
						DoRequesCallback callback = weakCallback.get();
						if (callback != null) {
            	callback.errorReq(error);
						}
          }

      });
      queue.add(jsObjRequest);
  }
}

public class MainActivity extends AppCompatActivity implements DoRequesCallback {
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		sendButton.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
          	DoRequestClass doRequestClass = new DoRequestClass();
	          doRequestClass.execute("http://myserver.local", this);
		      }
		  });
	}

	@Override
	public void successReq(JSONObject response){
	    txtDisplay.setText("Response => "+response.toString());
	}

	@Override
	public void errorReq(VolleyError error){
	    txtDisplay.setText("Error => "+error.toString());
	}
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
leahch
@leahch
3D специалист. Dолго, Dорого, Dерьмово.
Вам поможет шаблон проектирования observer - https://ru.m.wikipedia.org/wiki/Наблюдатель_(шабло...
Смотрите реализацию на java.
Ответ написан
@ipc_ngs
Чтобы передавать методы в качестве параметров, можно воспользоваться лямбдами и ссылками на методы в Java8, смотрите https://habrahabr.ru/post/224593/
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы