Android 天气APP(二十三)增加灾害预警、优化主页面UI

简介: Android 天气APP(二十三)增加灾害预警、优化主页面UI

效果图


image.gif



前言


  天气预报光有普通天气总感觉好少了点什么,所以和风天气给补上了,那就是灾害天气的预警,灾害预警API可以获取指定城市的极端天气预警数据。


一、灾害预警


首先当然是从API下手了。测试API地址如下:


https://devapi.heweather.net/v7/warning/now?key=3086e91d66c04ce588a7f538f917c7f4&location=101200106


随便打开一个网页,复制进去回车你就能拿到返回数据,还是比较简单的。


20200814161829356.png


1.数据实体


通过这些数据生成一个实体bean,在app的bean包下新建一个WarningResponse


20200814162422745.png



代码如下:

package com.llw.goodweather.bean;
import java.util.List;
public class WarningResponse {
    /**
     * code : 200
     * updateTime : 2020-08-14T10:10+08:00
     * fxLink : http://hfx.link/2fh5
     * warning : [{"id":"23062241600000_20200813132751","sender":"肇源县气象局","pubTime":"2020-08-13T13:28+08:00","title":"肇源县气象局发布大风蓝色预警[IV级/一般]","startTime":"2020-08-13T13:30+08:00","endTime":"2020-08-14T13:30+08:00","status":"active","level":"蓝色","type":"11B06","typeName":"大风","text":"肇源县气象台2020年8月13日13时28分发布大风蓝色预警信号:预计未来24小时肇源县受大风影响,平均风力可达5-6级,阵风可达7-8级,请有关单位和个人注意做好预防工作。防御指南:1.政府及相关部门按照职责做好防大风工作;2.关好门窗,加固围板、棚架、广告牌等易被风吹动的搭建物,妥善安置易受大风影响的室外物品,遮盖建筑物资;3.行人注意尽量少骑自行车,刮风时不要在广告牌、临时搭建物等下面逗留;4.有关部门和单位请注意森林、草原防火等防火,个人请注意室外和野外用火安全。             ","related":""}]
     * refer : {"sources":["12379","Weather China"],"license":["no commercial use"]}
     */
    private String code;
    private String updateTime;
    private String fxLink;
    private ReferBean refer;
    private List<WarningBean> warning;
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getUpdateTime() {
        return updateTime;
    }
    public void setUpdateTime(String updateTime) {
        this.updateTime = updateTime;
    }
    public String getFxLink() {
        return fxLink;
    }
    public void setFxLink(String fxLink) {
        this.fxLink = fxLink;
    }
    public ReferBean getRefer() {
        return refer;
    }
    public void setRefer(ReferBean refer) {
        this.refer = refer;
    }
    public List<WarningBean> getWarning() {
        return warning;
    }
    public void setWarning(List<WarningBean> warning) {
        this.warning = warning;
    }
    public static class ReferBean {
        private List<String> sources;
        private List<String> license;
        public List<String> getSources() {
            return sources;
        }
        public void setSources(List<String> sources) {
            this.sources = sources;
        }
        public List<String> getLicense() {
            return license;
        }
        public void setLicense(List<String> license) {
            this.license = license;
        }
    }
    public static class WarningBean {
        /**
         * id : 23062241600000_20200813132751
         * sender : 肇源县气象局
         * pubTime : 2020-08-13T13:28+08:00
         * title : 肇源县气象局发布大风蓝色预警[IV级/一般]
         * startTime : 2020-08-13T13:30+08:00
         * endTime : 2020-08-14T13:30+08:00
         * status : active
         * level : 蓝色
         * type : 11B06
         * typeName : 大风
         * text : 肇源县气象台2020年8月13日13时28分发布大风蓝色预警信号:预计未来24小时肇源县受大风影响,平均风力可达5-6级,阵风可达7-8级,请有关单位和个人注意做好预防工作。防御指南:1.政府及相关部门按照职责做好防大风工作;2.关好门窗,加固围板、棚架、广告牌等易被风吹动的搭建物,妥善安置易受大风影响的室外物品,遮盖建筑物资;3.行人注意尽量少骑自行车,刮风时不要在广告牌、临时搭建物等下面逗留;4.有关部门和单位请注意森林、草原防火等防火,个人请注意室外和野外用火安全。             
         * related :
         */
        private String id;
        private String sender;
        private String pubTime;
        private String title;
        private String startTime;
        private String endTime;
        private String status;
        private String level;
        private String type;
        private String typeName;
        private String text;
        private String related;
        public String getId() {
            return id;
        }
        public void setId(String id) {
            this.id = id;
        }
        public String getSender() {
            return sender;
        }
        public void setSender(String sender) {
            this.sender = sender;
        }
        public String getPubTime() {
            return pubTime;
        }
        public void setPubTime(String pubTime) {
            this.pubTime = pubTime;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
        public String getStartTime() {
            return startTime;
        }
        public void setStartTime(String startTime) {
            this.startTime = startTime;
        }
        public String getEndTime() {
            return endTime;
        }
        public void setEndTime(String endTime) {
            this.endTime = endTime;
        }
        public String getStatus() {
            return status;
        }
        public void setStatus(String status) {
            this.status = status;
        }
        public String getLevel() {
            return level;
        }
        public void setLevel(String level) {
            this.level = level;
        }
        public String getType() {
            return type;
        }
        public void setType(String type) {
            this.type = type;
        }
        public String getTypeName() {
            return typeName;
        }
        public void setTypeName(String typeName) {
            this.typeName = typeName;
        }
        public String getText() {
            return text;
        }
        public void setText(String text) {
            this.text = text;
        }
        public String getRelated() {
            return related;
        }
        public void setRelated(String related) {
            this.related = related;
        }
    }
}


2.新增API和方法


打开ApiService


20200814162747686.png


新增了一个api接口,然后进入WeatherContract中,新增请求方法和返回


2020081416295054.png

20200814163018837.png


然后进入到MainActivity中增加


20200814163144606.png


完成到这里,然后做数据的请求,在搜索城市的返回值中获取id,然后写入请求。


3.数据渲染


20200814163403991.png


然后在返回的地方做数据的展示处理就可以了。先进入到activity_main.xml中,增加一个TextView,这个TextView做了一个简单的自定义修改,在mvplibrary下的view包下新建一个MarqueeTextView,然后继承TextView,代码如下:

package com.llw.mvplibrary.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
import androidx.annotation.Nullable;
@SuppressLint("AppCompatCustomView")
public class MarqueeTextView extends TextView {
    public MarqueeTextView(Context context) {
        super(context);
    }
    public MarqueeTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    public MarqueeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    public boolean isFocused() {
        return true;
    }
}


然后在布局中使用。


20200814163852821.png


注意我放的位置,是在星期的上面,这个布局也要算在滑动的高度计算里面


<!--灾害预警-->
<com.llw.mvplibrary.view.MarqueeTextView
     android:id="@+id/tv_warn"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_marginStart="@dimen/dp_16"
     android:layout_marginEnd="@dimen/dp_16"
     android:ellipsize="marquee"
     android:marqueeRepeatLimit="marquee_forever"
     android:paddingTop="@dimen/dp_4"
     android:paddingBottom="@dimen/dp_4"
     android:singleLine="true"
     android:textColor="@color/white"
     android:textSize="@dimen/sp_12" />


android:marqueeRepeatLimit="marquee_forever"表示一直滚动

android:singleLine="true"表示单行

android:ellipsize="marquee"这里设置为超出文本后滚动显示


在MainActivity中声明


20200814164438613.png


在返回值中做显示处理


20210228121630838.png


这个灾害预警是存在没有数据的情况,所以没有数据的时候就隐藏掉这个TextView,这个我要说明一下不是所有城市都有灾害预警的,看你的运行了,如果没有数据你得到的返回就是这样的。


{
    "code": "200",
    "updateTime": "2020-08-14T10:59+08:00",
    "fxLink": "http://hfx.link/1u0z5",
    "warning": [],
    "refer": {
        "sources": [
            "12379",
            "Weather China"
        ],
        "license": [
            "no commercial use"
        ]
    }
}


这个我还特地问过和风那边是怎么回事,他们是这样回复我的。


如果你查询的城市预警信息返回为空,则代表这个城市当前没有预警信息。你也可以通过预警城市列表获得当前所有发生预警的城市id。即如果你想知道现在深圳市是否有预警,可以直接访问深圳市的预警信息,返回为空则当前无预警,或者访问预警城市列表,如果深圳城市id不在这个列表中,也代表当前深圳无预警。


他这里提到的预警城市列表,你可以用这个请求地址去获取,


https://devapi.heweather.net/v7/warning/list?range=cn&key=3086e91d66c04ce588a7f538f917c7f4


返回值就是当前有灾害预警的城市id列表,但是这个里面如果没有你当前定位到的城市的id,那你这个城市就没有灾害预警的信息,当然你想看数据的话,可以这样。下面我用这个101200106来演示这些数据。否则不够直观。


20200814165346704.png


先这样赋值,然后你现在就可以运行了。


20200814165603597.gif


OK,效果就是上面那样,下面要做这个点击之后打开详情页面


4.灾害预报详情


在app下的ui包中新建一个WarnActivity,页面的布局如下:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/img_6"
    android:fitsSystemWindows="true"
    android:orientation="vertical"
    tools:context=".ui.WarnActivity">
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:contentInsetLeft="@dimen/dp_16"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIcon="@mipmap/icon_return_white"
        app:popupTheme="@style/AppTheme.PopupOverlay">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="灾害预警详情"
            android:textColor="@color/white"
            android:textSize="@dimen/sp_18" />
    </androidx.appcompat.widget.Toolbar>
    <androidx.recyclerview.widget.RecyclerView
        android:paddingTop="@dimen/dp_10"
        android:id="@+id/rv"
        android:overScrollMode="never"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>


布局很简单就是一个标题和一个列表。

然后创建item的布局,在layout下新建一个item_warn_list.xml,代码如下:


<?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"
    android:layout_marginBottom="@dimen/dp_10"
    android:layout_marginLeft="@dimen/dp_20"
    android:layout_marginRight="@dimen/dp_20"
    android:background="@drawable/shape_transparent_12"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="@dimen/dp_20">
    <TextView
        android:id="@+id/tv_city"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="城市"
        android:textColor="@color/white"
        android:textSize="@dimen/sp_16" />
    <TextView
        android:id="@+id/tv_type_name_and_level"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dp_8"
        android:text="预警类型"
        android:textColor="@color/white"
        android:textSize="@dimen/sp_14" />
    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dp_12"
        android:text="预警详细内容"
        android:textColor="@color/white"
        android:textSize="@dimen/sp_14" />
    <TextView
        android:id="@+id/tv_time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dp_8"
        android:gravity="right"
        android:text="预警发布时间"
        android:textColor="@color/white"
        android:textSize="@dimen/sp_12" />
</LinearLayout>


也是比较的简单。

然后就要建适配器了,但是这个用内部类来解决好了。

在WarnActivity中,写入

