(原创)悟空天气------Android源码下载地址,代码结构与解析,附App截图

来源:互联网 发布:马克斯 cms 教程 编辑:程序博客网 时间:2024/04/29 15:59

前言

几个月前前就想把自己做的这款天气类的App写在自己的博客上,由于各种原因(主要是懒)一直耽误下去,前段时间对自己的代码进行更新,版本更新到version2.0觉得不能再拖了,就诞生了这篇博文,希望各位看官碰到本文错误的地方,可以及时与我沟通。

悟空天气简介

源码下载链接:悟空天气GitHub下载地址
version1.0版本源码下载链接:version1.0版本源码下载地址
version2.0版本
悟空天气采用权威数据源授权信息,拥有众多城市的天气预报和实时天气预警信息;更可查看大城市的空气质量情况。

特色功能:

1.简约

2.精确预报6天天气

3.查询空气质量

4.采用Matrial Design风格的侧滑菜单,以及support v7包的控件

5.使用数据库存储城市列表信息,采用内存缓存及文件缓存两种方式存储天气信息。

6.使用自定义view,创建圆形pm2.5的自定义view显示空气状况。
软件截图:
主界面

主界面

菜单

关于

代码结构解析

代码结构

  1. adapter—存放菜单城市列表,城市数据库,Fragment的包。
    重点内容 2. App—存放自定义Appliation。
  2. bean—存放Item,如City,Pm2.5信息,简单天气状况,详细天气状况,及天气预报。
  3. db—-使用SQLiteOpenHelper及SQLiteDatabase类的包。
  4. Fragment—各种用到的Fragment。
  5. fragmentViewPager—-滑动式5天天气预报,较好的操作效果。
  6. indicator—-fragment工具类。
  7. support—–工具类
  8. ui—-下拉刷新包
  9. util—-工具类
  10. weather—–主activity包。

代码主要部分

1.Application类
初始化操作类,如下:

private void initData() {        mApplication = this;        mNetWorkState = NetUtil.getNetworkState(this);        initCityList();        mLocationClient = new LocationClient(this, getLocationClientOption());        initWeatherIconMap();        initWidgetWeather();        mSpUtil = new SharePreferenceUtil(this,                SharePreferenceUtil.CITY_SHAREPRE_FILE);        IntentFilter filter = new IntentFilter(NET_CHANGE_ACTION);        registerReceiver(netChangeReceiver, filter);    }

获取网络状态,初始化城市列表,获取定位信息,初始化天气图标及widget。

2.MainActivity类
这个是核心类,内容包括:加入侧滑菜单,开启线程获取天气状况及pm值,更新天气模块(包括无网络或无响应时如何更新),获取定位位置,更新ui操作,防止滑动冲突
下面是添加侧滑菜单的代码,这里是使用了 mikepenz/MaterialDrawer的具有material风格的侧滑菜单,链接介绍地址。

header = new AccountHeaderBuilder().withActivity(this)                .withCompactStyle(false)                .withHeaderBackground(R.drawable.main_nav_header_bg)                .addProfiles(new ProfileDrawerItem().withIcon(R.drawable.ic_launcher).withEmail(getString(R.string.author_email)).withName(getString(R.string.author_name)))                .build();        // set creator        drawer = new DrawerBuilder().withActivity(this)                .withAccountHeader(header)                .addDrawerItems(new PrimaryDrawerItem().withName("添加城市").withIcon(R.drawable.behind_add_city).withIdentifier(R.drawable.behind_add_city)                )                .build();        drawer.setOnDrawerItemClickListener(this);        addAllMenuItem(databaseHelper.getReadableDatabase());        drawer.addStickyFooterItem(new SectionDrawerItem().withName("悟空天气"));        drawer.addStickyFooterItem(new SectionDrawerItem().withName("设置"));        drawer.addStickyFooterItem(new SectionDrawerItem().withName("关于"));

本应用主要通过4个Message值来更新ui:

