使用改造和 MPAndroidChart 动态检索 MySQL 数据并在 android 上绘图
Retrieving MySQL data dynamically and plotting on android using retrofit and MPAndroidChart
我正在关注剧情关注this example. Things work if I have a static JSON and it will plot the data like shown in the website. However, I am retrieving data from MySQL and they are being updated every hour (I had look into this;创建一个按钮并可能每小时调用 URL),但我不太确定这是否是有效的方法。
我的问题是,如果我每小时都有一个 MySQL table/data,我该如何检索它们并绘制(保留旧值并绘制新值)?我有以下
Api 客户 URL:
public class ApiClient {
private static Retrofit retrofit = null;
private static OkHttpClient buildClient() {
return new OkHttpClient
.Builder()
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
}
public static Retrofit getClient() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.client(buildClient())
.addConverterFactory(GsonConverterFactory.create())
/**
*
* base url here for api
*/
.baseUrl("https://xxx") //retrieve data from MySQL
.build();
}
return retrofit;
}
}
主要活动:
public class BarchartRetrofit extends AppCompatActivity {
public ApiInterface apiInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
apiInterface = ApiClient.getClient().create(ApiInterface.class);
/**
* api call to get some data from server
*
*/
getData();
}
private void getData() {
Call<PiChart> piChartCall = apiInterface.init();
piChartCall.enqueue(new Callback<PiChart>() {
@Override
public void onResponse(Call<PiChart> call, Response<PiChart> response) {
Log.d("CHART_RESPONSE", "" + response.body().getBarMonths().toString());
setData(response.body());
}
@Override
public void onFailure(Call<PiChart> call, Throwable t) {
}
});
}
private void setData(PiChart piChart) {
ArrayList<BarDataSet> dataSets = null;
ArrayList<BarEntry> completed = new ArrayList<>();
for (int i = 0; i < piChart.getBarCompleted().size(); i++) {
BarEntry value = new BarEntry(piChart.getBarCompleted().get(i), i); // Jan
completed.add(value);
}
BarDataSet completeData = new BarDataSet(completed, "Completed Issue");
completeData.setColor(Color.rgb(0, 155, 0));
ArrayList<BarEntry> pending = new ArrayList<>();
for (int i = 0; i < piChart.getBarCompleted().size(); i++) {
BarEntry value = new BarEntry(piChart.getBarPending().get(i), i); // Jan
pending.add(value);
}
BarDataSet pendingdata = new BarDataSet(pending, "Pending Issue");
pendingdata.setColor(Color.rgb(253, 129, 0));
ArrayList<BarEntry> rejected = new ArrayList<>();
for (int i = 0; i < piChart.getBarCompleted().size(); i++) {
BarEntry value = new BarEntry(piChart.getBarRejected().get(i), i); // Jan
rejected.add(value);
}
BarDataSet rejectedData = new BarDataSet(rejected, "Rejected Issue");
pendingdata.setColor(Color.rgb(255, 0, 0));
dataSets = new ArrayList<>();
dataSets.add(completeData);
dataSets.add(pendingdata);
dataSets.add(rejectedData);
ArrayList<String> xAxis = new ArrayList<>();
for (String months : piChart.getBarMonths()) {
Log.d("CHART_RESPONSE", "month: " + months.toString());
xAxis.add(months);
}
com.github.mikephil.charting.charts.BarChart chart = (com.github.mikephil.charting.charts.BarChart) findViewById(R.id.barchart);
BarData data = new BarData(xAxis, dataSets);
chart.setData(data);
chart.setDescription("Bar chart");
chart.invalidate();
}
}
创建 JSON POJO:
public class Example {
@SerializedName("success")
@Expose
private boolean success;
@SerializedName("bar_months")
@Expose
private List<String> barMonths = null;
@SerializedName("bar_pending")
@Expose
private List<Integer> barPending = null;
@SerializedName("bar_rejected")
@Expose
private List<Integer> barRejected = null;
@SerializedName("bar_completed")
@Expose
private List<Integer> barCompleted = null;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public List<String> getBarMonths() {
return barMonths;
}
public void setBarMonths(List<String> barMonths) {
this.barMonths = barMonths;
}
public List<Integer> getBarPending() {
return barPending;
}
public void setBarPending(List<Integer> barPending) {
this.barPending = barPending;
}
public List<Integer> getBarRejected() {
return barRejected;
}
public void setBarRejected(List<Integer> barRejected) {
this.barRejected = barRejected;
}
public List<Integer> getBarCompleted() {
return barCompleted;
}
public void setBarCompleted(List<Integer> barCompleted) {
this.barCompleted = barCompleted;
}
}
JSON是:
{
"success": true,
"bar_months":[
"jan",
"feb",
"mar"
],
"bar_pending":[
100,
200,
300
],
"bar_rejected":[
140,
220,
340
],
"bar_completed":[
170,
290,
310
]
}
所以基本上,我在 bar_months
、bar_pending
、bar_rejected
和 bar_completed
中的数据将发生变化,而不是静态值,想知道我可以提供哪些建议/示例尝试每小时重新训练动态数据。预先感谢您的阅读和帮助!
为了将您的 getData()
任务安排为周期性任务(即使您的应用程序不在前台),您可以使用 workmanager。
在这种特定情况下,您需要 PeriodicWorkRequestBuilder
(link)。
第一步是定义你想要定期 运行 的工作,扩展 Worker
class 这样做:
class ExampleWorker(
appContext: Context,
workerParams: WorkerParameters
) :
Worker(appContext, workerParams) {
override fun doWork(): Result {
getData()
// Indicate whether the work finished successfully with the Result
return Result.success()
}
private fun getData() {
val piChartCall: Call<PiChart> = apiInterface.init()
piChartCall.enqueue(object : Callback<PiChart?>() {
fun onResponse(call: Call<PiChart?>?, response: Response<PiChart?>) {
Log.d("CHART_RESPONSE", "" + response.body().getBarMonths().toString())
setData(response.body())
}
fun onFailure(call: Call<PiChart?>?, t: Throwable?) {}
})
}
}
第二步将以循环方式安排这项工作,PeriodicWorkRequestBuilder
功能可以帮助您:
private fun schedulePeriodicWork(context: Context) {
val request =
PeriodicWorkRequestBuilder<ExampleWorker>(1, TimeUnit.HOURS).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"charSync",
ExistingPeriodicWorkPolicy.REPLACE, request
)
}
将调度函数调用放在Application
class
的onCreate()
方法中可能是一个明智的选择
我正在关注剧情关注this example. Things work if I have a static JSON and it will plot the data like shown in the website. However, I am retrieving data from MySQL and they are being updated every hour (I had look into this;创建一个按钮并可能每小时调用 URL),但我不太确定这是否是有效的方法。
我的问题是,如果我每小时都有一个 MySQL table/data,我该如何检索它们并绘制(保留旧值并绘制新值)?我有以下
Api 客户 URL:
public class ApiClient {
private static Retrofit retrofit = null;
private static OkHttpClient buildClient() {
return new OkHttpClient
.Builder()
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
}
public static Retrofit getClient() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.client(buildClient())
.addConverterFactory(GsonConverterFactory.create())
/**
*
* base url here for api
*/
.baseUrl("https://xxx") //retrieve data from MySQL
.build();
}
return retrofit;
}
}
主要活动:
public class BarchartRetrofit extends AppCompatActivity {
public ApiInterface apiInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
apiInterface = ApiClient.getClient().create(ApiInterface.class);
/**
* api call to get some data from server
*
*/
getData();
}
private void getData() {
Call<PiChart> piChartCall = apiInterface.init();
piChartCall.enqueue(new Callback<PiChart>() {
@Override
public void onResponse(Call<PiChart> call, Response<PiChart> response) {
Log.d("CHART_RESPONSE", "" + response.body().getBarMonths().toString());
setData(response.body());
}
@Override
public void onFailure(Call<PiChart> call, Throwable t) {
}
});
}
private void setData(PiChart piChart) {
ArrayList<BarDataSet> dataSets = null;
ArrayList<BarEntry> completed = new ArrayList<>();
for (int i = 0; i < piChart.getBarCompleted().size(); i++) {
BarEntry value = new BarEntry(piChart.getBarCompleted().get(i), i); // Jan
completed.add(value);
}
BarDataSet completeData = new BarDataSet(completed, "Completed Issue");
completeData.setColor(Color.rgb(0, 155, 0));
ArrayList<BarEntry> pending = new ArrayList<>();
for (int i = 0; i < piChart.getBarCompleted().size(); i++) {
BarEntry value = new BarEntry(piChart.getBarPending().get(i), i); // Jan
pending.add(value);
}
BarDataSet pendingdata = new BarDataSet(pending, "Pending Issue");
pendingdata.setColor(Color.rgb(253, 129, 0));
ArrayList<BarEntry> rejected = new ArrayList<>();
for (int i = 0; i < piChart.getBarCompleted().size(); i++) {
BarEntry value = new BarEntry(piChart.getBarRejected().get(i), i); // Jan
rejected.add(value);
}
BarDataSet rejectedData = new BarDataSet(rejected, "Rejected Issue");
pendingdata.setColor(Color.rgb(255, 0, 0));
dataSets = new ArrayList<>();
dataSets.add(completeData);
dataSets.add(pendingdata);
dataSets.add(rejectedData);
ArrayList<String> xAxis = new ArrayList<>();
for (String months : piChart.getBarMonths()) {
Log.d("CHART_RESPONSE", "month: " + months.toString());
xAxis.add(months);
}
com.github.mikephil.charting.charts.BarChart chart = (com.github.mikephil.charting.charts.BarChart) findViewById(R.id.barchart);
BarData data = new BarData(xAxis, dataSets);
chart.setData(data);
chart.setDescription("Bar chart");
chart.invalidate();
}
}
创建 JSON POJO:
public class Example {
@SerializedName("success")
@Expose
private boolean success;
@SerializedName("bar_months")
@Expose
private List<String> barMonths = null;
@SerializedName("bar_pending")
@Expose
private List<Integer> barPending = null;
@SerializedName("bar_rejected")
@Expose
private List<Integer> barRejected = null;
@SerializedName("bar_completed")
@Expose
private List<Integer> barCompleted = null;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public List<String> getBarMonths() {
return barMonths;
}
public void setBarMonths(List<String> barMonths) {
this.barMonths = barMonths;
}
public List<Integer> getBarPending() {
return barPending;
}
public void setBarPending(List<Integer> barPending) {
this.barPending = barPending;
}
public List<Integer> getBarRejected() {
return barRejected;
}
public void setBarRejected(List<Integer> barRejected) {
this.barRejected = barRejected;
}
public List<Integer> getBarCompleted() {
return barCompleted;
}
public void setBarCompleted(List<Integer> barCompleted) {
this.barCompleted = barCompleted;
}
}
JSON是:
{
"success": true,
"bar_months":[
"jan",
"feb",
"mar"
],
"bar_pending":[
100,
200,
300
],
"bar_rejected":[
140,
220,
340
],
"bar_completed":[
170,
290,
310
]
}
所以基本上,我在 bar_months
、bar_pending
、bar_rejected
和 bar_completed
中的数据将发生变化,而不是静态值,想知道我可以提供哪些建议/示例尝试每小时重新训练动态数据。预先感谢您的阅读和帮助!
为了将您的 getData()
任务安排为周期性任务(即使您的应用程序不在前台),您可以使用 workmanager。
在这种特定情况下,您需要 PeriodicWorkRequestBuilder
(link)。
第一步是定义你想要定期 运行 的工作,扩展 Worker
class 这样做:
class ExampleWorker(
appContext: Context,
workerParams: WorkerParameters
) :
Worker(appContext, workerParams) {
override fun doWork(): Result {
getData()
// Indicate whether the work finished successfully with the Result
return Result.success()
}
private fun getData() {
val piChartCall: Call<PiChart> = apiInterface.init()
piChartCall.enqueue(object : Callback<PiChart?>() {
fun onResponse(call: Call<PiChart?>?, response: Response<PiChart?>) {
Log.d("CHART_RESPONSE", "" + response.body().getBarMonths().toString())
setData(response.body())
}
fun onFailure(call: Call<PiChart?>?, t: Throwable?) {}
})
}
}
第二步将以循环方式安排这项工作,PeriodicWorkRequestBuilder
功能可以帮助您:
private fun schedulePeriodicWork(context: Context) {
val request =
PeriodicWorkRequestBuilder<ExampleWorker>(1, TimeUnit.HOURS).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"charSync",
ExistingPeriodicWorkPolicy.REPLACE, request
)
}
将调度函数调用放在Application
class
onCreate()
方法中可能是一个明智的选择