Android——一个简单的天气APP

这篇具有很好参考价值的文章主要介绍了Android——一个简单的天气APP。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

效果演示视频

EasyWeather演示效果视频

简述

此天气数据源采用心知天气API(试用版),免费版获取数据有限,只能获取普通的温度、湿度等,例如压力、云量、可见度等均获取不到,试用版相当于正式版,可以获取大部分数据,试用日期是14天。

首页不同城市天气页面之间的滑动采用的是ViewPager,编辑界面的搜索栏采用的是SearchView+ListView,其中城市数据源是统计到一个xml文件中;通过点击搜索匹配项,插入至SQLite数据库中,然后刷新当前天气子项,然后通过EventBus通知首页更新views页面。处于编辑状态时,删除子项,同样使用EventBus通知首页更新;更新主要是页面数量更新和下方指示器更新。

天气JSON数据

实况天气

{
    "results":[
        {
            "location":{
                "id":"WKZTU85FVNSV",
                "name":"娄底",
                "country":"CN",
                "path":"娄底,娄底,湖南,中国",
                "timezone":"Asia/Shanghai",
                "timezone_offset":"+08:00"
            },
            "now":{
                "text":"晴",
                "code":"1",
                "temperature":"25",
                "feels_like":"26",
                "pressure":"984",
                "humidity":"56",
                "visibility":"19.0",
                "wind_direction":"北",
                "wind_direction_degree":"342",
                "wind_speed":"6.0",
                "wind_scale":"2",
                "clouds":"13",
                "dew_point":""
            },
            "last_update":"2022-09-02T22:08:30+08:00"
        }
    ]
}

逐24小时天气预报

{
    "results":[
        {
            "location":{
                "id":"WWYMRT0VRMUG",
                "name":"大连",
                "country":"CN",
                "path":"大连,大连,辽宁,中国",
                "timezone":"Asia/Shanghai",
                "timezone_offset":"+08:00"
            },
            "hourly":[
                {
                    "time":"2022-09-02T22:00:00+08:00",
                    "text":"多云",
                    "code":"4",
                    "temperature":"21",
                    "humidity":"81",
                    "wind_direction":"东",
                    "wind_speed":"7.52"
                },
                {
                    "time":"2022-09-02T23:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"21",
                    "humidity":"82",
                    "wind_direction":"东北",
                    "wind_speed":"7.02"
                },
                {
                    "time":"2022-09-03T00:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"21",
                    "humidity":"83",
                    "wind_direction":"东北",
                    "wind_speed":"7.81"
                },
                {
                    "time":"2022-09-03T01:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"21",
                    "humidity":"84",
                    "wind_direction":"东北",
                    "wind_speed":"8.64"
                },
                {
                    "time":"2022-09-03T02:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"21",
                    "humidity":"85",
                    "wind_direction":"东北",
                    "wind_speed":"9.54"
                },
                {
                    "time":"2022-09-03T03:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"21",
                    "humidity":"85",
                    "wind_direction":"东北",
                    "wind_speed":"10.15"
                },
                {
                    "time":"2022-09-03T04:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"21",
                    "humidity":"86",
                    "wind_direction":"东北",
                    "wind_speed":"10.73"
                },
                {
                    "time":"2022-09-03T05:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"21",
                    "humidity":"86",
                    "wind_direction":"东北",
                    "wind_speed":"11.34"
                },
                {
                    "time":"2022-09-03T06:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"21",
                    "humidity":"86",
                    "wind_direction":"东北",
                    "wind_speed":"13.68"
                },
                {
                    "time":"2022-09-03T07:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"22",
                    "humidity":"85",
                    "wind_direction":"东北",
                    "wind_speed":"16.16"
                },
                {
                    "time":"2022-09-03T08:00:00+08:00",
                    "text":"多云",
                    "code":"4",
                    "temperature":"23",
                    "humidity":"83",
                    "wind_direction":"东北",
                    "wind_speed":"18.72"
                },
                {
                    "time":"2022-09-03T09:00:00+08:00",
                    "text":"多云",
                    "code":"4",
                    "temperature":"23",
                    "humidity":"81",
                    "wind_direction":"东",
                    "wind_speed":"18.18"
                },
                {
                    "time":"2022-09-03T10:00:00+08:00",
                    "text":"多云",
                    "code":"4",
                    "temperature":"24",
                    "humidity":"79",
                    "wind_direction":"东",
                    "wind_speed":"18.97"
                },
                {
                    "time":"2022-09-03T11:00:00+08:00",
                    "text":"晴",
                    "code":"0",
                    "temperature":"24",
                    "humidity":"77",
                    "wind_direction":"东",
                    "wind_speed":"20.92"
                },
                {
                    "time":"2022-09-03T12:00:00+08:00",
                    "text":"多云",
                    "code":"4",
                    "temperature":"24",
                    "humidity":"76",
                    "wind_direction":"东",
                    "wind_speed":"19.84"
                },
                {
                    "time":"2022-09-03T13:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"24",
                    "humidity":"76",
                    "wind_direction":"东",
                    "wind_speed":"19.12"
                },
                {
                    "time":"2022-09-03T14:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"24",
                    "humidity":"75",
                    "wind_direction":"东",
                    "wind_speed":"18.83"
                },
                {
                    "time":"2022-09-03T15:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"24",
                    "humidity":"76",
                    "wind_direction":"东",
                    "wind_speed":"19.44"
                },
                {
                    "time":"2022-09-03T16:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"23",
                    "humidity":"77",
                    "wind_direction":"东",
                    "wind_speed":"20.09"
                },
                {
                    "time":"2022-09-03T17:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"23",
                    "humidity":"77",
                    "wind_direction":"东",
                    "wind_speed":"20.77"
                },
                {
                    "time":"2022-09-03T18:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"22",
                    "humidity":"78",
                    "wind_direction":"东",
                    "wind_speed":"19.66"
                },
                {
                    "time":"2022-09-03T19:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"22",
                    "humidity":"78",
                    "wind_direction":"东",
                    "wind_speed":"18.58"
                },
                {
                    "time":"2022-09-03T20:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"22",
                    "humidity":"78",
                    "wind_direction":"东",
                    "wind_speed":"17.53"
                },
                {
                    "time":"2022-09-03T21:00:00+08:00",
                    "text":"阴",
                    "code":"9",
                    "temperature":"22",
                    "humidity":"78",
                    "wind_direction":"东",
                    "wind_speed":"15.7"
                }
            ]
        }
    ]
}

