APP开发流程实例讲解-儒释道网络电台八天开发全程-在Android Studio中完成界面设计

来源:互联网 发布:淘宝短视频服务商 编辑:程序博客网 时间:2024/06/05 04:35

APP开发流程实例讲解-儒释道网络电台八天开发全程

功能和界面初步设定

APP开发流程实例讲解-儒释道网络电台八天开发全程

  1. 项目发起
  2. 功能和界面初步设定
  3. 在Android Studio中完成界面设计
  4. 实现功能代码:播放控制
  5. 优化排错:增强稳定性和添加异常处理
  6. 界面美化并进一步优化排错
  7. 百度云深度兼容测试并进一步优化排错
  8. 签名发布



昨天的做的设计图是比较简单的,主要麻烦是需要实现两侧的滑动抽屉菜单。

在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

0 0
原创粉丝点击