I
I
ilitaexperta2018-04-03 04:27:17
Android
ilitaexperta, 2018-04-03 04:27:17

Best practice for Android client-server applications?

How is it customary to make client-server applications on Android in 2018? I can't google normal best practice. Everywhere a zoo of freaks. AsyncTask, AsyncTaskLoader, IntentService, custom shit wrappers like RoboSprice, Pattern A\B\C, etc.
What is the current best practice? Do an IntentService, put it in the database, and then notify the Activity through the BroadcastReceiver and read back from the database? It doesn't look very appropriate. Maybe there are more sane ways?
In normal operating systems, everything is simple: you make an asynchronous request in a callback, save it to some local cache, then update the desired UI. In android, there are a lot of problems with this, turning the activity, etc.
I want the simplest solution, with a minimum of junk code, crutches, overengineering and fat dependencies of the RxJava type and all hellish nonsense like MVP. It's amazing that to do a trivial task, you have to drag all sorts of crutches.

Answer the question

In order to leave comments, you need to log in

5 answer(s)
S
Sergey Vashchenko, 2018-04-03
@Simipa

RxJava + RxAndroid

A
awesomer, 2018-04-03
@awesomer

take something ready-made like Google Firebase as a basis
and see examples for it.

V
Vladimir Yakushev, 2018-04-12
@VYakushev

If MVP and Rxjava are crutches for you, then look towards Google's ViewModel, LiveData, etc. The site for android developers has examples of use. True, you will again have a "crutch" in the form of MVVM from Google, but no problems with screen rotation.

D
Dmtm, 2018-04-12
@Dmtm

if the "simplest solution" is without libraries, then
these are requests in Thread, Thread stored in Application, data layer - singleton also with binding to Application
data layer - map of the form <url, object>where object is the deserialized response
of the broadcast to send messages about the results of the request (if not I want to mess around with broadcasts, that is, EventBus)
i.e. the request changes the data, the date layer notifies about the change, the consumer himself takes the data
for simple projects, it will do, but then the difficulties will begin
such as the atomicity of a business operation consisting of several requests (hello RxJava) or saving the state of the screen (including with dynamic views) - (hello Moxy), even just wait for the Internet to appear and re-execute the request from the queue - you will have to write everything yourself

I
ilitaexperta, 2018-04-27
@ilitaexperta

In general, I found an acceptable approach, maybe it will come in handy for someone:
Thus:
I threw a simplified code example, some places are omitted for simplicity.
Query layer

public class Requests
{
  public interface OnCompleteListener
  {
    default void onSomeMethod1(JsonElement answer) {}
    default void onSomeMethod2(JsonElement answer) {}

    default int getPriority() { return 0; }
  }

  private static class RequestTask extends AsyncTask<Void, Void, String>
  {
    public RequestTask(String method)
    {
      this.method = method;
    }

    private String method;

    @Override
    protected String doInBackground(Void ... params)
    {
      // Тут делаем запрос к серверу
      // ...
    }

    @Override
    protected void onPostExecute(String result)
    {
      handleAnswer(result);
    }
  }

  private static List<OnCompleteListener> listeners = new ArrayList<>();

  private static void handleAnswer(String answer)
  {
    for(OnCompleteListener listener : listeners)
    {
      if(methodName.equals("api/method1")) listener.onSomeMethod1(answer);
      else if(methodName.equals("api/method2")) listener.onSomeMethod2(answer);
                }
  }

  private static void makeRequest(String method)
  {
    new RequestTask(method).execute();
  }

  public static void registerListener(OnCompleteListener listener)
  {
    listeners.add(listener);

    Collections.sort(listeners, (l1, l2) -> l2.getPriority() - l1.getPriority());
  }

  public static void unregisterListener(OnCompleteListener listener)
  {
    listeners.remove(listener);
  }

  public static void method1()
  {
    makeRequest("api/method1");
  }

  public static void method2()
  {
    makeRequest("api/method2");
  }
}

Activity
public class MainActivity extends AppCompatActivity implements Requests.OnCompleteListener
{
  // ...

  @Override
  protected void onPause()
  {
    super.onPause();

    Requests.unregisterListener(this);
  }

  @Override
  protected void onResume()
  {
    super.onResume();

    Requests.registerListener(this);
    updateView();
  }

  private void updateView()
  {
    String someData = Data.getSomeData();

    // Тут обновляем вьюшки в активити
    // ...
  }

  @Override
  public void onMethod1(String answer)
  {
    updateView();
  }
}

data layer
public class MyApp extends Application
{
  @Override
  public void onCreate()
  {
    super.onCreate();
    
    Requests.registerListener(Data.listener);
  }
}

public class Data
{
  // Просто какие-то данные для примера
  private static List<String> someDataStorage = new ArrayList<>();

  public static String getSomeData()
  {
    return someDataStorage.last();
  }

  public static Requests.OnCompleteListener listener = new Api.OnCompleteListener()
  {
    @Override
    public void onMethod1(String answer)
    {
      someDataStorage.add(answer);
    }

    public void onMethod2(String answer)
    {
      someDataStorage.add(answer);
    }

    @Override
    public int getPriority()
    {
      return Integer.MAX_VALUE;
    }
  };
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question