  /**
     * 内部适配器
     */
    public class WarnAdapter extends BaseQuickAdapter<WarningResponse.WarningBean, BaseViewHolder> {
        public WarnAdapter(int layoutResId, @Nullable List<WarningResponse.WarningBean> data) {
            super(layoutResId, data);
        }
        @RequiresApi(api = Build.VERSION_CODES.O)
        @Override
        protected void convert(BaseViewHolder helper, WarningResponse.WarningBean item) {
            TextView tvTime = helper.getView(R.id.tv_time);
            String time = DateUtils.updateTime(item.getPubTime());
            tvTime.setText("预警发布时间:" + WeatherUtil.showTimeInfo(time) + time);
            helper.setText(R.id.tv_city, item.getSender())//地区
                    .setText(R.id.tv_type_name_and_level,
                            item.getTypeName() + item.getLevel() + "预警")//预警类型名称和等级
                    .setText(R.id.tv_content, item.getText());//预警详情内容
        }
    }


这段代码和onCreate是平级的。现在就要考虑数据的来源了,因为我们是在MainActivity中做请求的,但是详情数据在WarnActivity中显示,所以要先把数据传过来。


回到MainActivity,定义一个全局变量

private String warnBodyString = null;//灾害预警数据字符串

20210228121716104.png


然后在返回值中将实体转换为JSON字符串,


20200814171149737.png


再点击时传递到WarnActivity。


进入到WarnActivity,先继承BaseActivity,然后实现两个构造方法。将布局复制到getLayoutId的返回中,删掉onCreate方法。


然后在initData方法中实例化适配器,并填入数据


