TabLayout или DatePicker - вкладка переключения не обновляется, то же самое с DatePicker - PullRequest
3 голосов
/ 22 мая 2019

Я написал небольшое приложение для Android, которое будет собирать данные из JSON API, отображать график из этих данных и вычислять общее количество данных в графике (данные являются выходными данными установки PV).

Приложение использует TabLayout для отображения графиков для ежедневного, ежемесячного, годового и общего обзора.

Моя идея состоит в том, чтобы иметь средство выбора даты, чтобы изменить дату, для которой данные извлекаются и отображаются. Для этого я использую TextView со связанным DatePicker. Новые данные извлекаются и рассчитываются, так как я вижу, как обновляется сумма при изменении контрольной даты.

Однако при выборе другой даты график не сразу обновляется новыми данными, и график очищается / очищается.
Мне нужно еще 2 вкладки, а затем вернуться на правильную вкладку или повернуть устройство, чтобы получить график в этой вкладке для отображения правильных данных.
Как только новые данные визуализируются во вкладке, изменение данных снова очищает график. Возвращение к тем же данным показывает правильный график.

Дата также не распространяется на вкладки. Изменение даты на 1 вкладке не меняет ее на следующую. При входе в систему getItem в MyPagerAdapter я заметил, что переключение с вкладки 0 на вкладку 1 вызывает запрос на вкладку 2, а переход с вкладки 3 на вкладку 2 загружает вкладку 1. Я предполагаю, что это какая-то предварительная загрузка ? Возможно, это приводит к тому, что изменение дат на вкладке 0 не отражается на вкладке 1, а на вкладке 2, и что мне нужно перейти с вкладки 0 на вкладку 3 обратно на вкладку 1, чтобы получить дату для обновления даты?

Следующие фрагменты кода немного изменены для удобства чтения. То есть Я повторно использую фрагмент вкладки для другого представления данных (день / месяц / год / итог) и использую некоторые переключатели или, если / еще, например. установить правильные метки. В каждом классе есть еще несколько методов, которые, я не думаю, имеют отношение к этой проблеме.

MainActivity.java

Связывает TabLayout / Pager in View с MyPagerAdapter

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        final ViewPager viewPager = findViewById(R.id.pager);
        MyPagerAdapter myPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), this, new Date());
        viewPager.setAdapter(myPagerAdapter);

        TabLayout tabLayout = findViewById(R.id.tablayout);
        tabLayout.setupWithViewPager(viewPager);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {...}

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {...}
}

MyPagerAdapter.java

Возвращает объект Fragment с частотой (день / месяц / год / всего) и сериализованный объект Calendar, переданный как параметр.

public class MyPagerAdapter extends FragmentStatePagerAdapter {
    private final int NUM_TABS = 4;
    private String classtag = this.getClass().getSimpleName();
    private Context _context;
    private Calendar mCal;

    MyPagerAdapter(FragmentManager fm, Context c, Date d) {
        super(fm); // TODO: deprecated
        _context = c;

        mCal = Calendar.getInstance();
        mCal.setTime(d);
    }

    @Override
    public int getCount() {
        return NUM_TABS;
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        Log.d(classtag, "DEBUG: getItem(position=" + position + ")");

        Bundle args = new Bundle();
        Fragment chartFragment = new Tab();

        args.putSerializable("calendar", mCal);

        switch (position) {
            default:
            case 0:
                args.putInt("frequency", Misc.FREQ_DAILY);
                break;
            case 1:
                args.putInt("frequency", Misc.FREQ_MONTHLY);
                break;
            case 2:
                args.putInt("frequency", Misc.FREQ_YEARLY);
                break;
            case 3:
                args.putInt("frequency", Misc.FREQ_TOTAL);
                break;
        }

        chartFragment.setArguments(args);
        return chartFragment;

    }

    @NonNull
    @Override
    public CharSequence getPageTitle(int position) {
        Log.d(classtag, "DEBUG: getPageTitle(position=" + position + ")");

        switch (position) {
            default:
            case 0:
                return _context.getString(R.string.day);
            case 1:
                return _context.getString(R.string.week);
            case 2:
                return _context.getString(R.string.year);
            case 3:
                return _context.getString(R.string.total);
        }
    }
}

Tab.java

  • onCreateView создает ссылки на объекты во фрагменте / представлении, вызывает createGraph, а затем updateTab
  • createGraph готовит график и начальную серию (данные)
  • updateTab вызывается после создания графика или при изменении даты (с помощью кнопки «Предыдущая / Следующая» или DatePicker). здесь resetData называется