未来七天天气预报

{
    "results":[
        {
            "location":{
                "id":"WWYMRT0VRMUG",
                "name":"大连",
                "country":"CN",
                "path":"大连,大连,辽宁,中国",
                "timezone":"Asia/Shanghai",
                "timezone_offset":"+08:00"
            },
            "daily":[
                {
                    "date":"2022-09-02",
                    "text_day":"晴",
                    "code_day":"0",
                    "text_night":"阴",
                    "code_night":"9",
                    "high":"23",
                    "low":"17",
                    "rainfall":"0.00",
                    "precip":"0.00",
                    "wind_direction":"东北",
                    "wind_direction_degree":"65",
                    "wind_speed":"6.41",
                    "wind_scale":"2",
                    "humidity":"60"
                },
                {
                    "date":"2022-09-03",
                    "text_day":"阴",
                    "code_day":"9",
                    "text_night":"阴",
                    "code_night":"9",
                    "high":"24",
                    "low":"21",
                    "rainfall":"0.00",
                    "precip":"0.00",
                    "wind_direction":"东",
                    "wind_direction_degree":"86",
                    "wind_speed":"19.44",
                    "wind_scale":"3",
                    "humidity":"83"
                },
                {
                    "date":"2022-09-04",
                    "text_day":"小雨",
                    "code_day":"13",
                    "text_night":"阴",
                    "code_night":"9",
                    "high":"22",
                    "low":"19",
                    "rainfall":"0.69",
                    "precip":"0.91",
                    "wind_direction":"东北",
                    "wind_direction_degree":"51",
                    "wind_speed":"15.19",
                    "wind_scale":"3",
                    "humidity":"85"
                },
                {
                    "date":"2022-09-05",
                    "text_day":"小雨",
                    "code_day":"13",
                    "text_night":"晴",
                    "code_night":"1",
                    "high":"24",
                    "low":"18",
                    "rainfall":"0.14",
                    "precip":"0.56",
                    "wind_direction":"西北",
                    "wind_direction_degree":"321",
                    "wind_speed":"18.54",
                    "wind_scale":"3",
                    "humidity":"86"
                },
                {
                    "date":"2022-09-06",
                    "text_day":"晴",
                    "code_day":"0",
                    "text_night":"晴",
                    "code_night":"1",
                    "high":"23",
                    "low":"20",
                    "rainfall":"0.00",
                    "precip":"0.00",
                    "wind_direction":"西",
                    "wind_direction_degree":"288",
                    "wind_speed":"19.66",
                    "wind_scale":"3",
                    "humidity":"62"
                },
                {
                    "date":"2022-09-07",
                    "text_day":"多云",
                    "code_day":"4",
                    "text_night":"阴",
                    "code_night":"9",
                    "high":"26",
                    "low":"20",
                    "rainfall":"0.00",
                    "precip":"0.00",
                    "wind_direction":"西南",
                    "wind_direction_degree":"229",
                    "wind_speed":"14.04",
                    "wind_scale":"3",
                    "humidity":"73"
                },
                {
                    "date":"2022-09-08",
                    "text_day":"阴",
                    "code_day":"9",
                    "text_night":"阴",
                    "code_night":"9",
                    "high":"25",
                    "low":"22",
                    "rainfall":"0.00",
                    "precip":"0.00",
                    "wind_direction":"东南",
                    "wind_direction_degree":"149",
                    "wind_speed":"6.77",
                    "wind_scale":"2",
                    "humidity":"71"
                }
            ],
            "last_update":"2022-09-02T20:00:00+08:00"
        }
    ]
}

