Android小玩意儿-- 从头开发一个正经的MusicPlayer(三)
MusicService已经能够接收广播,通过广播接收的内容来做出相应的MediaPlayer对象的处理,包括播放,暂停,停止等,并当MediaPlayer对象的生命周期发生变化的时候,同样通过发送广播,让UI层产生变换。现在后台处理已经写好。下面就来实现前台的Activity。
1·构建UI布局框架##
1.先构建一个RelativeLayout布局,指定一个背景。
2.我的构想是把整个平面分为三部分,第一部分用来调节音量,因为音量调节常用。第二部分是音乐列表。第三部分是音乐控制按钮和音乐进度条。
3.这三部分一步一步的做出来。先做第一部分调节音量的视图。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/relativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/bg_mountain"
>
<LinearLayout
android:id="@+id/main_volumeLayout"
android:layout_height="wrap_content"
android:layout_width="fill_parent">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="1"></LinearLayout>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/main_tv_volumeText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="音量:100%"
android:textColor="#ffffffff"
android:textSize="15dp"/>
<SeekBar
android:id="@+id/main_sb_volumebar"
android:layout_width="82dp"
android:layout_height="wrap_content"
android:maxHeight="5dip"
android:minHeight="5dip"
android:progressDrawable="@drawable/seekbar_style"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
这一部分先这样布局,以后如果体验不好再重新修改。
第二部分是歌曲列表的布局
<ListView
android:id="@+id/main_listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/linearLayout1"
android:layout_below="@id/main_volumeLayout"
android:fastScrollEnabled="true"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:background="@drawable/widget_bg"
android:cacheColorHint="#00000000"></ListView>
第三部分是音乐控制的布局。
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:background="@drawable/widget_bg"
android:orientation="vertical"
>
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center">
<ImageButton
android:id="@+id/main_ibtn_pre"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:background="@drawable/button_previous"/>
<ImageButton
android:id="@+id/main_ibtn_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:background="@drawable/button_play" />
<ImageButton
android:id="@+id/main_ibtn_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:background="@drawable/button_stop" />
<ImageButton
android:id="@+id/main_ibtn_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:background="@drawable/button_next" />
</LinearLayout>
<SeekBar
android:id="@+id/main_seekBar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dip"
android:paddingRight="10dip" />
<RelativeLayout
android:id="@+id/relativeLayout2"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/main_tv_curtime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="00:00" />
<TextView
android:id="@+id/main_tv_totaltime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="00:00" />
</RelativeLayout>
</LinearLayout>
这样整个UI的布局就完成了。
2在之前的MainActivity的基础上继续开发##
先实现最基础的功能,让音乐播放器能够播放,暂停,下一首,上一首,停止。要实现这个功能就要思考,怎么样才能让MusicService能够按照我们UI的状态变化来操纵MediaPlayer对象呢?最直观的一点就是,最起码要让我们的按钮都有响应了,所以要为我们的音乐控制按钮都加上事件监听器,比如,播放按钮,如果触发了播放按钮,就应该让监听器监听到播放按钮被按下,然后我们需要做的就是在用户按下按钮之后,在监听器下做出相应的相应。MusicService里的MediaPlayer对象有绑定了广播接收器。我们可以让按钮按下之后分发相应的广播。通过广播来通知Service。所以,要给各个按钮增加事件监听器,并分发广播。
MainActivity.java
package com.zharma.greatlovemusic;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import com.zharma.data.Music;
import com.zharma.data.MusicList;
import android.support.v7.app.ActionBarActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
public class MainActivity extends ActionBarActivity {
// 显示组件
private TextView tv_current_time;
private TextView tv_total_time;
private ImageButton imgBtn_Previous;
private ImageButton imgBtn_PlayOrPause;
private ImageButton imgBtn_Stop;
private ImageButton imgBtn_Next;
private SeekBar seekBar;
private ListView listView;
private RelativeLayout root_Layout;
// 当前歌曲的持续时间和当前位置,作用于进度条
private int total_time;
private int curent_time;
//当前歌曲的序号,下标从零开始
private int number;
// 播放状态标志位
private int status;
//歌曲列表对象
private ArrayList<Music> musicArrayList;
//音量控制
private TextView tv_vol;
private SeekBar seekbar_vol;
// 进度条控制常量
private static final int PROGRESS_INCREASE = 0;
private static final int PROGRESS_PAUSE = 1;
private static final int PROGRESS_RESET = 2;
// 更新进度条的Handler
private Handler seekBarHandler;
//睡眠模式相关组件,标识常量
private ImageView iv_sleep;
private Timer timer_sleep ;
private static final boolean NOTSLEEP = false;
private static final boolean ISSLEEP = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViews();
initMusicList();
initListView();
registerListeners();
checkMusicfile();
startService(new Intent(this, MusicService.class));
// 绑定广播接收器,可以接收广播
bindStatusChangedReceiver();
sendBroadcastOnCommand(MusicService.COMMAND_CHECK_IS_PLAYING);
//初始化进度条的Handler
initSeekBarHandler();
status = MusicService.COMMAND_STOP;
}
void findViews() {
listView = (ListView) findViewById(R.id.main_listview);
tv_current_time = (TextView) findViewById(R.id.main_tv_curtime);
tv_total_time = (TextView) findViewById(R.id.main_tv_totaltime);
imgBtn_Previous = (ImageButton) findViewById(R.id.main_ibtn_pre);
imgBtn_PlayOrPause = (ImageButton) findViewById(R.id.main_ibtn_play);
imgBtn_Previous = (ImageButton) findViewById(R.id.main_ibtn_pre);
imgBtn_Next = (ImageButton) findViewById(R.id.main_ibtn_next);
imgBtn_Stop = (ImageButton) findViewById(R.id.main_ibtn_stop);
seekBar = (SeekBar) findViewById(R.id.main_seekBar);
root_Layout = (RelativeLayout) findViewById(R.id.relativeLayout1);
tv_vol = (TextView)findViewById(R.id.main_tv_volumeText);
seekbar_vol = (SeekBar)findViewById(R.id.main_sb_volumebar);
iv_sleep = (ImageView)findViewById(R.id.main_iv_sleep);
}
/**初始化音乐列表对象*/
private void initMusicList() {
musicArrayList = MusicList.getMusicList();
//避免重复添加音乐
if(musicArrayList.isEmpty())
{
Cursor mMusicCursor = this.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
MediaStore.Audio.AudioColumns.TITLE);
int indexTitle = mMusicCursor.getColumnIndex(MediaStore.Audio.AudioColumns.TITLE);
int indexArtist = mMusicCursor.getColumnIndex(MediaStore.Audio.AudioColumns.ARTIST);
int indexTotalTime = mMusicCursor.getColumnIndex(MediaStore.Audio.AudioColumns.DURATION);
int indexPath = mMusicCursor.getColumnIndex(MediaStore.Audio.AudioColumns.DATA);
/**通过mMusicCursor游标遍历数据库,并将Music类对象加载带ArrayList中*/
for (mMusicCursor.moveToFirst(); !mMusicCursor.isAfterLast(); mMusicCursor
.moveToNext()) {
String strTitle = mMusicCursor.getString(indexTitle);
String strArtist = mMusicCursor.getString(indexArtist);
String strTotoalTime = mMusicCursor.getString(indexTotalTime);
String strPath = mMusicCursor.getString(indexPath);
if (strArtist.equals("<unknown>"))
strArtist = "无艺术家";
Music music = new Music(strTitle, strArtist, strPath, strTotoalTime);
musicArrayList.add(music);
}
}
}
/**设置适配器并初始化listView*/
private void initListView() {
List<Map<String, String>> list_map = new ArrayList<Map<String, String>>();
HashMap<String, String> map;
SimpleAdapter simpleAdapter;
for (Music music : musicArrayList) {
map = new HashMap<String, String>();
map.put("musicName", music.getMusicName());
map.put("musicArtist", music.getMusicArtist());
list_map.add(map);
}
String[] from = new String[] { "musicName", "musicArtist" };
int[] to = { R.id.listview_tv_title_item, R.id.listview_tv_artist_item };
simpleAdapter = new SimpleAdapter(this, list_map, R.layout.listview,from, to);
listView.setAdapter(simpleAdapter);
}
private void registerListeners() {
imgBtn_Previous.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
sendBroadcastOnCommand(MusicService.COMMAND_PREVIOUS);
}
});
imgBtn_PlayOrPause.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
switch (status) {
case MusicService.STATUS_PLAYING:
sendBroadcastOnCommand(MusicService.COMMAND_PAUSE);
break;
case MusicService.STATUS_PAUSED:
sendBroadcastOnCommand(MusicService.COMMAND_RESUME);
break;
case MusicService.COMMAND_STOP:
sendBroadcastOnCommand(MusicService.COMMAND_PLAY);
break;
default:
break;
}
}
});
imgBtn_Stop.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
sendBroadcastOnCommand(MusicService.COMMAND_STOP);
}
});
imgBtn_Next.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
sendBroadcastOnCommand(MusicService.COMMAND_NEXT);
}
});
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
number = position;
sendBroadcastOnCommand(MusicService.COMMAND_PLAY);
}
});
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (status == MusicService.STATUS_PLAYING) {
// 发送广播给MusicService,执行跳转
sendBroadcastOnCommand(MusicService.COMMAND_SEEK_TO);
// 进度条恢复移动
seekBarHandler.sendEmptyMessageDelayed(PROGRESS_INCREASE,
1000);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// 进度条暂停移动
seekBarHandler.sendEmptyMessage(PROGRESS_PAUSE);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if (status != MusicService.STATUS_STOPPED) {
curent_time = progress;
// 更新文本
tv_current_time.setText(formatTime(curent_time));
}
}
});
}
}
现在主体已经写好,后面就是具体的各个实现方法。把发送广播的方法与格式化时间的方法实现如下:
/** 发送命令,控制音乐播放。参数定义在MusicService类中 */
private void sendBroadcastOnCommand(int command) {
Intent intent = new Intent(MusicService.BROADCAST_MUSICSERVICE_CONTROL);
intent.putExtra("command", command);
// 根据不同命令,封装不同的数据
switch (command) {
case MusicService.COMMAND_PLAY:
intent.putExtra("number", number);
break;
case MusicService.COMMAND_SEEK_TO:
intent.putExtra("time", curent_time);
break;
case MusicService.COMMAND_PREVIOUS:
case MusicService.COMMAND_NEXT:
case MusicService.COMMAND_PAUSE:
case MusicService.COMMAND_STOP:
case MusicService.COMMAND_RESUME:
default:
break;
}
sendBroadcast(intent);
}
/**如果列表没有歌曲,则播放按钮不可用,并提醒用户*/
private void checkMusicfile()
{
if (musicArrayList.isEmpty()) {
imgBtn_Next.setEnabled(false);
imgBtn_PlayOrPause.setEnabled(false);
imgBtn_Previous.setEnabled(false);
imgBtn_Stop.setEnabled(false);
Toast.makeText(getApplicationContext(), "当前没有歌曲文件",Toast.LENGTH_SHORT).show();
} else {
imgBtn_Next.setEnabled(true);
imgBtn_PlayOrPause.setEnabled(true);
imgBtn_Previous.setEnabled(true);
imgBtn_Stop.setEnabled(true);
}
}
/** 绑定广播接收器 */
private void bindStatusChangedReceiver() {
receiver = new StatusChangedReceiver();
IntentFilter filter = new IntentFilter(
MusicService.BROADCAST_MUSICSERVICE_UPDATE_STATUS);
registerReceiver(receiver, filter);
}
/** 内部类,用于播放器状态更新的接收广播 */
class StatusChangedReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
// 获取播放器状态
status = intent.getIntExtra("status", -1);
switch (status) {
case MusicService.STATUS_PLAYING:
String musicName = intent.getStringExtra("musicName");
String musicArtist = intent.getStringExtra("musicArtist");
seekBarHandler.removeMessages(PROGRESS_INCREASE);
curent_time = intent.getIntExtra("time", 0);
total_time = intent.getIntExtra("duration", 0);
number = intent.getIntExtra("number", number);
listView.setSelection(number);
seekBar.setProgress(curent_time);
seekBar.setMax(total_time);
seekBarHandler.sendEmptyMessageDelayed(PROGRESS_INCREASE, 1000);
tv_total_time.setText(formatTime(total_time));
imgBtn_PlayOrPause.setBackgroundResource(R.drawable.pause);
// 设置Activity的标题栏文字,提示正在播放的歌曲
MainActivity.this.setTitle("正在播放:" + musicName + " "+ musicArtist);
break;
case MusicService.STATUS_PAUSED:
seekBarHandler.sendEmptyMessage(PROGRESS_PAUSE);
String string = MainActivity.this.getTitle().toString().replace("正在播放:", "已暂停:");
MainActivity.this.setTitle(string);
imgBtn_PlayOrPause.setBackgroundResource(R.drawable.play);
break;
case MusicService.STATUS_STOPPED:
curent_time = 0;
total_time = 0;
tv_current_time.setText(formatTime(curent_time));
tv_total_time.setText(formatTime(total_time));
seekBarHandler.sendEmptyMessage(PROGRESS_RESET);
MainActivity.this.setTitle("GracePlayer");
imgBtn_PlayOrPause.setBackgroundResource(R.drawable.play);
break;
case MusicService.STATUS_COMPLETED:
number = intent.getIntExtra("number", 0);
//顺序模式:到达列表末端时发送停止命令,否则播放下一首
if(playmode == MainActivity.MODE_LIST_SEQUENCE)
{
if(number == MusicList.getMusicList().size()-1)
sendBroadcastOnCommand(MusicService.STATUS_STOPPED);
else
sendBroadcastOnCommand(MusicService.COMMAND_NEXT);
}
//单曲循环
else if(playmode == MainActivity.MODE_SINGLE_CYCLE)
sendBroadcastOnCommand(MusicService.COMMAND_PLAY);
//列表循环:到达列表末端时,把要播放的音乐设置为第一首
else if(playmode == MainActivity.MODE_LIST_CYCLE)
{
//然后发送播放命令。
if(number == musicArrayList.size()-1)
{
number = 0;
sendBroadcastOnCommand(MusicService.COMMAND_PLAY);
}
else sendBroadcastOnCommand(MusicService.COMMAND_NEXT);
}
//随机播放
else if (playmode == MainActivity.MODE_LIST_RANDOM)
{
Random random = new Random();
int randomnum = random.nextInt(listView.getCount());
number = randomnum;
sendBroadcastOnCommand(MusicService.COMMAND_PLAY);
}
seekBarHandler.sendEmptyMessage(PROGRESS_RESET);
MainActivity.this.setTitle("GracePlayer");
imgBtn_PlayOrPause.setBackgroundResource(R.drawable.play);
break;
default:
break;
}
}
}
private void initSeekBarHandler() {
seekBarHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case PROGRESS_INCREASE:
if (seekBar.getProgress() < total_time) {
// 进度条前进1秒
seekBar.incrementProgressBy(1000);
seekBarHandler.sendEmptyMessageDelayed(
PROGRESS_INCREASE, 1000);
// 修改显示当前进度的文本
tv_current_time.setText(formatTime(curent_time));
curent_time += 1000;
}
break;
case PROGRESS_PAUSE:
seekBarHandler.removeMessages(PROGRESS_INCREASE);
break;
case PROGRESS_RESET:
// 重置进度条界面
seekBarHandler.removeMessages(PROGRESS_INCREASE);
seekBar.setProgress(0);
tv_current_time.setText("00:00");
break;
}
}
};
}
3·AndroidManifest.xml文件配置##
最后还要把我们的Service加到配置文件里。
<service
android:name="com.zharma.greatlovemusic.MusicService"
android:exported="true" >
<intent-filter>
<action android:name="VideoService.START_Video_SERVICE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
到目前为止,这个播放器已经实现了基本的音乐播放功能,后面有时间就会再加一些网络歌词获取,放到一个Activity里。搞个华丽的侧滑界面。弄个睡眠模式,播放模式之类的东西,让这个播放器看起来更正儿八经。
Android小玩意儿-- 从头开发一个正经的MusicPlayer(三)的更多相关文章
- Android小玩意儿-- 从头开发一个正经的MusicPlayer(一)
之前从未接触过音乐播放器这块东西的开发.今天偶然想做一个自己的音乐播放器.算是练练手.既然要做,就要做一个正儿八经的App.很多网上的资料也是模模糊糊,不是很全,现在开始,自己摸索着尝试着一步一步的做 ...
- Android小玩意儿-- 从头开发一个正经的MusicPlayer(二)
1·在Service中实例化MusicPlayer,实现对整个播放过程的控制 上一次做到了找到音乐数据,并封装成对象装在ArrayList里,把数据的信息显示在UI上.下面一个阶段就要开始真正的音乐播 ...
- 微信小程序实战--开发一个简单的快递单号查询
功能如图: 虽然工作中只负责小程序后台开发,但是还是小程序开发产生了浓厚的兴趣,官方文档也是超级详细了 这里就简单做一个快递单号的查询: 新建一个page: 接着就可以写wxml了.这里用一个简单的i ...
- 微信小程序:开发之前要知道的三件事
前言 微信之父张小龙在年初的那次演讲中曾表示:"我自己是很多年的程序员,我觉得我们应该为开发的团队做一些事情".几个月后,微信正式推出微信应用号(即微信小程序),在互联网中掀起了又 ...
- 用Visual Studio 2015 编写 MASM 汇编程序(二)从头开发一个Win32汇编程序
一,建立一个VC的控制台类型的空工程: 1,从VS菜单中选择“文件”->“新建”->“项目”. 2,在新建项目中选择:“Visual c++”->"Win32"- ...
- Android | 教你如何用代码开发一个拍照翻译小程序
引子 想必有很多小伙伴喜欢外出旅游,能去海外玩一圈那是更好不过了,旅游前大家一定会对吃.穿.住.行.游玩路线做各种攻略,然后满怀期待的出发- 想象中的旅游 出发前,想象中的旅游目的地可能有漂亮 ...
- Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序
Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序 引子 上期给大家介绍了如何使用如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓 ...
- 「1.0」一个人开发一个App,小程序从0到1,起航了
古有,秦.齐.楚.赵.魏.韩.燕七国争雄:今有,微信.QQ.百度.支付宝.钉钉.头条.抖音七台争霸.古有,白起.李牧.王翦.孙膑.庞涓.赵奢.廉颇驰骋疆场:今有程序员1,程序员2,程序员3…编写代码. ...
- Android | 教你如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓拍神器
Android | 只要三十分钟就可以在手机上开发一个微笑抓拍神器!!! 前言 前段时间Richard Yu在发布会上给大家介绍了华为HMS Core4.0,回顾发布会信息请戳: 华为面向全球发布HM ...
随机推荐
- POJ1094 Sorting It All Out —— 拓扑排序
题目链接:http://poj.org/problem?id=1094 Sorting It All Out Time Limit: 1000MS Memory Limit: 10000K Tot ...
- 应用程序启动器 “sublime_text.desktop“ 还没有被标记为 信任。如果您不知道这个文件的来源,那么启动它可能会不安全。解决sublime在ubuntu中不支持中文输入问题。
1.下载 git clone https://github.com/lyfeyaj/sublime-text-imfix.git 2.进行一些处理 cd ~/sublime-text-imfix su ...
- 一步一步学Silverlight 2系列(24):与浏览器交互相关辅助方法
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- 自写程序调用mount
代码: int fd = open("/dev/fuse", O_RDWR); printf("fd=%d\n",fd); int res; res=mount ...
- 网站页面打开浏览器table中显示图片
就类似博客园这种:
- oracle实例的内存(SGA和PGA)调整,优化数据库性能
一.名词解释 (1)SGA:SystemGlobal Area是OracleInstance的基本组成部分,在实例启动时分配;系统全局域SGA主要由三部分构成:共享池.数据缓冲区.日志缓冲区. (2) ...
- 「LuoguP1122」 最大子树和
Description 小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题.一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题.于是 ...
- Java throw与throws
以前虽然知道一些异常的处理,也用过一些,但是对throw和throws区别还是有不太清楚.今天用实例测试一下. 异常处理机制 异常处理是对可能出现的异常进行处理,以防止程序遇到异常时被卡死,处于一直等 ...
- spring+mybatis 多数据源整合--temp
<!-- 数据源配置 --> <bean id="ds1" class="org.apache.commons.dbcp.BasicDataSour ...
- C++实现查找链表中环的入口节点
/* * 寻找链表中环的入口节点.cpp * * Created on: 2018年4月10日 * Author: soyo */ #include<iostream> using nam ...