毕业设计项目:基于 Android 的天气 APP | 您所在的位置:网站首页 › 国际天气预报app › 毕业设计项目:基于 Android 的天气 APP |
前言
项目地址:https://download.csdn.net... 多知天气,主要是给大家学习一下。有些东西也是借鉴别人的主要借鉴的是别人的UI。 感谢开源看别人的代码慢慢学习,你会看到自己的成长的~ 现在的我看这个毕业设计项目会觉得没有当初想的那么难了,可以用更高的效率,更好的方式去实现这个项目。 借鉴过的项目就看天气 高仿雅虎天气 还有郭神的第二行代码,不解释 开源框架Butterknife注解式框架 jakewharton.github.io/butterknife… Glide图片加载框架 github.com/bumptech/gl… Okhttp网络请求框架 square.github.io/okhttp/ LitePal数据库操作框架 github.com/LitePalFram… Logger 开发日志框架 github.com/orhanobut/l… Gson json数据解析框架 github.com/google/gson SlidingMenu侧拉菜单框架 github.com/jfeinstein1… SwipeMenuListView侧滑删除框架 github.com/baoyongzhan… 易源数据提供的天气数据 www.showapi.com/ 极光推送服务 www.jiguang.cn/accounts/pl… 有米广告平台 www.youmi.net/ 高德地图 lbs.amap.com/ 功能第一次打开APP引导页,缓冲加载 天气信息的显示 广告,推送 桌面小工具 新闻资讯的查看 蓝牙串口传输温度 准备易源数据中的天气Json如果请求的是15天的Json数据那有近千行,所以取自己有用的。 开发环境:Android studio 数据获取:易源数据SDK 帮助工具Json在线解析 易源数据官网 Json数据分析![]() image 这么多Json,细思极恐啊~ 不过我们一步步来分析,key的作用可以看易源的文档。 cityInfo 城市信息 time 时间 now 现在的天气 f1~f6 近一星期的天气预报信息 alarmList 预警信息 hourDataList 半小时更新一次的天气信息 aqi 空气质量 天气封装在目录下新建com.weather.entity 其实觉得Gson挺好用的…… 那我为何不用Gson呢。。。因为那时候还不会用@Serializedname,易源数据的json竟然还有用数字开头的key ┭┮﹏┭┮ 然后经过了一番的倒腾,终于一个个把数据给对上了= =,当做自己解析json数据的练手吧 网络请求主要是用okhttp,用到的是郭神的几行代码 public static void sendOkHttpRequest(String address, okhttp3.Callback callback) { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(address).build(); client.newCall(request).enqueue(callback); }直接传入地址就请求到数据了, 不过这边有个坑!! 有个坑!!! 有个坑!!! 重要的事情所三遍 在请求后不能直接使用response.body().string(),要缓存一下才能使用,不然为空。 //使用okhttp的封装进行请求 HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() { @Override public void onResponse(Call call, Response response) throws IOException { //这里有坑 String responseText = response.body().string(); 数据库数据库我设计的十分简单,只有两个重要的属性,就是城市名和json数据,为的是在无网络状态下从数据库直接获取到json数据,解析后显示到界面上。 框架的话本来打算用GreenDao的,不过后面改成LitePal了。 public class WeatherDB extends DataSupport { public int id; public String mCityName; public String mJsonData; ... 广告,推送广告用的是有米广告,直接对着SDK把代码加进去就好了,想用腾讯的广告,但是打电话给我问我有没营业执照。。。。晕,没有所以没有审核通过。 推送使用的是极光推送,也是直接使用SDK,本来使用的是BOMB的,但是Bomb SDK中的okhttp和我自己的依赖起冲突了,而且还有一些机子无法推送成功,所以最后改成了极光推送,这都是血淋淋的坑啊,一步步踩过来简直吐血。 //广告条初始化 View bannerView = BannerManager.getInstance(WeatherActivity.this) .getBannerView(WeatherActivity.this, new BannerViewListener() { @Override public void onRequestSuccess() {} @Override public void onSwitchBanner() {} @Override public void onRequestFailed() {} }); // 获取要嵌入广告条的布局 LinearLayout bannerLayout = (LinearLayout) findViewById(R.id.ll_banner); // 将广告条加入到布局中 bannerLayout.addView(bannerView);嵌入广告就是这么简单暴力,但是建议用积分墙,我这个是广告条。。。。。 因为。。。 他们广告条好像没啥广告。。。可能在实际中显示不出来,不过在初始化时使用测试广告的话那就可以看到了。 城市选择这里推荐别人写的一个依赖,直接传送门 CityPicker 用的是高德地图定位 ![]() image 桌面小工具这方面我需要学习的东西还有很多的,开启服务在后台更新,想想后期如果能加入Rxjava,看看能不能优化一些操作,不过在使用Glide加载图片到AppWidget时需要获取到ImageView控件,所以有折腾了一下。 ![]() image //通过APPWIdgetTarget获取到Image控件 mAppWidgetTarget =new AppWidgetTarget(getApplicationContext(),mRemoteViews,R.id.appwiget_picture,mAppwidgetId); Glide.with(getApplicationContext()).load(weatherBean.getmNowWeatherBean().getmWeather_Pic()).asBitmap().into(mAppWidgetTarget); 蓝牙和单片机通信模块因为本人学过嵌入式开发,在机缘巧合的时候接触了Android,所以现在做Android开发,单片机上使用的是DS18B20温度传感器,蓝牙是HC-05,通过串口进行温度传输,不要觉得很难,其实很简单,嗯,说笑的,基础好就很简单啦,代码并不多,曾经试过一次返回数据一直都是乱码,找了一个星期的问题都没找到,最后发现是波特率的问题,太感动了,传送门 界面进入APP加载界面,淡入淡出效果,弱引用持有Activity对象,文字动画效果 ![]() 缓冲界面 //activity切换的淡入淡出效果 overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); //弱引用的使用 private static class SwitchHandler extends Handler { private WeakReference mWeakReference; SwitchHandler(SplashActivity activity) { mWeakReference = new WeakReference(activity); } @Override public void handleMessage(Message msg) { SplashActivity activity = mWeakReference.get(); if (activity != null) { WeatherActivity.launch(activity); activity.finish(); } } } 主界面![]() image 这边其实没有按照Material design的要求透明化状态栏,主界面填充整个手机屏幕,通过计算手机屏幕总高度,减去状态栏的高度和ActionBar的高度,得出了主界面视图的高度,就做到了在任何分辨率下都只显示这样的界面的效果(原谅我这种拗口的表达,你懂就好哈哈哈哈~~) /** * 获取手机屏幕高度 * * @param context * @return */ public static int getDisplayHeight(Context context) { WindowManager wm = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); // 获取屏幕信息 wm.getDefaultDisplay().getMetrics(dm); return dm.heightPixels; } /** * 获取手机屏幕宽度 * * @param context * @return */ public static int getDisplayWidth(Context context) { WindowManager wm = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); // 获取屏幕信息 wm.getDefaultDisplay().getMetrics(dm); return dm.widthPixels; } /** * 反射方法获取状态栏高度 * * @param context * @return */ public static int getStatusBarHeight(Context context) { int statusBarHeight = 20; try { Class _class = Class.forName("com.android.internal.R$dimen"); Object object = _class.newInstance(); Field field = _class.getField("status_bar_height"); int restult = Integer.parseInt(field.get(object).toString()); statusBarHeight = context.getResources().getDimensionPixelSize( restult); } catch (Exception e) { e.printStackTrace(); } // Toast.makeText(getActivity(), "StatusBarHeight = " + statusBarHeight, // Toast.LENGTH_SHORT).show(); return statusBarHeight; } /** * 获取?attr/actionBarSize高度 * * @param context * @return */ public static int getActionBarSize(Context context) { TypedValue typedValue = new TypedValue(); context.getTheme().resolveAttribute(R.attr.actionBarSize, typedValue, true); int actionBarHeight = TypedValue.complexToDimensionPixelSize(typedValue.data, context.getResources().getDisplayMetrics()); return actionBarHeight; } // mNowWeatherHeight高度=屏幕高度-标题栏高度-状态栏高度 mNowWeatherHeight = SystemUtils.getDisplayHeight(mContext) - SystemUtils.getActionBarSize(mContext) - SystemUtils.getStatusBarHeight(mContext); 每半小时更新的数据list和未来天气预报这边是RecyclerView,在绘制每个Item的时候也是计算了屏幕的宽度,每个item占屏幕的1/5,所以在所有分辨率下都只呈现五个Item ![]() image 空气指数和生活指数UI 很多都是从Android Studio中的Vetor assert里面找的,大家也可以去找找适合自己的UI,还有阿里的iconfont阿里巴巴矢量图标库 ![]() image 城市编辑界面背景Activity半透明,填充屏幕,listview侧滑删除 进入Activity后从数据库中获取到数据,然后显示到listview中,进行操作后再主界面的onActivityResult中重新获取数据库中的内容,更新UI. ![]() image //侧滑删除 SwipeMenuCreator creator = new SwipeMenuCreator() { @Override public void create(SwipeMenu menu) { SwipeMenuItem openItem = new SwipeMenuItem( getApplicationContext()); SwipeMenuItem deleteItem = new SwipeMenuItem( getApplicationContext()); deleteItem.setBackground(new ColorDrawable(Color.rgb(0xF9, 0x3F, 0x25))); deleteItem.setWidth(dp2px(60)); deleteItem.setIcon(R.drawable.ic_delete); menu.addMenuItem(deleteItem); } }; mCityEditListview.setMenuCreator(creator); mCityEditListview.setOnMenuItemClickListener(new SwipeMenuListView.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(int position, SwipeMenu menu, int index) { switch (index) { case 0: // open Toast.makeText(getApplicationContext(), position + " menu click", Toast.LENGTH_SHORT).show(); if(mCityList.size()>1){ CityRmoveThread cityRmoveThread = new CityRmoveThread(mCityList.get(position).getmCityName()); cityRmoveThread.start(); mCityList.remove(position); mCityEditListAdapter.notifyDataSetChanged(); }else{ Toast.makeText(getApplicationContext(), position + " 亲,删除了你看啥?", Toast.LENGTH_SHORT).show(); } break; } // false : 会关闭菜单; true :不会关闭菜单 return false; } }); 新闻,笑话,美图这个模块写的说实话我自己都看不下去了,那时候为了赶进度,,哎,意思一下。用的sharepreference进行很简单的存储。嗯,就是这样的 总结仅供参考,不得用于商业项目,如果觉得对你有帮助,给个Star吧亲~ 在写项目的时候写了好多细节,都忘了很多了,还是很用心去处理一些问题的~ 还有引导页设计的不是很好,是直接扣网络上的图片,到第三个界面的时候点击一下就可以进去了~ 谢谢观看 |
CopyRight 2018-2019 实验室设备网 版权所有 |