天气详情页

包括实况天气、逐24小时天气预、未来七天天气预报三部分数据

效果图

Android——一个简单的天气APP

获取JSON数据

首先通过OKHttp使用get方式获取数据,不同的天气数据,传入不同的url,所以把请求作为公共方式,然后通过写一个回调接口,将数据源回调至外部。

public void Post(String url, HttpCallback callback){
        OkHttpClient client = new OkHttpClient();

        final Request request = new Request.Builder()
                .url(url)
                .get()
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onFailed(ErrorCodeParam.NetworkError);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                int code = response.code();
                if (code == 200){
                    String json = response.body().string();
                    callback.onResponse(json.toString());
                }else {
                    callback.onFailed(ErrorCodeParam.PostError);
                }
            }
        });
    }

URL请求

实况天气URL

具体方法参考官网
官网所展示的请求参数并不是需要所有都添加,例如语言都有默认想,一般不需要提交,在官网也有标注,此处传入key(心知天气API密钥)和城市(你所想获取天气预报的城市,可以是汉字)

/**
     * 获取当前实况天气*/
    public String getNowUrl(String location) {
        HttpUrl.Builder builder = HttpUrl.parse(WeatherParam.NowWeatherURL).newBuilder();
        builder.addQueryParameter("key",WeatherParam.weatherToken);
        builder.addQueryParameter("location",location);

        return builder.build().toString();
    }
逐24小时天气预报URL

具体参考官网
前两项参数与实况天气一致,第三个参数是你需要获取多少小时的天气预报数据,以当前时间为第一个小时;例如:你传入5个小时,你当时系统时间是9点,那么返回的第一个数据就是9点,第二个为10…第5个为13点;以此类推

 /**
     *  获取24小时天气情况*/
    public String getHourly24Url(String location,int hours) {
        HttpUrl.Builder builder = HttpUrl.parse(WeatherParam.Hourly24WeatherURL).newBuilder();
        builder.addQueryParameter("key",WeatherParam.weatherToken);
        builder.addQueryParameter("location",location);
        builder.addQueryParameter("hours",hours+"");

        return builder.build().toString();
    }
未来七天天气预报URL

具体参考官网
第三个参数与逐小时天气预报的小时一致,以当前日期为第一天;请求天数好像最大为15天

   /**
     * 获取未来七天天气预报情况*/
    public String getFuture7Url(String location,int days) {
        HttpUrl.Builder builder = HttpUrl.parse(WeatherParam.Future7WeatherURL).newBuilder();
        builder.addQueryParameter("key",WeatherParam.weatherToken);
        builder.addQueryParameter("location",location);
        builder.addQueryParameter("days",days+"");

        return builder.build().toString();
    }

解析JSON数据

解析实况天气数据

JSON数据格式在上文有提及,返回的数据较多,我们只需要关于天气的即可,地点可以不解析;此处将数据源解析成具体实体类,依旧通过回调接口,暴露给外部。

 /**
     * 获取当前天气情况
     */
     fun getNowWeather(location: String,callback: WeatherCallback_now) {
        val url = HttpUtils.getInstance().getNowUrl(location)
        Log.d(TAG, "url = $url")
        HttpUtils.getInstance().Post(url, object : HttpCallback {
            override fun onFailed(ErrorCode: Int) {
                callback.onFailed(ErrorCode)
            }
            override fun onResponse(JSONData: String) {
                if (TextUtils.isEmpty(JSONData)) {
                    callback.onFailed(0)
                    return
                }
                Log.d(TAG, "now = $JSONData")
                try {
                    val jsonObject = JSONObject(JSONData)
                    val jsonArray = jsonObject.getJSONArray("results")
                    val now = jsonArray.getJSONObject(0).getJSONObject("now")
                    val time : String = jsonArray.getJSONObject(0).getString("last_update");
                    val bean : WRealTimeBean? = HttpUtils.getInstance().fromJson(
                        now.toString(),
                        WRealTimeBean::class.java
                    )

                    if (bean != null) {
                        bean.last_update = time
                        bean.location = location;
                    }
                    callback.onSuccess(bean)
                } catch (e: JSONException) {
                    e.printStackTrace()
                }
            }
        })
    }