private Handler mHandler = new Handler() {        public void handleMessage(android.os.Message msg) {            switch (msg.what) {                case LOACTION_OK:                    String cityName = (String) msg.obj;                    L.i("cityName = " + cityName);                    mCurCity = mCityDB.getCity(cityName);                    L.i(mCurCity.toString());                    mSpUtil.setCity(mCurCity.getCity());                    cityTv.setText(mCurCity.getCity());                    frame.postDelayed(new Runnable() {                        @Override                        public void run() {                            frame.autoRefresh(true);                        }                    }, 100);                    break;                case ON_NEW_INTENT:                    mCurCity = mNewIntentCity;                    mSpUtil.setCity(mCurCity.getCity());                    cityTv.setText(mCurCity.getCity());                    frame.autoRefresh();                    updateWeather(true);                    break;                case UPDATE_EXISTS_CITY:                    String sPCityName = mSpUtil.getCity();                    mCurCity = mCityDB.getCity(sPCityName);                    updateWeather(false);                    break;                case GET_WEATHER_RESULT:                    updateWeatherInfo();                    updatePm2d5Info();                    updateWidgetWeather();                    break;

LOACTION_OK:在刚开始使用Gps定位时,获取定位成功将传LOACTION_OK值进行第一次获取天气操作。
ON_NEW_INTENT:点击添加城市来新增城市天气时,所返回的值操作。
UPDATE_EXISTS_CITY:刷新已有城市返回的值。
GET_WEATHER_RESULT:返回天气信息时所返回的值。

下面代码为获取天气的核心代码:

private void updateWeather(final boolean isRefresh) {        if (NetUtil.getNetworkState(getContext()) == NetUtil.NETWORN_NONE && isRefresh) {            T.showLong(getActivity(), R.string.net_err);            return;        }        if (mCurCity == null) {            T.showLong(mApplication, "未找到此城市,请重新定位或选择...");            return;        }        // T.showShort(this, "正在刷新天气...");        timeTv.setText("同步中...");        // 启动线程获取天气信息        new Thread() {            @Override            public void run() {                super.run();                getWeatherInfo(isRefresh);                getPm2d5Info(isRefresh);                if (mCurWeatherinfo != null)                    L.i(mCurWeatherinfo.toString());                if (mCurPm2d5 != null)                    L.i(mCurPm2d5.toString());                mHandler.sendEmptyMessage(GET_WEATHER_RESULT);            }        }.start();    }

下面 为解析天气的方法:

private void parseWeatherInfo(String url, String result,                                  boolean isRefreshWeather) {        mCurWeatherinfo = null;        mCurWeatherinfo = mApplication.getmCurWeatherinfo();        mApplication.setmCurWeatherinfo(null);        if (!TextUtils.isEmpty(result) && !result.contains("页面没有找到")) {            // L.i(result);            try {                mCurWeatherinfo = JsonForWeather.getCurrentWeather(result);                mPreWeatherinfo = JsonForWeather.getForecastWeather(result);                ((MainActivity) getActivity()).setFragment_weatherinfo(mCurWeatherinfo);            } catch (JSONException e) {                e.printStackTrace();            }        } else {        }        ConfigCache.setUrlCache(result, url);    }

同样解析pm的值的方法:

private void parsePm2d5Info(String url, String result,                                boolean isRefreshPm2d5) {        mCurPm2d5 = null;        System.out.println("---------" + result);        mApplication.setmCurWeatherinfo(null);        if (!TextUtils.isEmpty(result)) {            // L.i(result);            try {                mCurPm2d5 = JSonForPm.getPm2d5Object(result);                ((MainActivity) getActivity()).setFragment_pm(mCurPm2d5);                System.out.println("++++++++" + mCurPm2d5);            } catch (JSONException e) {                e.printStackTrace();            }            // L.i(mCurPm2d5.toString());        } else {            result = "";        }        if (isRefreshPm2d5 && !TextUtils.isEmpty(result))            // save2File(result, PM2D5_INFO_FILENAME);            ConfigCache.setUrlCache(result, url);    }

获取天气方法:

  private void getPm2d5Info(boolean isRefresh) {        String urlPm2d5 = PM2D5_BASE_URL.replace("商丘",                mCurCity.getCity());        String result;        if (!isRefresh) {            if (mApplication.getmCurPm2d5() != null) {// 内存中的信息                mCurPm2d5 = mApplication.getmCurPm2d5();                ((MainActivity) getActivity()).setFragment_pm(mCurPm2d5);                L.i("get the pm2.5 info from memory");                return;            }            result = ConfigCache.getUrlCache(urlPm2d5);            if (!TextUtils.isEmpty(result)) {                parsePm2d5Info(urlPm2d5, result, false);                L.i("get the pm2.5 info from file");                return;            }        }        // L.i("pm2.5 url: " + urlPm2d5);        String pmResult = connServerForResult(urlPm2d5);        if (TextUtils.isEmpty(pmResult) || pmResult.contains("reason")) {// 如果获取失败,则取本地文件中的信息,            String fileResult = getInfoFromFile(PM2D5_INFO_FILENAME);            // 只有当本地文件信息与当前城市相匹配时才使用            if (!TextUtils.isEmpty(fileResult)                    && fileResult.contains(mCurCity.getCity()))                pmResult = fileResult;        }        // pmResult = getInfoFromFile(PM2D5_INFO_FILENAME);        parsePm2d5Info(urlPm2d5, pmResult, true);    }

更新界面操作:

private void updatePm2d5Info() {        if (mCurPm2d5 != null) {            mApplication.setmCurPm2d5(mCurPm2d5);            pmQualityTv.setText(mCurPm2d5.getQuality());            pmDataTv.setText(mCurPm2d5.getPm());            int pm2_5 = Integer.parseInt(mCurPm2d5.getPm());            int pm_img = R.drawable.biz_plugin_weather_0_50;            if (pm2_5 > 300) {                pm_img = R.drawable.biz_plugin_weather_greater_300;            } else if (pm2_5 > 200) {                pm_img = R.drawable.biz_plugin_weather_201_300;            } else if (pm2_5 > 150) {                pm_img = R.drawable.biz_plugin_weather_151_200;            } else if (pm2_5 > 100) {                pm_img = R.drawable.biz_plugin_weather_101_150;            } else if (pm2_5 > 50) {                pm_img = R.drawable.biz_plugin_weather_51_100;            } else {                pm_img = R.drawable.biz_plugin_weather_0_50;            }            pmImg.setImageResource(pm_img);        } else {            pmQualityTv.setText("N/A");            pmDataTv.setText("N/A");            pmImg.setImageResource(R.drawable.biz_plugin_weather_0_50);            T.showLong(mApplication, "未获取到PM2.5数据");        }    }

网络操作:

public static String request(String httpUrl) {        BufferedReader reader = null;        String result = null;        StringBuffer sbf = new StringBuffer();        try {            URL url = new URL(httpUrl);            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();            connection.setRequestMethod("GET");            connection.connect();            InputStream is = connection.getInputStream();            reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));            String strRead = null;            while ((strRead = reader.readLine()) != null) {                sbf.append(strRead);                sbf.append("\r\n");            }            reader.close();            result = sbf.toString();        } catch (Exception e) {            e.printStackTrace();        }        return result;    }

还有一些详细介绍,后续再继续更新。

后言

本文还有对代码其余部分未作介绍,后面时间会陆续写出来,这款App也会一直更新,
我的GitHub地址

我的博客地址

3 0