public class Tab extends Fragment {
    private String classtag = this.getClass().getSimpleName();
    private Resources resources;
    private Calendar mCal;
    private int mFreq;
    private View rootView;
    private BaseSeries<DataPoint> mSeries;
    private TextView customerInfo;
    private TextView totalProduction;
    private TextView datepicker;
    private GraphView graph;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_tab, container, false);

        assert getArguments() != null;
        mFreq = getArguments().getInt("frequency", 0);
        mCal = (Calendar) getArguments().getSerializable("calendar");
        resources = rootView.getResources();

        customerInfo = rootView.findViewById(R.id.lbl_customer_info);
        totalProduction = rootView.findViewById(R.id.lbl_total);
        datepicker = rootView.findViewById(R.id.lbl_datepicker);

        graph = rootView.findViewById(R.id.graph);

        Button btnPrev = rootView.findViewById(R.id.btn_prev);
        Button btnNext = rootView.findViewById(R.id.btn_next);

        // Custom configs for certain tabs omitted here >>>
        btnPrev.setVisibility(View.VISIBLE);
        btnNext.setVisibility(View.VISIBLE);
        datepicker.setVisibility(View.VISIBLE);

        // Change date with frequency according to tab (hop 1 month in Month Tab)
        btnPrev.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Date _curDate = mCal.getTime();
                mCal.setTime(Misc.getPrevDate(_curDate, mFreq));
                updateTab();
            }
        });
        btnNext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Date _curDate = mCal.getTime();
                mCal.setTime(Misc.getNextDate(_curDate, mFreq));
                updateTab();
            }
        });
        datepicker.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new DatePickerDialog(rootView.getContext(), new DatePickerDialog.OnDateSetListener() {
                    @Override
                    public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                        mCal.set(Calendar.YEAR, year);
                        mCal.set(Calendar.MONTH, month);
                        mCal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
                        updateTab();
                    }
                }, mCal.get(Calendar.YEAR), mCal.get(Calendar.MONTH), mCal.get(Calendar.DAY_OF_MONTH)).show();
            }
        });
        // >>> Custom configs for certain tabs omitted here

        createGraph();
        updateTab();

        return rootView;
    }

    @Override
    public void onResume() {
        super.onResume();
        updateTab();
    }

    private void createGraph() {
        GridLabelRenderer gridLabel = graph.getGridLabelRenderer();
        Viewport viewport = graph.getViewport();
        LegendRenderer legend = graph.getLegendRenderer();

        // [...] Ommitted some irrelevant code here

        mSeries = new LineGraphSeries<>(getDataPoints());

        // [...] Ommitted some irrelevant code here

        graph.addSeries(mSeries);

        // [...] Ommitted some irrelevant code here

    }

    private void updateTab() {
        DataPoint[] dp;

        datepicker.setText(Misc.getDate(mCal.getTime()));

        // [...] Ommitted some irrelevant code here

        double totalProd = Misc.sumDataPoints(dp);
        totalProduction.setText(String.format(Locale.getDefault(), "%.1f", totalProd));

        mSeries.resetData(dp); // This should update the graph series with the new data
        graph.onDataChanged(false, false);
    }

    private Map<String, String> getCustomerInfo() {...}

    private DataPoint[] getDataPoints() {...}
}

Это макет фрагмента вкладки. Этот фрагмент загружается в пейджер в макете основной активности (который состоит из панели инструментов, табуляции и пейджера). Tab Fragment Layout

Я думал о том, чтобы разделить их на разные частоты, т.е. TabDay, TabMonth, TabYear, TabTotal, чтобы не создавать несколько экземпляров одного и того же объекта, но я не думаю, что это будет иметь какой-либо эффект и приведет к дублированию большого количества кода.
В той же строке я рассмотрел создание «основной вкладки» и расширение ее для разных частот, благодаря чему я, вероятно, смогу сохранить объект календаря в «основной вкладке» и надеюсь, что он будет синхронизировать вкладки на отображение части даты.

На перерисовке части графика у меня такое чувство, что мне нужно как-то заставить перерисовку, но я не знаю, как и где. Метод onResume вызывает метод своего высшего класса, который, я думаю, выполняет перерисовку, по крайней мере, при переключении вкладок.

GIF of issue

...