解析逐小时天气预报

步骤与实况天气雷同,区别在于逐小时天气预报返回的数组,所以回调接口,返回也是list数据

/**
     * 获取24小时天气情况
     */
    fun getHourly24Weather(location: String,callback: WeatherCallback_24H) {
        val url = HttpUtils.getInstance().getHourly24Url(location, 24)
        Log.d(TAG, "url = $url")
        HttpUtils.getInstance().Post(url, object : HttpCallback {
            override fun onFailed(ErrorCode: Int) {
                callback.onFailed(ErrorCode)
            }
            override fun onResponse(JSONData: String) {
                if (TextUtils.isEmpty(JSONData)) {
                    callback.onFailed(0)
                    return
                }
                Log.d(TAG, "hourlv24 = $JSONData")
                try {
                    val jsonObject = JSONObject(JSONData)
                    val jsonArray = jsonObject.getJSONArray("results")
                    val hourly24 = jsonArray.getJSONObject(0).getJSONArray("hourly")
                    val bean: MutableList<WHourly24Bean>? = HttpUtils.getInstance().fromListJson(
                        hourly24.toString(),
                        WHourly24Bean::class.java
                    )
                    callback.onSuccess(bean)
                } catch (e: JSONException) {
                    e.printStackTrace()
                }
            }
        })
    }
解析未来七天天气预报

同样返回的是数组数据,完成数据解析并回调;值得注意的是,如果有存在重复的城市名称,返回的数据也是多份,例如请求的城市名称并不精准,本来想请求张家界的天气数据,但是只输入张家二字,系统后台会返回张家界和张家口的数据,所以我们默认取第一个数据源

   /**
     * 获取未来七天天气情况(包括今天)
     */
     fun getFuture7Weather(location: String,callback: WeatherCallback_7D) {
        val url = HttpUtils.getInstance().getFuture7Url(location, 7)
        Log.d(TAG, "url = $url")
        HttpUtils.getInstance().Post(url, object : HttpCallback {
            override fun onFailed(ErrorCode: Int) {
                callback.onFailed(ErrorCode)
            }
            override fun onResponse(JSONData: String) {
                if (TextUtils.isEmpty(JSONData)) {
                    callback.onFailed(0)
                    return
                }
                Log.d(TAG, "future7 = $JSONData")
                try {
                    val jsonObject = JSONObject(JSONData)
                    val jsonArray = jsonObject.getJSONArray("results")
                    val future7 = jsonArray.getJSONObject(0).getJSONArray("daily")
                    val bean: MutableList<WFuture7Bean>? = HttpUtils.getInstance().fromListJson(
                        future7.toString(),
                        WFuture7Bean::class.java
                    )
                    callback.onSuccess(bean)
                } catch (e: JSONException) {
                    e.printStackTrace()
                }
            }
        })
    }

初始化天气详情页

获取当前位置

为了减轻app负重,并未采用高德、百度等API进行位置定位,采用原始的定位方式,使用网络方式进行定位

获取经纬度

获取位置信息需要动态申请位置权限

public String getLocationInfo() {
        if (ActivityCompat.checkSelfPermission(BaseApplication.context,Group_Location[0]) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(BaseApplication.context, Group_Location[1]) != PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "Don't apply for these permission");
            return null;
        }

        String strLocation = null;
        try {
            //获取系统的服务,
            locationManager = (LocationManager) BaseApplication.context.getSystemService(Context.LOCATION_SERVICE);
            //创建一个criteria对象
            Criteria criteria = new Criteria();
            criteria.setAccuracy(Criteria.ACCURACY_COARSE);
            //设置不需要获取海拔方向数据
            criteria.setAltitudeRequired(false);
            criteria.setBearingRequired(false);
            //设置允许产生资费
            criteria.setCostAllowed(true);
            //要求低耗电
            criteria.setPowerRequirement(Criteria.POWER_LOW);
            String provider = locationManager.getBestProvider(criteria, true);
            Location location = locationManager.getLastKnownLocation(provider);

            if (location == null)return null;

            //strLocation =  location.getLongitude()+","+location.getLatitude();
            strLocation = convertAddress(BaseApplication.context, location.getLatitude(), location.getLongitude());
            Log.d(TAG, "location is = " + strLocation);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return strLocation;
    }
