✅简易的安卓天气app(一)——解析Json数据、数据类封装
✅简易的安卓天气app(二)——适配器、每小时数据展示
📌简易的安卓天气app(三)——城市管理、数据库操作
✅简易的安卓天气app(四)——搜索城市、完善页面
需求🏷️
当我们查看天气时,我们都拥有自己的手机,都知道现在的智能手机已经可以根据定位来自动查询所在位置的天气信息,这个依靠的就是手机的定位功能,此处的项目纯属练手,不会涉及定位操作,那一大堆步骤我直接放弃,所以这个功能我们可以偷鸡摸,,,不对,投机取巧从天气api接口想办法搞到。(源码见页尾✨)
本项目用到的天气api接口天气api
详细操作内容见第一篇-->
🧿简易的安卓天气app(一)——解析Json数据<--
此接口当我们默认不拼接参数,直接访问会得到当前位置的温度Json数据,这不就弥补了我们在定位方面的缺陷了吗,那么很好,当我们加上参数之后(此api根据城市查询的参数需+&city=(城市名称)
)那么,当我们只加了参数却没有加参数值(&city=)他还是会根据当前位置进行定位,简直是太妙了。
所以接下来就是进行安卓SQLite数据库的一些操作,把当前位置信息保存到数据库中(城市名,城市温度,更新时间)
待实现效果:
数据库成功插入当前位置数据信息(之前测试插入过几条的测试对照用数据):
位置商丘的信息成功插入,插入之后,后续要进行的操作就是实时更新数据库
涉及内容
- SQLite数据库操作,创建数据库,新建表,增删查改操作
- 适配器adapter添加点击事件
- 页面传值跳转
项目结构
其他内容暂不涉及,本文章只包含城市管理,添加城市到数据库等的一系列操作,前面基础内容移步到页首地址界面设计
城市管理的界面设计city_manager.xml
city_manager.xml界面布局源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <?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:background="@mipmap/bg" android:orientation="vertical">
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:orientation="horizontal">
<ImageView android:id="@+id/iv_add" android:layout_width="35dp" android:layout_height="30dp" android:layout_marginLeft="20dp" android:src="@drawable/add" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="城市管理" android:layout_gravity="center" android:layout_weight="1" android:textColor="@color/purple_200" android:textSize="20dp" />
<ImageView android:id="@+id/iv_more" android:layout_width="35dp" android:layout_height="30dp" android:layout_marginRight="20dp" android:src="@drawable/more" /> </LinearLayout>
<View android:layout_width="390dp" android:layout_height="8px" android:layout_gravity="center" android:layout_marginBottom="5dp" android:alpha="0.6" android:background="@color/white" />
<androidx.recyclerview.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/city_manager"/>
</LinearLayout>
|
added_city.xml页面表示要展示的一个个城市数据:
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <?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="55dp" android:textSize="20sp" android:layout_marginLeft="40dp" android:layout_marginRight="40dp" android:layout_marginTop="5dp" android:background="@drawable/blackground" android:gravity="center_vertical" android:paddingLeft="10dp" >
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="220dp" android:layout_height="wrap_content" android:id="@+id/city_city" android:layout_marginLeft="10dp" android:textSize="22dp" android:textColor="@color/white" android:text="西安" /> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:text="16°C" android:textSize="24dp" android:textColor="@color/white" android:id="@+id/city_tem"/>
</LinearLayout>
</LinearLayout>
|
最终从数据库拿到信息呈现出的效果:
适配器AddCityAdapter
界面布局设计完成接下来就是适配器AddCityAdapter
public class AddCityAdapter extends RecyclerView.Adapter<AddCityAdapter.AddViewHolder>
适配器就是决定在此城市管理页面的RecyclerView中展示哪个页面,跟之前一样,前几篇文章都有篇幅概括,基本的一些操作就是,
添加一个构造方法,
1 2 3 4 5 6 7
| private Context mContext; private List<CityBean> mCityBeans;
public AddCityAdapter(Context context, List<CityBean> cityBeans) { mContext = context; this.mCityBeans = cityBeans; }
|
创建一个类class AddViewHolder extends RecyclerView.ViewHolder
来绑定控件,此时在城市管理页面要求点击某个城市,需要传值到MainActivity,并获取指定点击城市的天气信息
所以适配器中添加一个点击事件,首先在适配器中添加接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
private OnItemClickListener onItemClickListener;
public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; }
|
然后在适配器中的类AddViewHolder中绑定点击事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class AddViewHolder extends RecyclerView.ViewHolder {
TextView cityCity,cityTem;
public AddViewHolder(@NonNull View itemView) { super(itemView); cityCity=itemView.findViewById(R.id.city_city); cityTem = itemView.findViewById(R.id.city_tem); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (onItemClickListener!=null) { onItemClickListener.onItemClick(view,getLayoutPosition()); } } }); } }
|
然后就是一如既往的重写三个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @NonNull @Override public AddViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(mContext).inflate(R.layout.added_city, parent, false); AddViewHolder cityViewHolder = new AddViewHolder(view); return cityViewHolder; }
@Override public void onBindViewHolder(@NonNull AddViewHolder holder, int position) { CityBean cityBean = mCityBeans.get(position); holder.cityCity.setText(cityBean.getName()); holder.cityTem.setText(cityBean.getTem()); }
@Override public int getItemCount() { return (mCityBeans == null) ? 0 : mCityBeans.size(); }
|
适配器AddCityAdapter源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| public class AddCityAdapter extends RecyclerView.Adapter<AddCityAdapter.AddViewHolder>{
private Context mContext; private List<CityBean> mCityBeans;
public AddCityAdapter(Context context, List<CityBean> cityBeans) { mContext = context; this.mCityBeans = cityBeans; }
@NonNull @Override public AddViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(mContext).inflate(R.layout.added_city, parent, false); AddViewHolder cityViewHolder = new AddViewHolder(view); return cityViewHolder; }
@Override public void onBindViewHolder(@NonNull AddViewHolder holder, int position) { CityBean cityBean = mCityBeans.get(position);
holder.cityCity.setText(cityBean.getName()); holder.cityTem.setText(cityBean.getTem()); }
@Override public int getItemCount() { return (mCityBeans == null) ? 0 : mCityBeans.size(); }
class AddViewHolder extends RecyclerView.ViewHolder {
TextView cityCity,cityTem;
public AddViewHolder(@NonNull View itemView) { super(itemView);
cityCity=itemView.findViewById(R.id.city_city); cityTem = itemView.findViewById(R.id.city_tem);
itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (onItemClickListener!=null) { onItemClickListener.onItemClick(view,getLayoutPosition()); } } }); } }
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
private OnItemClickListener onItemClickListener;
public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } }
|
操作数据库
然后进行数据库工具的构建,要操作数据库,一般的方法得需要实体类吧,接着就是城市实体类的封装,当获取当前定位天气信息时,把此数据类保存到数据库
所以先构建城市实体类CityBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class CityBean {
private String name; private String[] area; private String tem; private String updateTime;
public CityBean() { }
public CityBean(String name) { this.name = name; }
public CityBean(String name, String tem, String updateTime) { this.name = name; this.tem = tem; this.updateTime = updateTime; }
}
|
接着就是数据库的CityDatabaseConfig,有数据库名,表名的信息,以防操作数据库写错名称,故写在此配置下:
1 2 3 4 5 6 7
| public class CityDatabaseConfig { public static final String DATABASE_NAME = "cityDb"; public static final String TABLE_NAME = "city_weather"; }
|
然后是CityDbHelper
继承自SQLiteOpenHelper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class CityDbHelper extends SQLiteOpenHelper {
public CityDbHelper(Context context) { super(context, CityDatabaseConfig.DATABASE_NAME, null, 1); }
@Override public void onCreate(SQLiteDatabase db) { String sql = "create table if not exists "+CityDatabaseConfig.TABLE_NAME+"(cityName text,tem text,updateTime text)"; db.execSQL(sql); Log.i(CityDatabaseConfig.DATABASE_NAME,"created success!!"); }
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i(CityDatabaseConfig.DATABASE_NAME,"updated success!!"); }
}
|
接着是数据库一些操作的工具,里面写一些能用到的方法,自行扩展即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| public class DBUtils {
private Context context; private CityDbHelper helper;
public DBUtils(Context context) { this.context = context; helper = new CityDbHelper(context) { }; }
public boolean insertData(String cityName,String tem,String updateTime) { SQLiteDatabase db = helper.getReadableDatabase(); ContentValues values = new ContentValues();
values.put("cityName", cityName); values.put("tem", tem); values.put("updateTime", updateTime); long insert = db.insert(CityDatabaseConfig.TABLE_NAME, null, values); if (insert > 0) { return true; } return false; }
public boolean updateByName(String cityName,String tem,String updateTime){ SQLiteDatabase db = helper.getReadableDatabase(); ContentValues values = new ContentValues();
values.put("cityName", cityName); values.put("tem", tem); values.put("updateTime", updateTime); long update = db.update(CityDatabaseConfig.TABLE_NAME,values,"cityName=?", new String[]{cityName});
if (update>0){ return true; }return false; }
public List<CityBean> getAllCity() { List<CityBean> list = new ArrayList<>(); SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from " + CityDatabaseConfig.TABLE_NAME, null); if (cursor != null && cursor.getCount() > 0) { while (cursor.moveToNext()) {
String cityName = cursor.getString(0); String tem = cursor.getString(1); String updateTime = cursor.getString(2);
CityBean cityBean = new CityBean(cityName,tem,updateTime); list.add(cityBean); } } return list; }
public CityBean getCityByName(String cityName) { CityBean cityBean = new CityBean(); SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from " + CityDatabaseConfig.TABLE_NAME + " where cityName=?", new String[]{cityName}); if (cursor != null && cursor.getCount() > 0) { while (cursor.moveToFirst()) {
String cityNameResult = cursor.getString(0); cityBean.setName(cityName); break; }
} return cityBean;
}
public boolean delCityByName(String cityName){ SQLiteDatabase db = helper.getReadableDatabase();
long delRow = db.delete(CityDatabaseConfig.TABLE_NAME, "cityName=?", new String[]{cityName}); if (delRow > 0) { return true; } return false;
}
}
|
跳转页面,展示数据
一些基本的方法写好后就是MainActivity.java文件,用Intent跳转到城市管理界面,注意先引入数据库操作工具
1
| DBUtils dbUtils = new DBUtils(MainActivity.this);
|
设置右上角图标的点击事件,此小圆点图标绑定为ivMore
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ivMore.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (null == dbUtils.getCityByName(tvCity.getText().toString()).getName()) { dbUtils.insertData(tvCity.getText().toString(),tvTem.getText().toString(),tvTime.getText().toString()); } else { dbUtils.updateByName(tvCity.getText().toString(),tvTem.getText().toString(),tvTime.getText().toString());
List<CityBean> list = dbUtils.getAllCity(); Log.d("getAllCity", "allList<CityBean>>>>》》》" + list.toString());
ToastUtil.showShortToast(MainActivity.this, "当前位置:" + tvCity.getText()); Intent intent = new Intent(MainActivity.this, CityManagerActivity.class); Log.d("getNowCity", "nowCity<CityBean>>>>》》》" + tvCity.getText());
startActivityForResult(intent, 200); } } });
|
跳转到城市管理页面,添加activity.java文件,命名CityManagerActivity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public class CityManagerActivity extends AppCompatActivity {
private AddCityAdapter addCityAdapter; private RecyclerView rvAddedCity;
private List<CityBean> cityDbBeanList; DBUtils dbUtils= new DBUtils(CityManagerActivity.this);
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.city_manager);
initView(); }
public void initView() {
rvAddedCity = findViewById(R.id.city_manager);
cityDbBeanList = dbUtils.getAllCity(); Log.d("cityList",">>>>>数据库中的数据》》》》》》"+cityDbBeanList); addCityAdapter = new AddCityAdapter(CityManagerActivity.this,cityDbBeanList); rvAddedCity.setAdapter(addCityAdapter); LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); rvAddedCity.setLayoutManager(layoutManager); addCityAdapter.setOnItemClickListener(new AddCityAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) {
Intent intent = new Intent(CityManagerActivity.this,MainActivity.class); intent.putExtra("selectedCity",cityDbBeanList.get(position).getName()); setResult(200,intent); finish();
} }); }
}
|
然后既然是要求页面返回传值,MainActivity就要重写方法onActivityResult
接受传来的值
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 200 && resultCode == 200) { String dt = data.getExtras().getString("selectedCity"); tvCity.setText(dt); nowCity=dt; getWeather(nowCity); ToastUtil.showLongToast(this,dt+"天气更新😘~"); } }
|
自此一部分功能就实现了,跳转城市管理页面,展示城市,指定城市展示天气信息,
数据库操作实现了:
- 拿到数据库所有城市信息、
- 插入一条数据、
- 根据城市名称更新数据、
- 删除一条数据待完成,,自行拓展,只要工具类删除方法写对,无非就是添加个事件调用删除方法
更精细化的搜索城市,主动根据搜索到的城市添加城市到数据库,后篇文章会逐渐完善,此篇文章主要是数据库的一些操作和适配器添加点击事件,订阅此栏可同步获取项目搭建过程😘😘
==源码地址==:Gitee