Я написал небольшое приложение для 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() {...}
}
Это макет фрагмента вкладки. Этот фрагмент загружается в пейджер в макете основной активности (который состоит из панели инструментов, табуляции и пейджера).
Я думал о том, чтобы разделить их на разные частоты, т.е. TabDay, TabMonth, TabYear, TabTotal, чтобы не создавать несколько экземпляров одного и того же объекта, но я не думаю, что это будет иметь какой-либо эффект и приведет к дублированию большого количества кода.
В той же строке я рассмотрел создание «основной вкладки» и расширение ее для разных частот, благодаря чему я, вероятно, смогу сохранить объект календаря в «основной вкладке» и надеюсь, что он будет синхронизировать вкладки на отображение части даты.
На перерисовке части графика у меня такое чувство, что мне нужно как-то заставить перерисовку, но я не знаю, как и где. Метод onResume
вызывает метод своего высшего класса, который, я думаю, выполняет перерисовку, по крайней мере, при переключении вкладок.