APP开发流程实例讲解-儒释道网络电台八天开发全程
优化排错:增强稳定性和添加异常处理
APP开发流程实例讲解-儒释道网络电台八天开发全程
在启动时检测网络状态
先增加检测网络状态的权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
然后用下面的代码检测是否连接有网络
/**
* 检测网络是否可用
* @return
*/
public boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
return ni != null && ni.isConnected();
}
在onCreate中检测网络状态,如果没连网,则提示没有网络连接,退出程序。
增加VideoView状态提示和错误处理
增加正在载入数据的提示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
videoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mediaPlayer, int what, int extra) {
if(what==MediaPlayer.MEDIA_INFO_BUFFERING_START ){
Toast.makeText(MainActivity.this,
"正在缓冲",
Toast.LENGTH_LONG).show();
}
return false;
}
});
}
处理三类网络错误:服务器断开、网络文件未找到、超时。对于出错时的处理,这里只是提示用户,并没有强制关闭程序。因为很有可能是线路选择有问题,只需要选择合适的线路就可以了。
videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
/*
错误常数
MEDIA_ERROR_IO
文件不存在或错误,或网络不可访问错误
值: -1004 (0xfffffc14)
MEDIA_ERROR_MALFORMED
流不符合有关标准或文件的编码规范
值: -1007 (0xfffffc11)
MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK
视频流及其容器不适用于连续播放视频的指标(例如:MOOV原子)不在文件的开始.
值: 200 (0x000000c8)
MEDIA_ERROR_SERVER_DIED
媒体服务器挂掉了。此时,程序必须释放MediaPlayer 对象,并重新new 一个新的。
值: 100 (0x00000064)
MEDIA_ERROR_TIMED_OUT
一些操作使用了过长的时间,也就是超时了,通常是超过了3-5秒
值: -110 (0xffffff92)
MEDIA_ERROR_UNKNOWN
未知错误
值: 1 (0x00000001)
MEDIA_ERROR_UNSUPPORTED
比特流符合相关编码标准或文件的规格,但媒体框架不支持此功能
值: -1010 (0xfffffc0e)
what int: the type of error that has occurred:
MEDIA_ERROR_UNKNOWN
MEDIA_ERROR_SERVER_DIED
extra int: an extra code, specific to the error. Typically implementation dependent.
MEDIA_ERROR_IO
MEDIA_ERROR_MALFORMED
MEDIA_ERROR_UNSUPPORTED
MEDIA_ERROR_TIMED_OUT
MEDIA_ERROR_SYSTEM (-2147483648) - low-level system error.
* */
if(what==MediaPlayer.MEDIA_ERROR_SERVER_DIED){
//媒体服务器挂掉了。此时,程序必须释放MediaPlayer 对象,并重新new 一个新的。
Toast.makeText(MainActivity.this,
"网络服务错误",
Toast.LENGTH_LONG).show();
}else if(what==MediaPlayer.MEDIA_ERROR_UNKNOWN){
if(extra==MediaPlayer.MEDIA_ERROR_IO){
//文件不存在或错误,或网络不可访问错误
Toast.makeText(MainActivity.this,
"网络连接错误",
Toast.LENGTH_LONG).show();
} else if(extra==MediaPlayer.MEDIA_ERROR_TIMED_OUT){
//超时
Toast.makeText(MainActivity.this,
"网络超时",
Toast.LENGTH_LONG).show();
}
}
return false;
}
});
动态计算ListView的高度
public void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
对播放和暂停进行统一控制
将播放的暂停的操作,写到了下面这个函数里进行统一管理。
private void resetVideoView(boolean toPlay){
if(!isNetworkConnected()){
Toast.makeText(this, "未连接网络,程序将关闭。请连网后重新打开本程序。", Toast.LENGTH_LONG).show();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//没有连接到网络,关系程序
finish();
}
}).start();
}else {
if (toPlay) {
if (videoView.isPlaying()) {
videoView.suspend();
}
if (onlySound) {
videoView.setVisibility(View.VISIBLE);
videoView.setBackgroundResource(R.drawable.zcgt);
videoView.setVideoURI(data.getServers().getSoundUriAuto());
} else {
videoView.setBackgroundResource(0);
videoView.setVideoURI(data.getServers().getVideoUriAuto());
}
videoView.start();
bt_play.setImageResource(android.R.drawable.ic_media_pause);
} else {
if (videoView.isPlaying()) {
videoView.suspend();
}
videoView.setBackgroundResource(0);
bt_play.setImageResource(android.R.drawable.ic_media_play);
}
}
}
增加等待对话框
//打开等待初始化的对话框
runOnUiThread(new Runnable() {
@Override
public void run() {
proDialog = ProgressDialog.show(MainActivity.this, "载入数据", "数据加载中...");
}
});
在载入数据结束后,然后关闭进度对话框
//结束等待
proDialog.dismiss();
获取网络数据错误处理
首先在给 OkHttp3 设置超时,这个我已经在另一篇文章里做了详细说明(《OkHttp3超时设置和超时异常捕获 》)。
并在代码中检测超时。超时次数超过一定限制后返回空值。
同时检测正则表达式的返回结果。
public void GetNote(IStringEvent noteEvent) {
this.noteEvent = noteEvent;
noteLoadTimes = 0;
Request request = new Request.Builder()
.url(noteUrl)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
if(e.getCause().equals(SocketTimeoutException.class) && noteLoadTimes<maxLoadTimes)
{
noteLoadTimes++;
client.newCall(call.request()).enqueue(this);
}else {
e.printStackTrace();
WebApi.this.noteEvent.getMsg(null);
}
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String html = new String(response.body().bytes(), "utf8");
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());
}
});
}
今天的工作就到这里吧。
APP程序能跑了,哈哈
源码地址 https://code.youkuaiyun.com/do168/buddhismnetworkradio