基于Android开发的天气预报app(源码下载)_android天气预报app源码-程序员宅基地

技术标签: 完整项目  毕业设计  毕设  android  天气预报  源码  

基于AndroidStudio环境开发的天气app

由于需要源码的人特别多,我特地花时间新增了对最新IDE版本Android Studio Chipmunk | 2021.2.1 Patch 1的支持,并开源了源码,需要的自取。

  • 源码地址:https://github.com/LuoPeiQin/DongWeather
  • 发现很多人有了源码地址,还是在下面留言要源码,应该是新手不会下载和打开GitHub的源码,所以特地写了一篇下载并打开源码教程的文章,帮助大家下载源码并打开和运行
  • 如果觉得对你有帮助,麻烦帮忙点个赞,谢谢!

主要实现了:
1、定位城市天气显示;
2、城市编辑功能(增、删、改、查)以及对应天气显示信息的改变;
3、天气信息的Widget窗口显示(城市的编辑功能可以远程的更新Widget窗口信息的显示)
4、下拉刷新、天气显示界面左右滑动、城市拖拽等小模块

一、 开发需求分析

1、开发环境搭建 - AndroidStudio

安装步骤:
(1)下载。建议在官网下载,因为国内很多映射文件多少都是有点年代的,还是下载最新的比较好,也免去更新的麻烦。不过国内由于网络限制,上Android官网需要翻墙。AndroidStudio下载地址:https://developer.android.google.cn/studio/index.html里面是最新版本的AndroidStudio。
(2)安装,下载完成之后没有特别要求的话默认选择一直next就好了,一般的话只需要改下安装路径,避免C盘空间不够。因为AndroidStudio自带了JDK和Android SDK,所以Android完成后就可以直接进行开发了。

2、城市信息获取的api

城市信息这里我直接使用的是Android前辈搭建的一个服务器获取的,数据链接是http://guolin.tech/api/china,访问返回的是JSON数据类型的省份信息(JSON数据类型的解析后面会再详细说明),需要返回城市时只需要在本链接后加上“/对应省份id”即可获取到相应的城市信息,县市信息也是一样的,原链接加上“/对应省份id/对应城市id”即可。
这里其实也可以从其它天气服务商提供的api接口获取城市信息。

3、天气信息获取的api

天气信息的获取我使用的是和风天气提供的免费的api,和风天气每天有提供4000次免费的基础天气查询,用来做开发测试是足够用的了。而且和风天气api接口返回的JSON数据类型也比较简单,作为Android初学者做项目是比较好的。想使用该接口只需要简单注册一个账号就可以了(对返回数据的处理我后面再详细说明)。老手的话可以在网上搜索别的服务商提供的免费接口,现在网上的免费接口少了很多,不过有还是有的。

4、定位信息获取的api

我这里使用的是百度提供的免费api接口http://lbsyun.baidu.com/apiconsole/key,因为Android原生定位API在国产手机中一般被阉割了,或者国内网络限制的原因,使用Android原生定位API一般是很难获取到定位信息的,跟手机厂商和网络环境都有关系。所以这边为了避免这种情况的不确定因素,我选择了使用百度提供的免费地位接口,在国内,百度和高德定位服务做得都还是不错的。使用百度定位api接口同样需要注册一个百度开发者账号,因为这不是本篇文章的重点。这边具体的操作就不再说明了。

二、 系统设计分析

1、天气信息界面显示设计

首先先上效果图:
天气主界面图

接下来我介绍一下天气显示信息中用到的一些设计:
首先是功能实现上的:
1)首先背景图片是每天会更新的,是从必应网上获取到的背景图片。
2)下拉刷新功能。
3)天气显示信息左右活动切换已选择要显示的城市。
4)通过点击右上角的编辑按钮进入城市管理功能。
5)导航组件功能。
6)小时天气小时超出屏幕宽度时的当前页面左右滑动。