经纬度转为地理信息

将经纬度转为具体地理信息,由于心知天气API需要提供城市级城市数据,所以我们只需要xx市数据即可

 private String convertAddress(Context context, double latitude, double longitude) {
        Geocoder mGeocoder = new Geocoder(context, Locale.getDefault());
        try {
            List<Address> mAddresses = mGeocoder.getFromLocation(latitude, longitude, 1);
            if (mAddresses != null && mAddresses.size() > 0) {
                Address address = mAddresses.get(0);
                Log.d(TAG, "国家 is " + address.getCountryName());
                Log.d(TAG, "省 is " + address.getAdminArea());
                Log.d(TAG, "市 is " + address.getLocality());
                Log.d(TAG, "区/县 is " + address.getSubLocality());
                Log.d(TAG, "具体 is " + address.getFeatureName());
                return  address.getLocality();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
页面初始化

详情页采用的是viewPager添加多个views实现页面滑动;
首先获取数据库内所有存储的城市名称,然后通过get模式获取天气的网络数据,然后填充到adapter中;需要注意的是获取的本地位置在整个app都较为特殊,与其他添加的城市数据存在差距,因为需要改变其显示状态,具体后文会提交,所以并未将此添加到数据库中。

private void initViewPager(){
        dao = new Dao(this);
        locationList = dao.QueryAll();
        location = LocationUtils.getInstance().getLocationInfo();

        if (locationList == null || locationList.size() == 0){
            locationList = new ArrayList<>();
            locationList.add(location);
        }else {
            locationList.add(0,location);
        }

        for (int i = 0; i < locationList.size(); i++) {
            Message message = new Message();
            message.what = WEATHER_Start;
            message.obj = locationList.get(i);
            handler.sendMessage(message);
        }

        adapter.notifyDataSetChanged();
    }

单个页面初始化,通过遍历,将所有页面进行填充;每个界面背景图片会根据心知天气返回天气状态发生变化,由于素材有限,只适配了较为常见的几种状态,例如:晴、多云、阴、雨、雪、雷

 /**
     * viewPager页面添加,包括实况天气数据、预期24小时、预报7天*/
    private void addView(String location){
        View view = LayoutInflater.from(this).inflate(R.layout.activity_main,null,false);

        LinearLayout weatherLayout;
        TextView weatherLocation,weatherTemp,weatherStatus,weatherWindDirection,weatherWindSpeed,weatherCloud,weatherFellLikes,weatherHum,weatherVisibility,weatherPressure;
        RecyclerView weather7D,weather24H;

        weatherLayout = view.findViewById(R.id.mainLinearLayout);
        weatherLocation = view.findViewById(R.id.normal_city);
        weatherTemp = view.findViewById(R.id.normal_temp);
        weatherStatus = view.findViewById(R.id.normal_status);
        weatherWindDirection = view.findViewById(R.id.windDirection);
        weatherWindSpeed = view.findViewById(R.id.windSpeed);
        weatherCloud = view.findViewById(R.id.cloud);
        weatherFellLikes = view.findViewById(R.id.bodyTmp);
        weatherHum = view.findViewById(R.id.hum);
        weatherVisibility = view.findViewById(R.id.visibility);
        weatherPressure = view.findViewById(R.id.pressure);
        weather7D = view.findViewById(R.id.Recycler_7D);
        weather24H = view.findViewById(R.id.Recycler_24H);


        List<WHourly24Bean> hourlyBeanList = new ArrayList<>();
        List<WFuture7Bean> dailyBeanList = new ArrayList<>();

        weather24H.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
        Weather24HAdapter  adapter24H = new Weather24HAdapter(hourlyBeanList);
        weather24H.setAdapter(adapter24H);

        weather7D.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        Weather7DAdapter adapter7D = new Weather7DAdapter(dailyBeanList);
        weather7D.setAdapter(adapter7D);

        viewList.add(view);
        titleList.add(location);

        adapter.notifyDataSetChanged();

        weatherLocation.setText(location);


        JsonUtils.INSTANCE.getNowWeather(location, new WeatherCallback_now() {
            @Override
            public void onFailed(int ErrorCode) {

            }

            @Override
            public void onSuccess(WRealTimeBean bean) {
                if (bean != null){
                    runOnUiThread(()->{
                        weatherTemp.setText(bean.getTemperature() + "°");//温度
                        weatherStatus.setText(bean.getText());//天气状态
                        weatherWindSpeed.setText(bean.getWindSpeed() + "km/h");//风速
                        weatherWindDirection.setText(bean.getWindDirection()+bean.getWindDirectionDegree()+ "°");//风向
                        weatherCloud.setText(bean.getClouds() + "%");//云量
                        weatherFellLikes.setText(bean.getFeelsLike() + "°");//体感温度
                        weatherHum.setText(bean.getHumidity() + "%");//湿度
                        weatherVisibility.setText(bean.getVisibility() + "km");//可见度
                        weatherPressure.setText(bean.getPressure() + "mb");//气压

                        switch (bean.getText()){
                            case "晴":weatherLayout.setBackground(getDrawable(R.drawable.icon_bg_sunny));break;
                            case "多云":weatherLayout.setBackground(getDrawable(R.drawable.icon_bg_cloudy));break;
                            case "阴":weatherLayout.setBackground(getDrawable(R.drawable.icon_bg_cloudy));break;
                            case "雨":weatherLayout.setBackground(getDrawable(R.drawable.icon_bg_big_rain));break;
                            case "雪":weatherLayout.setBackground(getDrawable(R.drawable.icon_bg_snow));break;
                            case "雷":weatherLayout.setBackground(getDrawable(R.drawable.icon_bg_thunder));break;
                        }
                    });
                }else {
                    Log.d(TAG,"bean is empty");
                }
            }
        });

        JsonUtils.INSTANCE.getFuture7Weather(location, new WeatherCallback_7D() {
            @Override
            public void onFailed(int ErrorCode) {

            }

            @Override
            public void onSuccess(List<WFuture7Bean> beanList) {
                if (beanList != null && beanList.size() > 0){
                    if (dailyBeanList != null && dailyBeanList.size() > 0){
                        dailyBeanList.clear();
                    }
                    dailyBeanList.addAll(beanList);
                    runOnUiThread(()->{
                        adapter7D.notifyDataSetChanged();
                    });
                }
            }
        });

        JsonUtils.INSTANCE.getHourly24Weather(location, new WeatherCallback_24H() {
            @Override
            public void onFailed(int ErrorCode) {

            }

            @Override
            public void onSuccess(List<WHourly24Bean> beanList) {
                if (beanList != null && beanList.size() > 0){
                    if (hourlyBeanList != null && hourlyBeanList.size() > 0){
                        hourlyBeanList.clear();
                    }
                    hourlyBeanList.addAll(beanList);
                    runOnUiThread(()->{
                        adapter24H.notifyDataSetChanged();
                    });
                }
            }
        });
    }
ViewPager子页面编辑

view添加和删除都是通过EventBus进行监听,然后操作adapter完成操作

 /**
     * 在城市页面进行数据添加或删除,使用EventBus进行监测*/
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void onEvent(LocationBusBean bean){
        if (bean != null){
            if (bean.getDeletePos() == -1){
                addView(bean.getLocation());
                updateIndicator();
            }else {
                removeView(bean.getLocation());
            }
        }
    }
页面添加

此功能就是重复调用单个views初始化方法,然后使用adapter进行notify和更新指示器即可

页面删除

通过从天气编辑页面点击的城市子项,传过来的城市数据,然后与views存在的数据进行匹配,然后删除对应的界面

   /**
     * 删除viewPager子项*/
    private void removeView(String location){
        int position = titleList.indexOf(location);
        if (position != -1){
            viewList.remove(position);
            titleList.remove(position);
            adapter.notifyDataSetChanged();
        }

        updateIndicator();
    }
指示器

指示器是通过两个xml定义不同的圆,然后通过selector文件进行选择,使用一个LinearLayout控件作为指示器控件,通过传入的指示器个数,添加多个view,然后设置背景为selector文件,通过设置其enable属性,改变圆形状态

  private void updateIndicator(){
        binding.indicatorLayout.removeAllViews();
        List<String> list = dao.QueryAll();

        /**
         * 因为有一个本地位置,所以需要+1*/
        int size = 1;
        if (list != null){
            size = list.size()+1;
        }
        for (int i = 0; i < size; i++) {
            View view = new View(this);
            view.setBackgroundResource(R.drawable.selector_indicator);
            view.setEnabled(false);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(30,30);
            params.rightMargin = 15;
            params.leftMargin = 15;
            binding.indicatorLayout.addView(view,params);
        }
    }

天气编辑页

此页面功能包括searchView和listView匹配搜索、城市天津、城市天气简单版子项显示、天气子项编辑等功能

效果图

Android——一个简单的天气APP

Android——一个简单的天气APP

简版天气数据

此数据与天气详情页数据请求一致,只是数据更为简单,值得注意的是,从天气详情页传过来的城市,并不显示其具体名称,而是以我的位置代替,因为是子线程加载,获取的数据排列方式不一,所以在展示数据时,需要将本地数据一列移到到最前方。

获取数据并初始化
/**
     * 获取所以数据库中城市的天气*/
    private void getWeatherData() {
        if (dao == null) {
            dao = new Dao(this);
        }

        beanList.clear();//防止数据重复

        List<String> locationList = dao.QueryAll();
        if (locationList == null || locationList.size() == 0) {
            locationList = new ArrayList<>();
        }

        if (locationList.size() > 0) {
            String data = locationList.get(0);
            if (!data.equals(location)) {
                locationList.add(0, location);
            }
        }else {
            locationList.add(location);
        }

        for (int i = 0; i < locationList.size(); i++) {
            postWeather(locationList.get(i), locationList.size());
        }
    }
子项删除

通过EventBus通知天气详情页进行更新

adapter.setDelItemClickListener(new LocationAdapter.OnWeatherItemsClickListener() {
            @Override
            public void onClickListener(int pos, String location) {
                beanList.remove(pos);
                dao.Delete(location);
                adapter.notifyDataSetChanged();

                EventBus.getDefault().postSticky(new LocationBusBean(location, pos));
            }
        });

搜索

效果图
Android——一个简单的天气APP
更改SearchView背景和字体样式

定义一个xml文件,然后在SearchView的background属性引用即可改变其背景

 android:background="@drawable/searchview_bg"
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="10dp" />
    <solid android:color="@color/searchViewBg" />
</shape>

更改SearchView字体颜色,需要获取其内置的一个控件id,然后通过EditText进行改变即可,TextView也可以

 /**
     * 更改searchView字体颜色
     */
    private void initSearchViewStyle() {
        EditText editText = (EditText) binding.searchView.findViewById(androidx.appcompat.R.id.search_src_text);
        if (editText != null) {
            editText.setTextColor(getColor(R.color.white));
            editText.setHintTextColor(getColor(R.color.searchHintColor));
            editText.setTextSize(14);

            SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
            binding.searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        } else {
            Log.d("MoreLocationActivity", "empty");
        }
    }
搜索初始化

重点在于xml城市列表文件,然后采用默认的adapter作为适配

private void initListView() {
        String[] cityArray = getResources().getStringArray(R.array.city);
        binding.locationList.setAdapter(new ArrayAdapter(this, R.layout.searchview_item, cityArray));
        /**
         * 属性为true表示listview获得当前焦点的时候,与相应用户输入的匹配符进行比对,筛选出匹配的ListView的列表中的项*/
        binding.locationList.setTextFilterEnabled(true);
        binding.searchView.setOnQueryTextListener(this);
        binding.searchView.setSubmitButtonEnabled(false);

        binding.locationList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                String str = adapterView.getAdapter().getItem(i).toString();
                if (dao == null) {
                    dao = new Dao(MoreLocationActivity.this);
                }
                boolean flag = dao.Query(str);
                if (flag) {
                    Toast.makeText(MoreLocationActivity.this, "该城市已添加到天气列表,请勿重复添加", Toast.LENGTH_SHORT).show();
                } else {
                    dao.Insert(str);
                    EventBus.getDefault().postSticky(new LocationBusBean(str, -1));
                    handler.sendEmptyMessage(1);
                    Toast.makeText(MoreLocationActivity.this, "添加成功", Toast.LENGTH_SHORT).show();
                }
                binding.locationList.clearTextFilter();
                binding.locationList.setVisibility(View.GONE);
            }
        });
    }
