Страницы

Поиск по вопросам

пятница, 9 ноября 2018 г.

Как правильно организовать REST-клиент ? Асинхронная загрузка JSON, изображений в базу и отображении в списке

Хочу разобраться разобраться как правильно организовать REST-клиент.
Есть API, которая по запросу выдает JSON объекты.
Нужно построить список ListView(или лучше использовать RecyclerView?) из этих JSON.
Как я это все делаю:
public class MainActivity extends AppCompatActivity {
private static final String API = "https://api.github.com";
ListView listView; UserAdapter adapter; DBHandler mDBhandler;
int lastUserIDinList=0; //начальное кол-во пользователей в списке int initialAmountUsers=10;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
mDBhandler = new DBHandler(this);
listView = (ListView) findViewById(R.id.listview);
adapter = new UserAdapter(MainActivity.this, new ArrayList()); listView.setAdapter(adapter);
new CountUserInDB().execute();
listView.setOnScrollListener(new EndlessScrollListener() { @Override public boolean onLoadMore(int page, int totalItemsCount) { loadUsers(1); return true; } });
}
//получаем от API объекты, ждем коллбэк и запускаем AsyncTask запись в базу(в качестве параметра передаем список моделей) void loadUsers(int count){ RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint(API).build(); GitAPI git = restAdapter.create(GitAPI.class); //полчаем от АПИ пользователей с ид больше lastUserIDinList. количество пользователей в ответе - count git.getNextUsers(lastUserIDinList, count, new Callback>() { @Override public void success(ArrayList gitHubUsers, Response response) { new WriteToDB().execute(gitHubUsers); }
@Override public void failure(RetrofitError error) { Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_LONG).show(); } }); }

//get arralist of users and write it to db class WriteToDB extends AsyncTask,Void,Integer> {
@Override protected void onPreExecute() { super.onPreExecute(); }
@Override protected Integer doInBackground(ArrayList... params) { //заноси в таблицу всех пользователей полученных в коллбэке for(int i=0; i @Override protected void onPostExecute(Integer firstID) { super.onPostExecute(firstID); //вызываем четние из базы с первого ид, который пришел в ответе от АПИ new ReadFromDB().execute(firstID); } }
//get id of userd from what need to read from db class ReadFromDB extends AsyncTask> {
@Override protected void onPreExecute() { super.onPreExecute(); }
@Override protected ArrayList doInBackground(Integer... params) { //читаем из базы всех пользователей, ид которых >= params[0] return mDBhandler.getUserFromID(params[0]); }
@Override protected void onPostExecute(ArrayList userList) { super.onPostExecute(userList); new DisplayUserInListView().execute(userList); } }

//get arralist of users and add it to adapter class DisplayUserInListView extends AsyncTask,Void,Void> { @Override protected void onPreExecute() { super.onPreExecute(); }
@Override protected Void doInBackground(ArrayList... params) { //добавляем по очереди пользователей в адаптер for(int i=0; i @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); //сообщаем, что обновили данные adapter.notifyDataSetChanged(); } }

class CountUserInDB extends AsyncTask {
int lastUserIDinTable=-1;
@Override protected void onPreExecute() { super.onPreExecute(); }
@Override protected Integer doInBackground(Void... params) { //получаем ИД последней записи в таблице lastUserIDinTable=mDBhandler.getLastUseID(); //получаем количество пользователей в таблице return mDBhandler.getUserCount(); }
@Override protected void onPostExecute(Integer userCount) { super.onPostExecute(userCount);
if(userCount==0){ //база пуста, загрузим 10 пользователей для начала loadUsers(10); }
if(userCount>=initialAmountUsers){ //в базе больше 10 пользователей, что достаточно для начала - читаем из базы. new ReadFromDB().execute(0); }
if(userCount>0 && userCount }
} }


}
У меня такое чувство, что сделал какой-то велосипед.
Какие есть советы по улучшение(или переделыванию полностью) логики ? Не много ли я использую AsyncTask ?
Интересны любые советы по грамотному получению JSON объектов, использованию API, добавлением итемов в список..
UPD:
Почитав статьи, пришел к выводу, что REST клиента на андроиде нужно делать по двум вариантам:
1)Создавать сервис, в котором будут загружаться данные с API(), парситься, записываться в базу и потом передавать в активити сообщение, что надо обновить список. Активити как получит такое уведомление, с помощью CursorLoader'а грузит данные из таблицы и добавляет их адаптеру списка.
2)Не создавать сервисов, а в активити с помощью AsyncTaskLoader'ов(для получения инфы в фоне, при этом еще использовать Retrofit) и CursorLoader'ов, с помощью которых читать/писать базу.
Какой из этих подходов более грамотный ? Возможно есть какие-то дополнения или уточнения к этим подходам ?


Ответ

Многократно уже отписывался на эту тему, как писать REST клиента. Не поленюсь написать еще раз:
Через сервис тягаем JSON объекты из сети и складываем в SQLite БД Над SQLite БД создаем ContentProvider и через CursorLoader организуем подпитку CursorAdapter, который и будет адаптером для ListView или RecyclerView Вопрос выбора ListView или RecyclerView - это вопрос не только вкуса, но и квалификации (все таки). Как показывает опыт RecyclerView сложнее в понимании, но дает гораздо большую свободы в плане управления списком. Я бы рекомендовал начинать с ListView и только потом приступать к RecyclerView Для работы с JSon лучшим инструментом является Google Gson - берите его и даже не сомневайтесь. Функция Gson очень простая, но важная: это трансляция вашего Java объекта в Json строку и обратно. По сути вместо рутинного парсинга json строки вы будете иметь дело с интеллигентными Java классами. Часто при работе с Rest требуется реализация функциональности Pull-To-Refresh - ну то есть обновление списка при вытягивании вверх/вниз. В сети есть огромное количество реализаций Pull-To-Refresh. Я пользовался этим проектом - но он сейчас мертвый. Недавно в суппорт либах появился новый виджет: SwipeRefreshLayout я лично не пользовался не знаю как с ним работать. Те из знакомых кто пользовались - пищат от восторга. У меня нет оснований не доверять им.
P.S. Для RecyclerView организовать CursorAdapter напрямую не получится, нужно будет применить эту наработку
Update
Создавать сервис, в котором будут загружаться данные с API(), парситься, записываться в базу и потом передавать в активити сообщение, что надо обновить список. Активити как получит такое уведомление, с помощью CursorLoader'а грузит данные из таблицы и добавляет их адаптеру списка.
В качестве сервиса подойдет IntentService, который можно запускать по таймеру и/или через событие генерируемое при Pull-To-Refresh Не надо никак уведомлять Activity о том, что БД изменилось - CursorLoader сам будет автоматом подгружать обновленные данные при изменении БД через соответствующий Observer (в случае RecyclerView), а в случае CursorAdapter это уже будет "из коробки"

Комментариев нет:

Отправить комментарий