其次是具体显示上的(分为一个城市的天气信息一个页面,每个页面又有七个模块)我们从上往下分析:
1)最上部分是城市名的显示和编辑按钮。
2)然后是导航原点显示。
3)其次是当前温度,当天天气和当天最低最高温的显示。(1)(2)部分都是用户比较关心的问题,所以我们放在最前面。
4)接下来是将来的小时预告,由于和风天气返回的数据只有当天每三小时的天气预告,所以这边的显示实现得比较差,不过我这里做的是兼容可以扩展的,不管数据多少都可以显示。如果将来需要更改数据源,这里的操作将非常简单 。
5)接着显示的是接下来几天的天气的大体介绍,这里显示的数据同样受限于获取到的数据。
6)再接着是一些生活指数的显示,由于我艺术细胞不太好,所以这里的图片显示有点丑。。你们可以根据自己的喜好去更改图片。
7)最后就是一些生活建议的显示了。

2、已选择城市信息界面显示设计

先上图吧
城市编辑显示1
城市编辑显示2

这里主要是有点击编辑前后的区别

下面我们来一一说明:
点击编辑前
布局主要分成三个部分:
1、最上方的:
*左侧返回按钮,回到天气显示界面
*中间固定的“城市管理”四个字
*右侧的编辑按钮,点击之后就可以对城市进行增、删、和更改位置了
2、中间部分:
*中间部分是已选择城市信息的显示
3、最下方部分:
*最下面是一个添加城市的按钮,点击之后进入城市添加功能

点击编辑后
1、最上方的:
*左侧取消按钮,即放弃本次编辑后的结果,回到非编辑界面
*中间固定的“城市管理”四个字
*右侧的保存按钮,即保存本次编辑的结果并回到非编辑界面
2、中间部分:
*中间部分是已选择城市信息的显示,与编辑前不同的是增加了左侧拖动改变顺序的按钮和右侧的删除城市按钮
3、最下方部分:
*最下面是一个添加城市的按钮,点击之后进入城市添加功能

所用到的功能点
1、dragListView:可拖拽的listview
2、Android自带数据库
3、重叠按钮的实现
以上功能模块下面我都会一一说明

3、添加城市信息界面显示设计

先上图:
添加城市显示图1
添加城市显示图2

说明
这里的实现比较简单,就是使用ListView去显示省、市、县三个级别的城市,根据选择的城市去网络或者本地加载数据,然后显示。

4、Widget设计

同样先上图
widget显示设计

说明
这里的实现显示上比较简单,但是功能逻辑和实现上相对复杂。

显示上的设计
1、背景图片:widget的背景图片同样是网络上下载并且每天会自动更换的,不同的是为了保证用户滑动界面时的流畅性,这里做了图片缩放处理之后再显示。
2、中间固定文字“当前天气”
3、下面是一个ListView用来显示简略的已选择城市的信息

功能上的设计
1、服务listView改变的server进程
2、contentProvider提供跨进程间的数据通信
3、图片下载的异步线程和图片缩放实现
4、异步线程与UI线程通过handler实现通信

5、界面转换设计

有界面转换实现的:
1、点开app进入到城市天气信息显示界面
2、点击编辑按钮进入到城市管理界面
3、城市管理界面中点击添加按钮进入到城市添加界面
4、城市管理界面中点击返回按钮回到城市天气信息显示界面
5、添加城市界面中添加完成或者点击返回按钮回到城市天气信息显示界面

6、系统总体和局部流程设计(流程图)

这里写图片描述

由于时间原因,这边就先绘制一个流程图了,别的流程图等后面有时间了再绘制

三、 系统功能模块实现(代码部分)

前面介绍了那么多,现在终于到了重点了,前面讲述的功能我在这里都将为大家一一说明。
首先给大家看一下工程目录的截图:
工程目录图

项目总体流程思路

接下来我根据项目的实现过程来给大家介绍整个项目的总体流程

1、天气app最重要的是获取城市列表和天气信息,所以首先要解决的问题是在网络上找到合适的api接口,并根据服务商提供的数据转换成自己需要显示的数据。
2、有了需要的显示信息之后,我们需要自己去设计怎么显示,怎么让用户去有一个好的体验。我的设计是在使用三个Activity去和用户交互,参照我的项目截图,其中WeatherActivity作为启动活动,用于显示天气信息,提供的是多页带导航栏可左右滑动的效果。ChooseAreaActivity是管理城市的活动,用于添加、删除、改变要显示天气信息的城市列表。AddCountyActivity是用于添加城市的活动。
3、实现了这些基本的城市管理和天气显示之后,接下来就是进阶功能了,首先我们实现百度定位功能,根据定位结果加载当前城市天气。
4、实现widget功能。