  @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void initData(Bundle savedInstanceState) {
        StatusBarUtil.transparencyBar(context);//透明状态栏
        Back(toolbar);
        WarningResponse data = new Gson().fromJson(getIntent().getStringExtra("warnBodyString"), WarningResponse.class);
        WarnAdapter mAdapter = new WarnAdapter(R.layout.item_warn_list,data.getWarning());
        rv.setLayoutManager(new LinearLayoutManager(context));
        rv.setAdapter(mAdapter);
        mAdapter.notifyDataSetChanged();
        runLayoutAnimation(rv);
    }


大功告成,运行一下。


image.gif


完成后别忘了,将之前那个locationId = "101200106"改成

locationId = response.body().getLocation().get(0).getId();//城市Id

二、UI优化


1.主页面布局优化


打开activity_main.xml


20200814173003934.png



请根据这种图来修改。然后看一下ImageView的内容


  <ImageView
        android:id="@+id/bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/img_5"
        android:scaleType="centerCrop" />


20200814173149268.png


回到MainActivity中,修改


20200814173257164.png


改成ImageView。


20200814173343104.png


获取缓存时


20200814173412763.png


必应返回时。然后运行,看起来就会舒服一些。


20200814173645753.png


因为我用的是每日一图,所以就不会是默认的背景。


总结


总的来说还是不错的,我本意还是不希望一篇文章过长,否则会显得很乱,没有条理性,所以这篇文章也就要结束了。如果你有兴趣的话可以继续往下看


相关文章
|
2月前
|
移动开发 监控 前端开发
构建高效Android应用:从优化布局到提升性能
【7月更文挑战第60天】在移动开发领域,一个流畅且响应迅速的应用程序是用户留存的关键。针对Android平台,开发者面临的挑战包括多样化的设备兼容性和性能优化。本文将深入探讨如何通过改进布局设计、内存管理和多线程处理来构建高效的Android应用。我们将剖析布局优化的细节,并讨论最新的Android性能提升策略,以帮助开发者创建更快速、更流畅的用户体验。
52 10
|
21天前
|
存储 缓存 编解码
Android经典面试题之图片Bitmap怎么做优化
本文介绍了图片相关的内存优化方法,包括分辨率适配、图片压缩与缓存。文中详细讲解了如何根据不同分辨率放置图片资源,避免图片拉伸变形;并通过示例代码展示了使用`BitmapFactory.Options`进行图片压缩的具体步骤。此外,还介绍了Glide等第三方库如何利用LRU算法实现高效图片缓存。
40 20
Android经典面试题之图片Bitmap怎么做优化
|
14天前
|
XML Android开发 UED
💥Android UI设计新风尚!掌握Material Design精髓,让你的界面颜值爆表!🎨
随着移动应用市场的蓬勃发展,用户对界面设计的要求日益提高。为此,掌握由Google推出的Material Design设计语言成为提升应用颜值和用户体验的关键。本文将带你深入了解Material Design的核心原则,如真实感、统一性和创新性,并通过丰富的组件库及示例代码,助你轻松打造美观且一致的应用界面。无论是色彩搭配还是动画效果,Material Design都能为你的Android应用增添无限魅力。
31 1
|
24天前
|
移动开发 定位技术 Android开发
「揭秘高效App的秘密武器」:Kotlin Flow携手ViewModel,打造极致响应式UI体验,你不可不知的技术革新!
【9月更文挑战第12天】随着移动开发领域对响应式编程的需求增加,管理应用程序状态变得至关重要。Jetpack Compose 和 Kotlin Flow 的组合提供了一种优雅的方式处理 UI 状态变化,简化了状态管理。本文探讨如何利用 Kotlin Flow 增强 ViewModel 功能,构建简洁强大的响应式 UI。
30 3
|
24天前
|
Java Android开发 UED
安卓应用开发中的内存管理优化技巧
在安卓开发的广阔天地里,内存管理是一块让开发者既爱又恨的领域。它如同一位严苛的考官,时刻考验着开发者的智慧与耐心。然而,只要我们掌握了正确的优化技巧,就能够驯服这位考官,让我们的应用在性能和用户体验上更上一层楼。本文将带你走进内存管理的迷宫,用通俗易懂的语言解读那些看似复杂的优化策略,让你的开发之路更加顺畅。
32 2
|
25天前
|
Java Android开发 开发者
安卓应用开发中的线程管理优化技巧
【9月更文挑战第10天】在安卓开发的海洋里,线程管理犹如航行的风帆,掌握好它,能让应用乘风破浪,反之则可能遭遇性能的暗礁。本文将通过浅显易懂的语言和生动的比喻,带你探索如何优雅地处理安卓中的线程问题,从基础的线程创建到高级的线程池运用,让你的应用运行更加流畅。
|
2月前
|
存储 搜索推荐 Java
探索安卓开发中的自定义视图:打造个性化UI组件Java中的异常处理:从基础到高级
【8月更文挑战第29天】在安卓应用的海洋中,一个独特的用户界面(UI)能让应用脱颖而出。自定义视图是实现这一目标的强大工具。本文将通过一个简单的自定义计数器视图示例,展示如何从零开始创建一个具有独特风格和功能的安卓UI组件,并讨论在此过程中涉及的设计原则、性能优化和兼容性问题。准备好让你的应用与众不同了吗?让我们开始吧!
|
2月前
|
编解码 Android开发
【Android Studio】使用UI工具绘制,ConstraintLayout 限制性布局,快速上手
本文介绍了Android Studio中使用ConstraintLayout布局的方法,通过创建布局文件、设置控件约束等步骤,快速上手UI设计,并提供了一个TV Launcher界面布局的绘制示例。
37 1
|
22天前
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
43 0
|
1月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
111 0
下一篇
无影云桌面