public class Weather {
private String city; //城市名
private String update_time; //更新时间
private List<DayData> data; //每天的天气数据列表,data.get(0)为当天数据
/*
getter and setter
*/
}
// class DayData
public class DayData {
private String wea; //天气状况
private String tem; //当前温度
private String tem1; //最高温
private String tem2; //最低温
private String humidity; //湿度
private String air_level; //空气质量等级
private String air_tips; //空气质量小提示
/*
getter and setter
*/
}
4、由于OkHttp的请求是在子线程中进行的,需要使用Handler消息队列机制将解析出来的Weather实例发送到主线程用以显示在界面上。
//消息处理类
public class MyHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//what == 1 天气消息
if (msg.what == 1)
ShowWeatherInfo((Weather) msg.obj);
}
}
public void ShowWeatherInfo(Weather weather) {
String city = weather.getCity();
String wea = weather.getData().get(0).getWea();
String maxTem = weather.getData().get(0).getTem1();
String minTem = weather.getData().get(0).getTem2();
String tem = weather.getData().get(0).getTem();
String humidity = "湿度 " + weather.getData().get(0).getHumidity();
String air_level = "空气指数 " + weather.getData().get(0).getAir_level();
// tem tem1 tem2 city wea rain pm image
((TextView) findViewById(R.id.cityView)).setText(city);
((TextView) findViewById(R.id.weaView)).setText(wea);
((TextView) findViewById(R.id.mmtemView)).setText(
String.format("%s° / %s°", minTem.substring(0, minTem.length() - 1), maxTem.substring(0, maxTem.length() - 1)));
((TextView) findViewById(R.id.temView)).setText(tem.substring(0, tem.length() - 1) + "°");
((TextView) findViewById(R.id.humidityView)).setText(humidity);
((TextView) findViewById(R.id.levelView)).setText(air_level);
ShowWeatherImage(wea); //根据天气状况wea显示对应的天气图片,这里不详细说明,使用switch就行
}
5、别忘了在OkHttp请求完成时发送消息
public void RefreshWeatherData() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(weatherUrl).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
String weatherJson = response.body().string();
Weather weather = new Gson().fromJson(weatherJson, Weather.class);
Message message = new Message();
message.what = 1;
message.obj = weather;
myHandler.sendMessage(message);
}
});
}
6、优化xml布局
[]( )三、待办事项界面
-------------------------------------------------------------------
这里由于ListView是放在Fragment中的,所以直接在MainAcitivity.java中设置适配器可能会出现数据没法显示的bug。所以我直接把从数据库获取数据,Adapter的定义,ListView设置适配器的模块搬到了TaskFragment.java中。
1.在task.xml中添加ListView,先不用设置UI样式,先把数据拿到并显示在界面上
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/taskText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="事项"/>
<ListView
android:id="@+id/taskListView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
2.创建task\_item.xml布局文件(这里注意线性布局的方向及宽高,以保证task\_item能放在ListView中)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/task_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="30dp"
android:text="TextView" />
3.新建TaskItem类,存放事项数据
package com.example.daily.tasks;
public class TaskItem {
private int id;
private String content;
private String type;
private int status;
public TaskItem(int id, String type, String content, int status){
this.id = id;
this.type = type;
this.content = content;
this.status = status;
}
// 自行添加Get和Set方法
}
4.在TaskFragment.java中创建SQLite数据库并获取待办事项的数据
public class TaskFragment extends Fragment {
private static final String TAG = TaskFragment.class.getName();
private List<TaskItem> taskList = new ArrayList<>();
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.task, container, false);
ReadTaskDataFromSQL();
//测试数据获取是否正常
for(TaskItem item : taskList){
Log.i(TAG, "taskList "+item.getId()+" "+item.getContent());
}
return view;
}
//读取数据库并将数据存到taskList
public void ReadTaskDataFromSQL(){
MySQLiteOpenHelper openHelper = new MySQLiteOpenHelper(getActivity());
SQLiteDatabase readDatabase = openHelper.getReadableDatabase();
Cursor cursor = readDatabase.query(
"task",
new String[]{"id", "type", "content", "status"},
null,null,null,null,null
);
while(cursor.moveToNext()){
TaskItem task = new TaskItem(
cursor.getInt(0),
cursor.getString(1),
cursor.getString(2),
cursor.getInt(3)
);
taskList.add(task);
}
}
//创建SQLite数据库
public class MySQLiteOpenHelper extends SQLiteOpenHelper{
public MySQLiteOpenHelper(@Nullable Context context) {
super(context, "Daily.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "onCreate: sqlite");
//创建待办事项数据表
String create_sql =
"create table task(" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"content varchar(50), " +
"type varchar(50), " +
"status int);";
db.execSQL(create_sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}
}
5.数据获取正常以后,建立ListView适配器。这里涉及到缓存convertView的使用,使用convertView可以防止每创建一个item时就解析一个布局,这样效率肯定不高。convertView是Android提供的用于缓存的View,在第一次渲染item时,将将解析出来的View放入缓存convertView,在下一次渲染item的时候,判断convertView是否为空即可。
public class TaskAdapter extends BaseAdapter{
@Override
public int getCount() {
//测试getCount返回值是否正常
Log.i(TAG, "getCount: "+taskList.size());
return taskList.size();
}
@Override
public Object getItem(int position) {
return taskList.get(position);
}
@Override
public long getItemId(int position) {
return taskList.get(position).getId();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//测试getView是否执行
Log.i(TAG, "getView: "+position);
ViewHolder viewHolder;
TaskItem task = (TaskItem) getItem(position);
if(convertView == null){
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(getActivity()).inflate(R.layout.task_item, null);
viewHolder.taskItemTextView = convertView.findViewById(R.id.task_content);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.taskItemTextView.setText(task.getId()+" "+task.getContent());
return convertView;
}
}
public class ViewHolder{
TextView taskItemTextView;
}
6.在onCreateView中设置ListView的适配器
private List taskList = new ArrayList<>();
private TaskAdapter taskAdapter;
private ListView taskListView;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.task, container, false);
taskListView = view.findViewById(R.id.taskListView);
taskAdapter = new TaskAdapter();
taskListView.setAdapter(taskAdapter);
ReadTaskDataFromSQL();
return view;
}
**7.设计每一条待办事项的布局样式,如图所示,布局设计就不放原码了,使用多个线性布局的嵌套,gravity,margin属性即可实现。**
**img:task-2.jpg**
**8.根据待办事项的状态显示不同按钮,并标记待办事项的重要程度。**
public void ShowTaskContent(View convertView, TaskItem task){
//显示事项内容
TextView content = ((ViewHolder) convertView.getTag()).taskContent;
int status = task.getStatus();
content.setText(task.getContent());
//事项已完成 中划线 灰色
if(status == 1){
content.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
content.setTextColor(getResources().getColor(R.color.GRAY, null));
}
//事项未完成 无中划线 黑色
if(status == 0){
content.