这个项目总体的思路就是这样的,接下来我们一步一步的去说明

#城市和天气信息获取模块

1、获取城市信息

数据链接http://guolin.tech/api/china,访问返回的是JSON数据类型的省份信息,需要返回城市时只需要在本链接后加上“/对应省份id”即可获取到相应的城市信息,县市信息也是一样的,原链接加上“/对应省份id/对应城市id”即可。
大家点击网址可以得到这样的响应:
这里写图片描述
这里得到的是一个JSON数据,以下是对它的解析代码:

JSONArray jsonArray = new JSONArray(response);
                for (int i = 0; i < jsonArray.length(); ++i) {
    
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    Province province = new Province();
                    province.setProvinceCode(jsonObject.getInt("id"));
                    province.setProvinceName(jsonObject.getString("name"));
                    province.save();
                }
        这里的后几行代码是我使用LItepal存储数据到数据库的操作,response变量就是访问网址得到的原JSON数据。
        网上关于JSON的解析方法很多,这边不再说得过多。
        这边还需要说明的是怎么去网上获取JSON数据。
        首先要说明的是网络操作是不能在UI线程里进行的,否则会程序崩溃。所以这里必须用的异步线程去处理网络加载的问题,并且在加载线程事使用一个进度条来给予用户交互。
        以下是网络加载的代码:
        ```java
        public static void sendRequestOkHttpForGet(final String adress,final MyCallBack myCallBack) {
    
        new Thread(new Runnable() {
    
            @Override
            public void run() {
    
                HttpURLConnection connection = null;
                try {
    
                    URL url = new URL(adress);
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    InputStream in = connection.getInputStream();
                    String response = convertStreamToString(in);
                    //回调接口函数,让主线程处理
                    //成功
                    myCallBack.onResponse(response);
                } catch (MalformedURLException e) {
    
                    e.printStackTrace();
                    //失败
                    myCallBack.onFailure(e);
                } catch (ProtocolException e) {
    
                    e.printStackTrace();
                    myCallBack.onFailure(e);
                } catch (IOException e) {
    
                    e.printStackTrace();
                    myCallBack.onFailure(e);
                } finally {
    
                    if (null != connection) {
    
                        connection.disconnect();
                    }
                }
            }
        }).start();
   其中第一个参数是要访问的网络的地址,第二个参数是一个回调接口。
        public interface MyCallBack {
    

        void onFailure(IOException e);

        void onResponse(String response) throws IOException;
}

	第一个参数没有什么好说的(就是我们刚刚使用的 ),第二个参数是异步线程经常会用到的一个和主线程交互的手段。在调用函数时传入一个回调接口的指针,当异步线程完成相应的耗时操作之后,再使用该指针调用回调函数即可实现异步线程与主线程的交互了。
	城市列表的信息的获取到这里就算结束了。

2、获取天气信息

获取天气信息的网络操作是和获取城市信息的操作是一样的,使用上面那个网络异步函数即可,如果觉得不好,也可以使用网络开源项目包装的网络访问接口,比如说OKHttp。不同的是天气信息的JSON数据要比城市信息的JSON数据复杂得多。
这里提供连接给大家感受一下深圳天气
这里写图片描述
这里是用Chrome的JSON-handle解析之后的结果。可以看到还是比较复杂的。所以这里我们采用GSON方式来解析JSON,方便我们后面对数据的操作。
GSON方式是把JSON数据解析成相应的对象的一种方式,主要步骤如下:
1、根据JSON数据建立不同的类,JSON数据的每一个结点对应一个类,并且根据不同的结点的复杂程度选择是否还要使用内部类。
2、@SerializedName(“JSON中的结点名”)需要转换成的节点名;
使用关键字把一些JSON数据中意义晦涩的名词转换成类中名字可以见名知意的属性。
3、JSON数据转换成对象实例

JSONObject jsonObject = new JSONObject(response);
                JSONArray jsonArray = jsonObject.getJSONArray("HeWeather5");
                String weateherContent = jsonArray.getJSONObject(0).toString();
                return new Gson().fromJson(weateherContent, 类名.class);

最后,我们把得到的对象的数据对应的添加到要显示的活动的布局当中就可以了。

#城市和天气信息显示模块

3、天气信息的显示

这里相对麻烦一点,因为天气信息的显示中我们做了比较多的功能

获取背景图片和图片的更新

这里我使用的是必应主页提供的背景图片作为天气信息显示的背景图片http://guolin.tech/api/bing_pic这个链接是获取必应每日背景图片下载链接的,可以通过该链接获取图片下载地址,然后再去下载。
由于下载图片是耗时的网络操作,所以我们这里需要使用一个异步线程去下载图片,然后在下载好之后再通知UI线程去加载。
具体代码:

		public void updateBingPic() {
    
        String requestBingPic = "http://guolin.tech/api/bing_pic";
        OkHttp.sendRequestOkHttpForGet(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(WeatherActivity.this).edit();
                editor.putString("bing_pic", bingPic);
                editor.apply();
            }
        });
    }

这个是获取图片下载地址的代码,变量bingPic的内容就是下载链接
if (bingPic != null) {
Glide.with(WeatherActivity.this).load(bingPic).into(bingPicIv);
}
当它不为空时,我们使用Glide去下载并加载图片到天气显示背景。Glide 是 Google 员工的开源项目, Google I/O 上被推荐使用Glide具有获取、解码和展示视频剧照、图片、动画等功能,它还有灵活的API,这些API使开发者能够将Glide应用在几乎任何网络协议栈里。创建Glide的主要目的有两个,一个是实现平滑的图片列表滚动效果,另一个是支持远程图片的获取、大小调整和展示。

天气显示信息左右活动切换已选择要显示的城市(ViewPager)

ViewPager是android扩展包v4包中的类,主要功能是实现view页面的左右切换。在本项目中,就是一个view包含一个城市的天气信息,然后view又加入到ViewPager中。
这里说一下ViewPager的使用步骤,ViewPager的实现与ListView有很多相似之处,主要步骤如下:
1、创建或设置数据源。
2、根据数据源创建或配置好相应的适配器。
3、在布局文件中加入ViewPager控件,并在程序给控件设置步骤2中的适配器。
4、给控件添加监听器。
PS:其实Android中很多包含多View的控件都是通过以上步骤实现的,很相似,只要我们认真的掌握了其中的一种,那么别的也就很容易去上手了。

下拉刷新功能

本项目中的下拉刷新功能是使用SwipeRefreshLayout控件实现的,实现的步骤很简单:
1、在布局文件中实现下拉刷新功能的地方添加android.support.v4.widget.SwipeRefreshLayout控件,这里推荐使用v4包,因为能够支持低版本的Android手机。
2、在程序中定义并设置相应属性(样式等等)和监听器。
3、设置事件的相应响应和启动下拉刷新和结束下拉刷新。

通过点击右上角的编辑按钮进入城市管理功能

这里的实现就很基础了,简单讲一下步骤:
1、在布局文件定义按钮
2、在程序中找到按钮并设置监听器
3、在响应事件中做进入城市功能活动的逻辑

导航组件功能

本项目的导航栏功能是用Selector实现,Selector主要是用来改变各种view控件的默认背景的。实现步骤如下:
1、xml文件定义
?xml version=“1.0” encoding=“utf-8” ?>
selector xmlns:android=“http://schemas.android.com/apk/res/android”>
!-- 默认时的背景图片–>
item android:drawable=“@drawable/pic1” />
!-- 没有焦点时的背景图片 -->
item android:state_window_focused=“false”
android:drawable=“@drawable/pic1” />
!-- 非触摸模式下获得焦点并单击时的背景图片 -->
item android:state_focused=“true” android:state_pressed=“true” android:drawable= “@drawable/pic2” />
!-- 触摸模式下单击时的背景图片–>
item android:state_focused=“false” android:state_pressed=“true” android:drawable=“@drawable/pic3” />
!–选中时的图片背景–>
item android:state_selected=“true” android:drawable=“@drawable/pic4” />
!–获得焦点时的图片背景–>
item android:state_focused=“true” android:drawable=“@drawable/pic5” />
/selector>

2、使用
LinearLayout layout = (LinearLayout)findViewById(R.id.vp_guide_layout);
LinearLayout.LayoutParams mParams = new LinearLayout.LayoutParams(20, 20);
mParams.setMargins(0, 0, 0, 0);//设置小圆点左右之间的间隔

    guideShapeViewArrayList.clear();
    layout.removeAllViews();
    ImageView imageView = new ImageView(this);
    imageView.setLayoutParams(mParams);
    imageView.setImageResource(R.drawable.guide_shape_select);

小时天气小时超出屏幕宽度时的当前页面左右滑动(RecycleListView)

RecycleListView是Android官方出品的一个可以代替甚至超越ListView的东西。RecycleListView的实现比不优化的ListView麻烦一些,但是功能上比ListView要更强大,因为他的显示不仅可以竖屏,还可以横屏。
实现步骤:
1、准备数据源
2、根据数据源设置适配器
static class ViewHolder extends RecyclerView.ViewHolder {
TextView hourlyTimeTV;
ImageView hourlyWeatherImageV;
TextView hourlyTemperatureTV;

    public ViewHolder(View view){
        super(view);
        hourlyTimeTV = (TextView) view.findViewById(R.id.hourly_time_tv);
        hourlyWeatherImageV = (ImageView) view.findViewById(R.id.hourly_weather_iv);
        hourlyTemperatureTV = (TextView) view.findViewById(R.id.hourly_temperature_tv);
    }
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.hourly_forecast_item, parent, false);
    ViewHolder holder = new ViewHolder(view);
    return holder;
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    HourlyWeather hourlyWeather = hourlyWeatherList.get(position);
    holder.hourlyTimeTV.setText(hourlyWeather.hourlyTime + "时");
    holder.hourlyWeatherImageV.setImageBitmap(hourlyWeather.hourlyImageBit);
    holder.hourlyTemperatureTV.setText(hourlyWeather.hourlyTemperature + "º");
}

@Override
public int getItemCount() {
    return hourlyWeatherList.size();
}

要实现RecyclerView.Adapter主要是要实现三个函数
onCreateViewHolder()
onBindViewHolder()
getItemCount()

3、在布局文件定义RecycleView控件,并在代码中为控件设置以上适配器。
4、选择是否要设置监听器。

有没有发现和ListView,ViewPager的实现步骤很相似呢。

布局圆角功能

布局圆角主要是为了让布局中的控件看起来美观一些。
实现很简单
1、在drawable中定义xml文件

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#8000" />
    <corners
        <android:topLeftRadius="10dp"
        <android:topRightRadius="10dp"
        <android:bottomRightRadius="10dp"
        <android:bottomLeftRadius="10dp"/>
</shape>

2、在需要引入圆角的布局文件中引入本配置作为背景

android:background="@drawable/corners_bg"

4、城市信息的显示

这里相对麻烦一点,因为城市信息的显示中我们做了比较多的功能,下面线总体介绍项目使用到的功能模块,然后再一一说明:
1、活动切换按钮,这里就不再重复说明了。
2、添加城市。
3、可拖拽的ListView(DragListView)的城市信息实现
本模块我们主要讲解DragListview的实现:
这里写图片描述
这里实现的主要功能有:删除城市、城市排序切换。
实现步骤:
1、准备数据源
2、设置适配器

public class CountiesAdapter extends BaseAdapter {
    
        private Context context;
        //适配器的数据源 selectedCityList
        private List<SelectedCounty> items;

        public CountiesAdapter(Context context,List<SelectedCounty> selectedCityList){
    
            this.context = context;
            this.items = selectedCityList;
            LogUtil.d(TAG, "CountiesAdapter: selectedCityList size:" + selectedCityList.size());
            LogUtil.d(TAG, "CountiesAdapter: selectedCityList items size:" + items.size());
        }

        @Override
        public int getCount() {
    
            return items.size();
        }

        @Override
        public Object getItem(int arg0) {
    
            return items.get(arg0);
        }

        @Override
        public long getItemId(int arg0) {
    
            return arg0;
        }

        public void remove(int arg0) {
    //删除指定位置的item
            items.remove(arg0);
            this.notifyDataSetChanged();//不要忘记更改适配器对象的数据源
        }

        public void insert(SelectedCounty item, int arg0) {
    
            items.add(arg0, item);
            this.notifyDataSetChanged();
        }

        public void change(List<SelectedCounty> selectedCityList) {
    
            items = selectedCityList;
            this.notifyDataSetChanged();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
    
            SelectedCounty item = (SelectedCounty)getItem(position);
            ViewHolder viewHolder;
            if(null == convertView){
    
                viewHolder = new ViewHolder();
                convertView = LayoutInflater.from(context).inflate(R.layout.drag_listview_item, null);
                viewHolder.dragMoveIv = (ImageView) convertView.findViewById(R.id.drag_move_iv);
                viewHolder.dragCountyNameTv = (TextView) convertView.findViewById(R.id.drag_county_name_tv);
                viewHolder.drag_click_remove = (ImageView) convertView.findViewById(R.id.drag_click_remove);
                moveImageViewList.add(viewHolder.dragMoveIv);
                deleteImageViewList.add(viewHolder.drag_click_remove);
                convertView.setTag(viewHolder);
            }else{
    
                viewHolder = (ViewHolder) convertView.getTag();
            }
            //是否点击了edit按钮,
            if (isEditClick) {
    
                if (!WeatherActivity.isLocationCountyRemove && null != WeatherActivity.locationCountyWeatherId && 0 == position ) {
    
                    viewHolder.drag_click_remove.setVisibility(View.GONE);
                } else {
    
                    viewHolder.dragMoveIv.setVisibility(View.VISIBLE);
                    viewHolder.drag_click_remove.setVisibility(View.VISIBLE);
                }
            }else {
    
                viewHolder.dragMoveIv.setVisibility(View.GONE);
                viewHolder.drag_click_remove.setVisibility(View.GONE);
            }
            viewHolder.dragCountyNameTv.setText(item.getCountyName());
            return convertView;
        }

        class ViewHolder {
    
            ImageView dragMoveIv;
            TextView dragCountyNameTv;
            ImageView drag_click_remove;
        }
    }

别的地方和ListView是一样的,不同的是多了一个remove和insert函数

public void remove(int arg0) {
    //删除指定位置的item
            items.remove(arg0);
            this.notifyDataSetChanged();//不要忘记更改适配器对象的数据源
        }

        public void insert(SelectedCounty item, int arg0) {
    
            items.add(arg0, item);
            this.notifyDataSetChanged();
        }

3、控件绑定适配器
这里也有区别:首先要定义两个函数:

//监听器在手机拖动停下的时候触发
    private DragSortListView.DropListener onDrop =
            new DragSortListView.DropListener() {
    
                @Override
                public void drop(int from, int to) {
    //from to 分别表示 被拖动控件原位置 和目标位置
                    //如果定位城市存在,则去除定位城市的操作
                    if (!WeatherActivity.isLocationCountyRemove && null != WeatherActivity.locationCountyWeatherId) {
    
                        if (0 == from || 0 == to) {
    
                            return;
                        }
                    }
                    if (from != to) {
    
                        SelectedCounty item = (SelectedCounty)countiesAdapter.getItem(from);//得到listview的适配器
                        countiesAdapter.remove(from);//在适配器中”原位置“的数据。
                        countiesAdapter.insert(item, to);//在目标位置中插入被拖动的控件。
                        isSwapCounty = true;
                    }
                }
            };
    //删除监听器,点击左边差号就触发。删除item操作。
    private DragSortListView.RemoveListener onRemove =
            new DragSortListView.RemoveListener() {
    
                @Override
                public void remove(int which) {
    
                    delCountyId.add(selectedCityList.get(which).getId());
                    delCountyIndex.add(which);
                    countiesAdapter.remove(which);
                    Log.d(TAG, "onClick: remove position:" + which);
                }
            };

然后绑定适配器时这两个函数也一起绑定

//水平滑动显示
        hourlyRecycler = (RecyclerView) currentView.findViewById(R.id.hourly_recycler);
        layoutManager = new LinearLayoutManager(currentView.getContext());
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        hourlyRecycler.setLayoutManager(layoutManager);
        hourlyWeatherAdapter = new HourlyWeatherAdapter(hourlyWeatherList);
        hourlyRecycler.setAdapter(hourlyWeatherAdapter);

有问题或要 者建议的可以在评论留言,需要源码的也可以留言,我看到了都会及时回复的。
未完待续。。。。。。


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/for_My_Future/article/details/72752626

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签