搜索字符监听

一开始那个提示黑框就比较呆,所以可以通过后面语句进行隐藏,因为搜索列表是覆盖简版天气子项的,所以当搜索列表显示时,天气简版隐藏,反之,亦然;

 @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        if (TextUtils.isEmpty(newText)) {
            binding.locationList.clearTextFilter();
            binding.locationList.setVisibility(View.GONE);
        } else {
            binding.locationList.setVisibility(View.VISIBLE);
            binding.locationList.setFilterText(newText);
            //隐藏黑框
            binding.locationList.dispatchDisplayHint(View.INVISIBLE);
        }
        return true;
    }

下载地址

Gitte下载链接文章来源地址https://www.toymoban.com/news/detail-425649.html

到了这里,关于Android——一个简单的天气APP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android Studio 实现天气预报App (简单方便展示内容超多)

    🍅 文章末尾有获取完整项目源码方式 🍅 目录 前言 一、任务介绍 1.1 背景 1.2目的和意义 二、 实现介绍 视频演示 2.1 启动页实现 2.2注册页面实现 2.3 登陆页面实现 2.4 首页实现 2.5 城市管理列表页面实现                三、获取源码         在使用Android Studio开发

    2024年04月24日
    浏览(36)
  • kotlin 编写一个简单的天气预报app(二)增加搜索城市功能

    在activity_main.xml里增加输入框来输入城市,在输入款旁边增加搜索按钮来进行查询。 然后原来显示helloworld的TextView用来显示结果。 增加搜索按钮 使用broadcast的方式把收到的天气信息发送到界面显示。 Android的广播机制是一种用于在应用程序内和应用程序之间传递消息和事件的

    2024年02月14日
    浏览(32)
  • kotlin 编写一个简单的天气预报app (七)使用material design

    对之前的天气预报的app进行了优化,原先的天气预报程序逻辑是这样的。 使用text和button组合了一个输入城市,并请求openweathermap对应数据,并显示的功能。 但是搜索城市的时候,可能会有错误,比如大小写,比如拼写之类的,所以打算给他升级一下。 目标: 在搜索的时候需

    2024年04月27日
    浏览(34)
  • Flutter开发微信小程序实战:构建一个简单的天气预报小程序

    微信小程序是一种快速、高效的开发方式,Flutter则是一款强大的跨平台开发框架。结合二者,可以轻松地开发出功能丰富、用户体验良好的微信小程序。 这里将介绍如何使用Flutter开发一个简单的天气预报小程序,并提供相应的代码示例。 在开始之前,确保你已经安装了Fl

    2024年02月12日
    浏览(40)
  • kotlin 编写一个简单的天气预报app(六)使用recyclerView显示forecast内容

    要使用RecyclerView显示天气预报的内容 先在grandle里添加recyclerView的引用 创建一个RecyclerView控件:在布局文件中,添加一个RecyclerView控件,用于显示天气预报的列表。 这是一个包含三个TextView的LinearLayout布局,用于显示天气相关的数据。每个TextView都有一个唯一的id,可用于在代

    2024年02月13日
    浏览(70)
  • 【C语言】做一个贪吃蛇小游戏,完整代码&附带视频演示

    视频演示: https://www.bilibili.com/video/BV1pt421a7Nu/?spm_id_from=333.999.0.0vd_source=82b65865be0947de29bd55efc8cdb40a 编译环境:linux(Vmware16.2.4 + Ubantu20.04.3); 小蛇🐍只能在固定的范围内活动; 可以利用键盘方向键控制小蛇🐍的前进方向; 活动范围内会随机生成食物; 小蛇🐍吃到食物,身

    2024年02月21日
    浏览(35)
  • 【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)

    需要全部代码请点赞关注收藏后评论区留言私信~~~ 与传统的影视行业相比,诞生于移动互联网时代的短视频是个全新行业,它制作方便又容易传播,一出现就成为大街小巷的时髦潮流。 各行各业的人们均可通过短视频展示自己,短小精悍的视频片段原来能够容纳如此丰富的

    2024年02月03日
    浏览(24)
  • Go实现一个简单的烟花秀效果(附带源码)

    在 Go 语言中,要实现烟花秀效果可以使用 github.com/fogleman/gg 包进行绘图。以下是一个简单的例子: 首先,确保你已经安装了( 有时候需要梯子才可以安装 )  github.com/fogleman/gg 包: 然后,使用以下 Go 代码: 在这个例子中,我们使用 github.com/fogleman/gg 包创建一个图形上下文

    2024年01月23日
    浏览(29)
  • 实现一个简单但有趣的AR效果(Web)

       有人说:一个人从1岁活到80岁很平凡,但如果从80岁倒着活,那么一半以上的人都可能不凡。 生活没有捷径,我们踩过的坑都成为了生活的经验,这些经验越早知道,你要走的弯路就会越少。   本文涉及多个 Codepen 案例,若想获得更佳体验,请到 凹凸实验室博客 阅读,

    2023年04月14日
    浏览(65)
  • Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十一 简单给视频添加水印图片效果

    目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十一 简单给视频添加水印图片效果 一、简单介绍 二、简单给视频添加水印图片效果实现原理 三、简单给视频添加水印图片效果案例实现简单步骤 四、注意事项 Python是一种跨平台的计算机程序设计语

    2024年04月25日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包