IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【第一行代码】Weather -> 正文阅读

[移动开发]【第一行代码】Weather

简介

完整的模拟了一个天气软件

功能列表

  • 罗列出全国所有的省、市、县
  • 查看全国任意城市的天气信息
  • 自由的切换城市,查看其他城市的天气
  • 能手动更新以及后台自动更新天气

获取全国的省市县信息

利用 作者的服务器 去获取数据信息

通过数据信息中的 weather_id 去访问和风天气的接口,即可得到该地区的天气

注册 和风天气获取 API Key。

最后利用 weather_id 和 Key 便可拿到天气相关的数据。

创建数据库和表

新建 db 目录存放数据库的表,利用 LitePal 管理数据库;

在 build.gradle 添加依赖 implementation 'org.litepal.android:core:1.3.2'

新建类 Province,City 和 County 继承 DataSupport,分别保存省市县的数据信息。

新建 assets 目录,新建文件 litepal.xml,内容如下:

<litepal>
    <dbname value="weather"/>
    <version value="1"/>
    <list>
        <mapping class="com.example.weather.db.Province"/>
        <mapping class="com.example.weather.db.City"/>
        <mapping class="com.example.weather.db.County"/>
    </list>
</litepal>

配置 LitePalApplication,在 MyApplication 中初始化

@Override
public void onCreate() {
    super.onCreate();
    mContext = getApplicationContext();
    LitePalApplication.initialize(mContext);
}

遍历全国省市县数据

获取数据

数据最开始去需要从服务器获取的,所以需要和服务器交互,利用 OkHttp 开源库

在 build.gradle 添加依赖 implementation 'com.squareup.okhttp3:okhttp:3.10.0'

用法:

public class HttpUtil {

    private static final String TAG = "ZLTEST";

    public static void sendOkHttpRequest(String address, okhttp3.Callback callback) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(address)
                .build();
        LogUtil.d(TAG, "request success");
        client.newCall(request).enqueue(callback);
    }
}

解析数据

由于服务器返回的数据是 json 格式的,所以需要利用 gson 去解析处理

在 build.gradle 添加依赖 implementation 'com.google.code.gson:gson:2.8.2'

用法:

public class Utility {

    public static Weather handleWeatherResponse(String response) {
        try {
            JSONObject jsonObject = new JSONObject(response);
            JSONArray jsonArray = jsonObject.getJSONArray("HeWeather");
            String weatherContent = jsonArray.getJSONObject(0).toString();
            return new Gson().fromJson(weatherContent, Weather.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

展示数据

利用 Fragment 去显示界面,用 fragment 是因为这个界面后面需要复用

新建布局文件,在 res/layout 新建文件 choose_area.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary">

        <TextView
            android:id="@+id/title_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="#fff"
            android:textSize="20sp"/>

        <Button
            android:id="@+id/back_button"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:layout_marginLeft="10dp"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:background="@drawable/back"/>

    </RelativeLayout>

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </ListView>

</LinearLayout>

新建 ChooseAreaFragment 类去处理相关逻辑,可以参考 源码文件

显示天气信息

定义 GSON 实体类

天气返回的数据格式:

{
  "HeWeather": [
    {
      "status" : "ok",
      "basic" : {},
      "aqi" : {},
      "now" : {},
      "suggestion" : {},
      "daily_forecast" : []
    }
  ]
}

其中 basic,aqi,now,suggestion 和 daily_forecast 的内部又有具体的内容,所以可以将这个五个部分定义成五个类

新建 Weather 类, 根据每个部分不同的属性分别建类,这里不再赘述,可以参考源码

public class Weather {

    public String status;
    public AQI aqi;
    public Basic basic;
    public Now now;
    public Suggestion suggestion;

    @SerializedName("daily_forecast")
    public List<Forecast> forecastList;

}

编写天气界面

新建一个 title.xml 作为头布局,用来显示城市名以及时间

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize">

    <Button
        android:id="@+id/nav_button"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginLeft="10dp"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:background="@drawable/home"/>

    <TextView
        android:id="@+id/title_city"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="#fff"
        android:textSize="20sp"/>

    <TextView
        android:id="@+id/title_update_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:textColor="#fff"
        android:textSize="16sp"/>

</RelativeLayout>

新建天气主界面布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary">

    <ImageView
        android:id="@+id/bing_pic_img"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>

    <androidx.drawerlayout.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh"
            android:layout_width="match_parent"
            android:layout_height="match_parent">


            <ScrollView
                android:id="@+id/weather_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scrollbars="none"
                android:overScrollMode="never">

                <LinearLayout
                    android:orientation="vertical"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:fitsSystemWindows="true">

                    <include layout="@layout/title"/>
                    <include layout="@layout/now"/>
                    <include layout="@layout/forecast"/>
                    <include layout="@layout/aqi"/>
                    <include layout="@layout/suggestion"/>

                </LinearLayout>

            </ScrollView>

        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

        <fragment
            android:id="@+id/choose_area_fragment"
            android:name="com.example.weather.ChooseAreaFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start">

        </fragment>

    </androidx.drawerlayout.widget.DrawerLayout>

</FrameLayout>

新建 WeatherActivity 类去处理相关逻辑,可以参考 源码文件

后台自动更新天气

利用 service 和 AlarmManager 实现定时更新

public class AutoUpdateService extends Service {

    private static final String TAG = "ZLTEST";

    public AutoUpdateService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        updateWeather();
        updateBingPic();
        AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
        int anHour = 8*60*1000;
        long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
        Intent intent1 = new Intent(this, AutoUpdateService.class);
        PendingIntent pendingIntent = PendingIntent.getService(this,
                0, intent1, 0);
        manager.cancel(pendingIntent);
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);
        return super.onStartCommand(intent, flags, startId);
    }

    private void updateBingPic() {
        LogUtil.d(TAG,"updateBingPic");
        String requestBingPic = "http://guolin.tech/api/bing_pic";
        HttpUtil.sendOkHttpRequest(requestBingPic, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String bingPic = response.body().string();
                SharedPreferences.Editor editor = PreferenceManager.
                        getDefaultSharedPreferences(AutoUpdateService.this).edit();
                editor.putString("bing_pic", bingPic);
                editor.apply();
            }
        });
    }

    private void updateWeather() {
        LogUtil.d(TAG,"updateWeather");
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        String weatherString = preferences.getString("weather", null);
        if (weatherString != null) {
            Weather weather = Utility.handleWeatherResponse(weatherString);
            String weatherId = weather.basic.weatherId;
            String weatherUrl = "http://guolin.tech/api/weather?cityid=" +
                    weatherId + "&key=a6ddec4e22e145eabb7e2ccafb24e0bd";
            HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String responseText = response.body().string();
                    Weather weather = Utility.handleWeatherResponse(responseText);
                    if (weather != null && "ok".equals(weather.status)) {
                        SharedPreferences.Editor editor = PreferenceManager.
                                getDefaultSharedPreferences(AutoUpdateService.this)
                                .edit();
                        editor.putString("weather", responseText);
                        editor.apply();

                    }
                }
            });
        }
    }
}

修改图标和名称

修改文件 AndroidManifest.xml

android:icon 对应图标,android:label 对应名称

    <application
        android:name="com.example.weather.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/we"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/we"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true">
</application>

项目源码下载

Github

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-19 12:09:56  更:2021-08-19 12:11:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:54:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码