Страницы

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

суббота, 21 декабря 2019 г.

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

#android #json #listview #api #rest

Хочу разобраться разобраться как правильно организовать 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 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 {

        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


Ответы

Ответ 1



Многократно уже отписывался на эту тему, как писать 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 это уже будет "из коробки"

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

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