APP开发流程实例讲解-儒释道网络电台八天开发全程-在Android Studio中完成界面设计
2016-07-05 22:36
781 查看
APP开发流程实例讲解-儒释道网络电台八天开发全程
项目发起
功能和界面初步设定
在Android Studio中完成界面设计
实现功能代码:播放控制
优化排错:增强稳定性和添加异常处理
界面美化并进一步优化排错
百度云深度兼容测试并进一步优化排错
签名发布
昨天的做的设计图是比较简单的,主要麻烦是需要实现两侧的滑动抽屉菜单。
在Android Studio中有一个模板可以创建左侧抽屉,但儒释道网络电台APP需要两边两个抽屉。在网上找到一篇文章《AndroidDrawerLayout+fragment布局实现左右侧滑 》,是使用FragmentTransaction来实现左右侧栏的显现。还有一种办法是使用第三方组件SlidingMenu。难道就不能用Android Studio模板可以创建两侧抽屉滑动菜单吗?经过我一个多小时的探索和尝试,最终发现是可以的。创建的方法我已经写到另一篇文章《Android
DrawerLayout+NavigationView布局实现左右两边侧滑菜单 》,这里不再多说。今天主要的完成的工作有。
nav_header_main.xml文件
nav_server_header_main.xml
ListView列表项Layout就不贴了。
初步完成网络访问API类
网络访问使用了OKHTTP组件,并且是异步访问。OKHttp的使用这里就不多说了。功能实现方法是使用OKHttp下载网页,用正则表达式解析网页,抓取数据生成对象。调用完成事件将数据传回。然后再在UI线程中使用数据填充ListView等。
API类如下
在UI线程中调用的代码如下
总的来说写代码用的时间比较少,界面设计不熟悉用时较多。原计划每天花2个小时来做这个APP,但今天实际花有4个多小时。界面代码那里花时间过多了,写JAVA代码反而比较快。
明天按计划,写播放器控制的代码。
所有代码已经上传到GIT:https://code.csdn.net/do168/buddhismnetworkradio
功能和界面初步设定
APP开发流程实例讲解-儒释道网络电台八天开发全程项目发起
功能和界面初步设定
在Android Studio中完成界面设计
实现功能代码:播放控制
优化排错:增强稳定性和添加异常处理
界面美化并进一步优化排错
百度云深度兼容测试并进一步优化排错
签名发布
昨天的做的设计图是比较简单的,主要麻烦是需要实现两侧的滑动抽屉菜单。
在Android Studio中有一个模板可以创建左侧抽屉,但儒释道网络电台APP需要两边两个抽屉。在网上找到一篇文章《AndroidDrawerLayout+fragment布局实现左右侧滑 》,是使用FragmentTransaction来实现左右侧栏的显现。还有一种办法是使用第三方组件SlidingMenu。难道就不能用Android Studio模板可以创建两侧抽屉滑动菜单吗?经过我一个多小时的探索和尝试,最终发现是可以的。创建的方法我已经写到另一篇文章《Android
DrawerLayout+NavigationView布局实现左右两边侧滑菜单 》,这里不再多说。今天主要的完成的工作有。
双侧滑动抽屉菜单
实现方法上面已经说过,但又略有不同。根据昨天设计的界面,两侧菜单其实是三个ListView,但NavigationView主要是结合menu菜单来创建,有些不对路。经过尝试,最终删掉了NavigationView的menu属性,将列表加入到headerLayout中。实际代码如下:nav_header_main.xml文件
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout 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:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:openDrawer="start"> <include layout="@layout/app_bar_main" android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_main" /> <android.support.design.widget.NavigationView android:id="@+id/right_nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="end" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_server_header_main" /> </android.support.v4.widget.DrawerLayout>然后就是在两个header的Layout文件如下:
<?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:orientation="vertical"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:showDividers="end" android:divider="@drawable/bottom_line"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="@dimen/nav_header_vertical_spacing" android:src="@mipmap/ic_launcher" android:padding="8dp" /> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:paddingBottom="8dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/app_name" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="android.studio@android.com" /> </LinearLayout> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="@dimen/banner48" android:showDividers="end" android:divider="@drawable/bottom_line" android:gravity="center_vertical"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@android:drawable/ic_menu_today" android:layout_margin="8dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="节目列表" /> </LinearLayout> <ListView android:id="@+id/lv_programs" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="@dimen/banner48" android:showDividers="end" android:divider="@drawable/bottom_line" android:gravity="center_vertical"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@android:drawable/ic_menu_compass" android:layout_margin="8dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="最新消息" /> </LinearLayout> <ListView android:id="@+id/lv_news" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView> </LinearLayout>
nav_server_header_main.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:orientation="vertical"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="@dimen/banner48" android:showDividers="end" android:divider="@drawable/bottom_line" android:gravity="center_vertical"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@android:drawable/ic_menu_compass" android:layout_margin="8dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="选择线路" /> </LinearLayout> <ListView android:id="@+id/lv_servers" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView> </LinearLayout>
ListView列表项Layout就不贴了。
主界面的设计
如昨天设计图所示的Layout文件如下:<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="com.jianchi.fsp.buddhismnetworkradio.MainActivity" tools:showIn="@layout/app_bar_main"> <!--640*360--> <FrameLayout android:id="@+id/player_frame" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_width="match_parent" android:layout_height="240dp"> <VideoView android:layout_width="match_parent" android:layout_height="240dp" android:id="@+id/videoView" /> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="@dimen/banner48" android:layout_gravity="bottom" android:background="#b4b4b4b4" android:gravity="center_vertical" android:padding="8dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="净土大经科注 第318集" android:id="@+id/textView3" android:textColor="@android:color/white" android:layout_weight="1" /> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="仅声音" android:id="@+id/checkBox" /> </LinearLayout> </FrameLayout> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/player_frame" android:layout_alignParentLeft="true" android:layout_alignParentBottom="true"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:background="@drawable/side_nav_bar" android:layout_height="@dimen/banner48" android:gravity="center_vertical"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_jiangyi" android:paddingLeft="8dp" android:paddingRight="8dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="经文讲义" /> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/scrollView" android:padding="8dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text New Text " android:id="@+id/textView2" /> </ScrollView> </LinearLayout> </LinearLayout> </RelativeLayout>
根据比例设置视频窗口高度
FrameLayout player_frame = (FrameLayout) findViewById(R.id.player_frame); WindowManager wm = this.getWindowManager(); int width = wm.getDefaultDisplay().getWidth(); int height = width * 9 / 16; player_frame.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
初步完成网络访问API类
网络访问使用了OKHTTP组件,并且是异步访问。OKHttp的使用这里就不多说了。功能实现方法是使用OKHttp下载网页,用正则表达式解析网页,抓取数据生成对象。调用完成事件将数据传回。然后再在UI线程中使用数据填充ListView等。API类如下
package com.jianchi.fsp.buddhismnetworkradio; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; /** * Created by fsp on 16-7-5. */ public class WebApi { /* 节目时间表: 视频音频播放器 线路选择:http://www.amtb.tw/tvchannel/play-1-revised.asp 最新讯息:http://www.amtb.tw/tvchannel/show_marquee.asp 经文讲义:http://ft.hwadzan.com/mycalendar/mycalendar_embed_livetv.php?calendar_name=livetv * */ private static final String programsListUrl = "http://ft.hwadzan.com/mycalendar/mycalendar_embed.php?calendar_name=livetv&showview=day&valign=true&bgcolor=none&showtimecolumns=start&tvmenu=3"; private static final String serversListUrl = "http://www.amtb.tw/tvchannel/play-1-revised.asp"; private static final String newsListUrl = "http://www.amtb.tw/tvchannel/show_marquee.asp"; private static final String noteUrl = "http://ft.hwadzan.com/mycalendar/mycalendar_embed_livetv.php?calendar_name=livetv"; Pattern programsListPattern = Pattern.compile("<td class='style1'>\\s*<strong>(.*?)</strong>\\s*(.*?)\\s*</td>"); Pattern htmlTagPattern = Pattern.compile("<[^>]*>"); Pattern serversListPattern = Pattern.compile("serverAddress = \"(.*?)\";\\s*serverName = \"(.*?)\";"); Pattern newsListPattern = Pattern.compile("<div id='bul_\\d'>(.*?)</div>"); Pattern noteItemPattern = Pattern.compile("<p class=\"MsoNormal\">\\s*(.*?)\\s*</p>"); private OkHttpClient client = new OkHttpClient(); IProgramsListEvent programsListEvent; IServersListEvent serversListEvent; IProgramsListEvent newsListEvent; IStringEvent noteEvent; public void GetNote(IStringEvent noteEvent) { this.noteEvent = noteEvent; Request request = new Request.Builder() .url(noteUrl) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); WebApi.this.noteEvent.getMsg(null); } @Override public void onResponse(Call call, Response response) throws IOException { String html = new String(response.body().bytes(), "big5"); Matcher m = noteItemPattern.matcher(html); StringBuilder sb = new StringBuilder(); while (m.find()){ String nm = m.group(1); if(nm.startsWith("<")) { Matcher hm = htmlTagPattern.matcher(nm); nm = hm.replaceAll(""); } sb.append(nm).append("\r\n"); } WebApi.this.noteEvent.getMsg(sb.toString()); } }); } public void GetNewsList(IProgramsListEvent newsListEvent) { this.newsListEvent = newsListEvent; Request request = new Request.Builder() .url(newsListUrl) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); WebApi.this.newsListEvent.getItems(null); } @Override public void onResponse(Call call, Response response) throws IOException { String html = new String(response.body().bytes(), "big5"); Matcher m = newsListPattern.matcher(html); List<String> newsList = new ArrayList<String>(); while (m.find()){ String nm = m.group(1); if(nm.startsWith("<")) { Matcher hm = htmlTagPattern.matcher(nm); nm = hm.replaceAll(""); } newsList.add(nm); } WebApi.this.newsListEvent.getItems(newsList); } }); } public void GetProgramsList(IProgramsListEvent programsListEvent) { this.programsListEvent = programsListEvent; Request request = new Request.Builder() .url(programsListUrl) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); WebApi.this.programsListEvent.getItems(null); } @Override public void onResponse(Call call, Response response) throws IOException { String html = new String(response.body().bytes(), "utf-8"); Matcher m = programsListPattern.matcher(html); List<String> programsList = new ArrayList<String>(); while (m.find()){ String nm = m.group(2); if(nm.startsWith("<")) { Matcher hm = htmlTagPattern.matcher(nm); nm = hm.replaceAll(""); } programsList.add(m.group(1) + " " + nm); } WebApi.this.programsListEvent.getItems(programsList); } }); } public void GetServersList(IServersListEvent serversListEvent) { this.serversListEvent = serversListEvent; Request request = new Request.Builder() .url(serversListUrl) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { String html = new String(response.body().bytes(), "utf-8"); Matcher m = serversListPattern.matcher(html); ServersList serverList = new ServersList(); while (m.find()){ serverList.add(new ServerInfo(m.group(1), m.group(2))); } WebApi.this.serversListEvent.getServers(serverList); } }); } }
在UI线程中调用的代码如下
api = new WebApi(); api.GetNewsList(new IProgramsListEvent() { @Override public void getItems(List<String> programs) { runOnUiThread(new Runnable() { @Override public void run() { } }); } }); api.GetNote(new IStringEvent() { @Override public void getMsg(String msg) { runOnUiThread(new Runnable() { @Override public void run() { } }); } }); api.GetProgramsList(new IProgramsListEvent() { @Override public void getItems(List<String> programs) { runOnUiThread(new Runnable() { @Override public void run() { } }); } }); api.GetServersList(new IServersListEvent() { @Override public void getServers(ServersList servers) { runOnUiThread(new Runnable() { @Override public void run() { } }); } });
总的来说写代码用的时间比较少,界面设计不熟悉用时较多。原计划每天花2个小时来做这个APP,但今天实际花有4个多小时。界面代码那里花时间过多了,写JAVA代码反而比较快。
明天按计划,写播放器控制的代码。
所有代码已经上传到GIT:https://code.csdn.net/do168/buddhismnetworkradio
相关文章推荐
- 分享下手机软件界面设计浅析
- WPF实现类似360安全卫士界面的程序源码分享
- Android App中DrawerLayout抽屉效果的菜单编写实例
- Android组件之DrawerLayout实现抽屉菜单
- Android Studio注释模板介绍
- Android使用DrawerLayout实现仿QQ双向侧滑菜单
- 关于Android Studio 和 Gradle的那些事儿
- 开源中国 OsChina Android 客户端源码分析(2)滑动菜单DrawerLayout
- 收藏各种技术源码
- [Android]继承式UI界面布局设计
- Android App中DrawerLayout抽屉效果的菜单编写实例
- 想学微信的界面设计,来看看WeUI的暴力美学
- SQLite可视化管理工具汇总
- Drawer实现左右侧滑DrawerLayout
- [网站美工必读]网页设计理念
- 谁说谷歌没品味?搜索巨人开始狠抓界面设计
- C/C++ 开发环境配置(GTK/GNOME/Qt/KDE)
- 黑暗模式:那些骗人的界面设计!
- Android Studio 使用 Gradle 打包 Jar-IT蓝豹
- Android ViewPager多页面滑动切换以及动画效果