This sequence of actions can be represented in the form of the following diagram:<\/p>\n\n\n\n
In this case, there are many intermediate actions, which will be discussed later. In the meantime, let’s implement such a simple approach. First of all, we modify the service for loading data, so that it stores data in the database and notifies subscribers about this:<\/p>\n\n\n\n
@Override\n\nprotected void onHandleIntent(Intent intent) {\n\n SQLite.get().delete(CityTable.TABLE);\n\n\n\n try {\n\n City city = ApiFactory.getWeatherService()\n\n .getWeather(getString(R.string.default_city))\n\n .execute()\n\n .body();\n\n SQLite.get().insert(CityTable.TABLE, city);\n\n } catch (IOException ignored) {\n\n } finally {\n\n SQLite.get().notifyTableChanged(CityTable.TABLE);\n\n }\n\n}\n\n \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0441\u0435\u0440\u0432\u0438\u0441 \u0432 \u043b\u044e\u0431\u043e\u043c UI-\u043a\u043b\u0430\u0441\u0441\u0435 \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435:\n\nprivate void loadWeather() {\n\n mLoadingView.showLoadingIndicator();\n\n SQLite.get().registerObserver(CityTable.TABLE, this);\n\n startService(new Intent(this, NetworkService.class));\n\n}<\/pre>\n\n\n\nWhen the service loads the data, the subscribed class will receive a notification about it that it can process:<\/p>\n\n\n\n
@Override\n\npublic void onTableChanged(@NonNull List<City> cities) {\n\n if (cities.isEmpty()) {\n\n mCity = null;\n\n showError();\n\n } else {\n\n mCity = cities.get(0);\n\n showWeather();\n\n }\n\n mLoadingView.hideLoadingIndicator();\n\n SQLite.get().unregisterObserver(this);\n\n}<\/pre>\n\n\n\nSuch a decision does not look particularly complicated, but in fact here it is necessary to solve a lot of questions and problems. First, we must correctly handle various life-cycle events and unsubscribe from notifications. That is, we did not leave here the problems that were considered in the framework of the previous lecture. Of course, these problems can be solved by the same means, but I would like that these problems were not at all.<\/p>\n\n\n\n
Secondly, you need to be able to handle errors. In the example above, we looked, if there are no records in the database, then an error occurred. Of course, in any more serious example, this option does not work.<\/p>\n\n\n\n
And thirdly, more precisely, developing the second point, we need to be able to track the status of each request to show the download process and hide it, and also to not re-run an already running query.<\/p>\n\n\n\n
That is why the example above is naive and the simplest implementation of pattern A. In fact, in the original presentation of the pattern, everything is more complicated, but this example was needed to show why these difficulties are needed.<\/p>\n\n\n\n
First of all, we need to create a class that will be responsible for the status and information about each request. This will allow us, and track status, and handle errors. This class must contain the request ID, request status and error body (which will be empty if the request is successful):<\/p>\n\n\n\n
public class Request {\n\n\n\n @NetworkRequest\n\n private final String mRequest;\n\n\n\n private RequestStatus mStatus;\n\n\n\n private String mError;\n\n\n\n public Request(@NonNull @NetworkRequest String request,\n\n @NonNull RequestStatus status,\n\n @NonNull String error) {\n\n mRequest = request;\n\n mStatus = status;\n\n mError = error;\n\n }\n\n}<\/pre>\n\n\n\nCreate a table for this class. After that, in UI-classes we will always subscribe to changes of this table with the status (ideally, of course, it should be subscription to a separate element, but it is more difficult to implement).<\/p>\n\n\n\n
After that we rework the service for queries as follows (due to the fact that the code has significantly increased, we will quote it in parts):<\/p>\n\n\n\n
@Override\n\nprotected void onHandleIntent(Intent intent) {\n\n Request request = SQLite.get().querySingle(RequestTable.TABLE);\n\n if (request != null && request.getStatus() == RequestStatus.IN_PROGRESS) {\n\n return;\n\n }\n\n if (request == null) {\n\n request = new Request(NetworkRequest.CITY_WEATHER, RequestStatus.IN_PROGRESS, \"\");\n\n } else {\n\n request.setStatus(RequestStatus.IN_PROGRESS);\n\n }\n\n SQLite.get().insert(RequestTable.TABLE, request);\n\n SQLite.get().notifyTableChanged(RequestTable.TABLE);\n\n \/\/...\n\n}<\/pre>\n\n\n\nFirst, we get the current record of requesting weather information. If this request is IN_PROGRESS, that is, already in the process of execution, then we ignore this new call.<\/p>\n\n\n\n
After that we translate the request into the IN_PROGRESS status and notify the subscribers (this is necessary for the UI classes to display the download process).<\/p>\n\n\n\n
Let’s continue the consideration of the method:<\/p>\n\n\n\n
\/\/...\n\ntry {\n\n City city = ApiFactory.getWeatherService()\n\n .getWeather(getString(R.string.default_city))\n\n .execute()\n\n .body();\n\n SQLite.get().delete(CityTable.TABLE);\n\n SQLite.get().insert(CityTable.TABLE, city);\n\n request.setStatus(RequestStatus.SUCCESS);\n\n} catch (IOException e) {\n\n request.setStatus(RequestStatus.ERROR);\n\n request.setError(e.getMessage());\n\n} finally {\n\n SQLite.get().insert(RequestTable.TABLE, request);\n\n SQLite.get().notifyTableChanged(RequestTable.TABLE);\n\n}<\/pre>\n\n\n\nHere everything is simple. We get the result from the server, store them in the database and depending on the success \/ failure when retrieving the data we translate the status either in SUCCESS or in ERROR. And notify subscribers about the completion of the request.<\/p>\n\n\n\n
The UI part can process these notifications as follows (here RxJava tools are used to provide asynchrony when working with the database.) RxJava will be considered in the next lecture, but in the meantime we will comment on the code in detail)<\/p>\n\n\n\n
When we receive a notification about changing the data in the table, we read the status of the request from the database. After that, we choose the actions depending on this status:<\/p>\n\n\n\n