Android:手机做服务器控制多个手机客户端同时播放音乐(含源码)
来源:互联网 发布:聪明的程序员用delphi 编辑:程序博客网 时间:2024/05/23 15:38
朋友要求婚,请我帮忙做个小软件,希望他能控制周边朋友的手机,同时播放求婚用的歌曲。想法挺好的,奈何时间紧急,花了几个小时,帮他实现了一个粗糙的版本,可以控制连接上的手机同时播放、暂停、停止放歌。
基本想法是使用C/S架构,一台手机做为服务器,其他手机做为客户端,所有客户端用socket连接上服务器,客户端不断读取socket中的数据,解析出命令后控制歌曲的播放。
实现效果:
废话不多说,直接贴代码:
服务器:
布局文件:activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#FFFFFF"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="20dp" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="15dp" android:textColor="#000000" android:text="服务器IP地址:" /> <TextView android:id="@+id/tvIP" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="192.168.0.1" android:textSize="20dp" android:textColor="#0000FF"/> </LinearLayout> <LinearLayout android:layout_marginTop="20dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="15dp" android:textColor="#000000" android:text="连接的客户端数目:" /> <TextView android:id="@+id/tvClientNum" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textSize="20dp" android:textColor="#FF0000"/> </LinearLayout> <Button android:id="@+id/btn_start_play" android:layout_gravity="center" android:layout_width="250dp" android:layout_height="80dp" android:textSize="22dp" android:text="开始播放音乐" android:layout_marginTop="50dp" android:layout_marginBottom="10dp" /> <Button android:id="@+id/btn_pause_play" android:layout_gravity="center" android:layout_width="250dp" android:layout_height="50dp" android:textSize="18dp" android:text="暂停播放" android:layout_marginTop="20dp" android:layout_marginBottom="10dp" /> <Button android:id="@+id/btn_stop_play" android:layout_gravity="center" android:layout_width="250dp" android:layout_height="50dp" android:textSize="18dp" android:text="停止播放" android:layout_marginTop="20dp" android:layout_marginBottom="10dp" /> </LinearLayout>ServerThread.java
package ict.ldj.server;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import android.util.Log; public class ServerThread implements Runnable { // 定义当前线程所处理的Socket private Socket socket = null; // 该线程所处理的Socket所对应的输入流 BufferedReader br = null; public ServerThread(Socket socket) throws IOException { this.socket = socket; // 初始化该Socket对应的输入流 br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8")); } @Override public void run() { try { String content = null; // 采用循环不断从Socket中读取客户端发送过来的数据 while ((content = readFromClient()) != null) { // 遍历socketList中的每个Socket,将读到的内容向每个Socket发送一次 Log.w("client msg",content + "\t"); if ("QUIT".equals(content)) {socket.close();ServerMainActivity.socketList.remove(socket);}// for (Socket s : ServerMainActivity.socketList) { // OutputStream os = s.getOutputStream(); // os.write((content + "\n").getBytes("utf-8")); // } } } catch (Exception e) { e.printStackTrace(); } } /** * 定义读取客户端数据的方法 * * @return */ private String readFromClient() { try { return br.readLine(); } // 如果捕捉到异常,表明该Socket对应的客户端已经关闭 catch (Exception e) { // 删除该Socket ServerMainActivity.socketList.remove(socket); e.printStackTrace(); } return null; } }ServerMainActivity.java
package ict.ldj.server;import java.io.IOException;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import android.app.Activity;import android.app.AlertDialog;import android.content.Context;import android.content.DialogInterface;import android.net.wifi.WifiInfo;import android.net.wifi.WifiManager;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.Process;import android.util.Log;import android.view.KeyEvent;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class ServerMainActivity extends Activity {// 定义保存所有Socket的集合public static ArrayList<Socket> socketList = new ArrayList<Socket>();private static final int refresh_num_msd_code = 0x101;public Button btnStartPlay = null;public Button btnPausePlay = null;public Button btnStopPlay = null;public TextView tvIP = null;public TextView tvClientNum = null;//用来更新与服务器连接的客户端个数public Handler mHandler = new Handler(){public void handleMessage(Message msg) {if (msg.what == refresh_num_msd_code) { tvClientNum.setText(socketList.size() + "");}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initWidget();new Thread() {public void run() {try {StartListenerSocket();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}.start();}private void initWidget() {btnStartPlay = (Button) findViewById(R.id.btn_start_play);btnPausePlay = (Button) findViewById(R.id.btn_pause_play);btnStopPlay = (Button) findViewById(R.id.btn_stop_play);tvIP = (TextView) findViewById(R.id.tvIP);tvClientNum = (TextView) findViewById(R.id.tvClientNum);btnStartPlay.setOnClickListener(myOnClickListener);btnPausePlay.setOnClickListener(myOnClickListener);btnStopPlay.setOnClickListener(myOnClickListener); tvIP.setText(getLocalIp()); new Thread(){ public void run(){ while(true){ try { mHandler.sendEmptyMessage(refresh_num_msd_code);this.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} } } }.start();}/** * 获取本机的IP地址 * @return 本机的IP地址,Sring */private String getLocalIp(){// 获取wifi服务WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); //判断wifi是否开启 if (!wifiManager.isWifiEnabled()) { wifiManager.setWifiEnabled(true); } WifiInfo wifiInfo = wifiManager.getConnectionInfo(); int ipAddress = wifiInfo.getIpAddress(); return intToIp(ipAddress); }private String intToIp(int i) { return (i & 0xFF ) + "." + ((i >> 8 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ( i >> 24 & 0xFF) ; } private OnClickListener myOnClickListener = new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.btn_start_play:try {for (Socket s : socketList) {OutputStream os = s.getOutputStream();if (os != null)os.write(("START PLAY MUSIC\n").getBytes("utf-8"));}} catch (Exception e) {e.printStackTrace();}break;case R.id.btn_pause_play:try {for (Socket s : socketList) {OutputStream os = s.getOutputStream();if (os != null)os.write(("PAUSE PLAY MUSIC\n").getBytes("utf-8"));}} catch (Exception e) {e.printStackTrace();}break;case R.id.btn_stop_play:try {for (Socket s : socketList) {OutputStream os = s.getOutputStream();if (os != null)os.write(("STOP PLAY MUSIC\n").getBytes("utf-8"));}} catch (Exception e) {e.printStackTrace();}break;default:break;}}};public void StartListenerSocket() throws IOException {ServerSocket ss = new ServerSocket(20000);System.out.println("服务器创建成功!");System.out.println("等待客戶端的连接。。。");while (true) {// 此行代码会阻塞,等待用户的连接Socket socket = ss.accept();System.out.println("有客户端连接进来!");Log.w("server log", "有客户端连接进来!");socketList.add(socket);// 每当客户端连接后启动一条ServerThread线程为该客户端服务new Thread(new ServerThread(socket)).start();}} @Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();closeAllSocket();} /** * 关闭服务器连接的所有Socket */ private void closeAllSocket(){ try {for (Socket s : socketList) {OutputStream os = s.getOutputStream();if(os != null)os.write(("QUIT\n").getBytes("utf-8"));s.close();ServerMainActivity.socketList.remove(s);}} catch (Exception e) {e.printStackTrace();} }@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {// TODO Auto-generated method stubif (keyCode == KeyEvent.KEYCODE_BACK) {new AlertDialog.Builder(this).setIcon(R.drawable.menu_exit).setTitle("Notice").setMessage("Do you want to quit?").setNegativeButton("No",new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog,int which) {}}).setPositiveButton("Yes",new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog,int whichButton) {closeAllSocket();ServerMainActivity.this.finish();Process.killProcess(Process.myPid());}}).show();return true;} else {return super.onKeyDown(keyCode, event);}}}
客户端:
布局文件activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:orientation="horizontal" > <EditText android:id="@+id/edtServerIp" android:layout_width="240dp" android:layout_height="wrap_content" android:layout_gravity="center" android:hint="如:192.168.0.101" android:paddingLeft="10dp" /> <Button android:id="@+id/btnSetAndEditIP" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" android:text="设置\n服务器IP" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:gravity="center" android:orientation="horizontal" > <Button android:id="@+id/btnConnectServer" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="3" android:enabled="false" android:paddingLeft="10dp" android:paddingRight="10dp" android:text="连接服务器" /> <Button android:id="@+id/btnDisConnectServer" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="2" android:enabled="false" android:paddingLeft="10dp" android:paddingRight="10dp" android:text="断开服务器连接" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:gravity="center" android:visibility="gone" android:orientation="horizontal" > <Button android:id="@+id/start" android:layout_width="0dp" android:layout_weight="2" android:layout_height="wrap_content" android:text="start" /> <Button android:id="@+id/pause" android:layout_width="0dp" android:layout_weight="2" android:layout_height="wrap_content" android:text="pause" /> <Button android:id="@+id/stop" android:layout_width="0dp" android:layout_weight="2" android:layout_height="wrap_content" android:text="stop" /> </LinearLayout></LinearLayout>ClientThread.java
package ict.ldj.client;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import android.os.Handler; import android.os.Message; import android.util.Log; public class ClientThread implements Runnable { private Handler handler; // 该线程所处理的Socket所对应的输入流 private BufferedReader br = null; public ClientThread(Socket socket, Handler handler) throws IOException { this.handler = handler; br = new BufferedReader(new InputStreamReader(socket.getInputStream())); } @Override public void run() { try { String content = null; // 不断读取Socket输入流的内容 while ((content = br.readLine()) != null) { // 每当读到来自服务器的数据之后,发送消息通知程序界面显示该数据 if ("START PLAY MUSIC".equals(content)) { handler.sendEmptyMessage(ClientMainActivity.socket_start_play);}else if ("PAUSE PLAY MUSIC".equals(content)) {handler.sendEmptyMessage(ClientMainActivity.socket_pause_play);}else if ("STOP PLAY MUSIC".equals(content)) {handler.sendEmptyMessage(ClientMainActivity.socket_stop_play);}else if ("QUIT".equals(content)) {handler.sendEmptyMessage(ClientMainActivity.socket_quit);}else{Message msg = new Message(); msg.what = ClientMainActivity.socket_msg; msg.obj = content; handler.sendMessage(msg);} Log.w("msg", content); } } catch (Exception e) { e.printStackTrace(); } } }ClientMainActivity.java
package ict.ldj.client;import java.io.IOException;import java.io.OutputStream; import java.net.Socket; import android.app.Activity; import android.app.AlertDialog;import android.content.DialogInterface;import android.content.res.AssetFileDescriptor;import android.media.MediaPlayer;import android.os.Bundle; import android.os.Handler; import android.os.Message;import android.os.Process;import android.view.KeyEvent;import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class ClientMainActivity extends Activity { public static final int socket_quit = 0;// socket断开public static final int socket_start_play = 1;// 播放音乐public static final int socket_pause_play = 2;// 暂停播放public static final int socket_stop_play = 3;// 停止播放public static final int socket_msg = 0x234;// 用来聊天用的信息,该程序中未使用 private EditText edtServerIp = null; private Button btnSetAndEditIP = null; private Button btnConnectServer = null; private Button btnDisConnectServer = null; private String serverIp = ""; private OutputStream os = null; private Handler handler = null; private Socket socket = null; private MediaPlayer mp3 = null; private Boolean isPlaying = false; //设置标记,false表示正在播放 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initWidget(); } private void initWidget(){ edtServerIp = (EditText) findViewById(R.id.edtServerIp); btnSetAndEditIP = (Button) findViewById(R.id.btnSetAndEditIP); btnConnectServer = (Button) findViewById(R.id.btnConnectServer); btnDisConnectServer = (Button) findViewById(R.id.btnDisConnectServer); btnSetAndEditIP.setOnClickListener(myOnClickListener); btnConnectServer.setOnClickListener(myOnClickListener); btnDisConnectServer.setOnClickListener(myOnClickListener); findViewById(R.id.start).setOnClickListener(myOnClickListener); findViewById(R.id.stop).setOnClickListener(myOnClickListener); findViewById(R.id.pause).setOnClickListener(myOnClickListener); initMediaPlayer(); handler = new Handler() { public void handleMessage(Message msg) { // 如果消息来自子线程 if (msg.what == socket_msg) { // 将读取的内容追加显示在文本框中 String mString = msg.obj.toString(); }else if (msg.what == socket_start_play) { showMessage("开始播放音乐"); // 开始播放音乐 startPlayMusic(); }else if (msg.what == socket_pause_play) { showMessage("暂停播放"); pausePlayMusic(); }else if (msg.what == socket_stop_play) { showMessage("停止播放"); stopPlayMusic(); }else if(msg.what == socket_quit){ showAlertDialog("与服务器的连接已断开!!");} } }; } /** * 初始化播放器句柄 */ private void initMediaPlayer(){ mp3 = new MediaPlayer(); // mp3 = MediaPlayer.create(ClientMainActivity.this,R.raw.music); try { AssetFileDescriptor afd = this.getAssets().openFd("music.mp3"); mp3.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength()); if (mp3 != null) { mp3.prepare(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 开始播放 */ private void startPlayMusic(){ try {if (mp3 != null) {mp3.stop();}mp3.prepare();mp3.start();isPlaying = true;} catch (Exception e) {// TODO: handle exceptione.printStackTrace();} } /** * 停止播放 */ private void stopPlayMusic(){ try {if (mp3 != null) {mp3.stop();mp3.reset();initMediaPlayer();}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();} } /** * 暂停播放 */ private void pausePlayMusic(){ try {if (isPlaying) {mp3.pause();isPlaying = false;}else {mp3.start();isPlaying = true;}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();} } private OnClickListener myOnClickListener = new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.btnSetAndEditIP:if (btnSetAndEditIP.getText().toString().startsWith("设置")) {serverIp = edtServerIp.getText().toString();edtServerIp.setEnabled(false);btnConnectServer.setEnabled(true);btnSetAndEditIP.setText("修改\n服务器IP");}else {// 修改\n服务器IPedtServerIp.setEnabled(true);btnConnectServer.setEnabled(false);btnSetAndEditIP.setText("设置\n服务器IP");}break;case R.id.btnConnectServer:// 连接服务器if (serverIp.length() <= 7) {showMessage("服务器 IP 地址输入不合法");}else {if (socket != null) {showMessage("服务器已连接!!");}else{ try { socket = new Socket(serverIp, 20000); // 客户端启动ClientThread线程不断读取来自服务器的数据 new Thread(new ClientThread(socket, handler)).start(); os = socket.getOutputStream(); showMessage("服务器连接成功!!"); btnDisConnectServer.setEnabled(true); } catch (Exception e) { showAlertDialog("服务器连接失败!!"); e.printStackTrace(); }}}break;case R.id.btnDisConnectServer:if (socket != null) {if(os != null){try {os.write(("QUIT\n").getBytes());socket.close();btnDisConnectServer.setEnabled(false);socket = null;} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}break;case R.id.start:startPlayMusic();break;case R.id.stop:stopPlayMusic();break;case R.id.pause:pausePlayMusic();break;default:break;}}}; /** * 弹出信息显示框,如果点击Yes按钮,则向服务器端发送一个QUIT标志,向服务器提示Socket要释放 * @param str 弹出框中输出的信息 */ public void showAlertDialog(String str){ new AlertDialog.Builder(this).setIcon(R.drawable.menu_exit).setTitle("Notice").setMessage(str).setPositiveButton("Yes",new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog,int whichButton) {try {if(os != null)os.write(("QUIT\n").getBytes());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} }}).show(); } @Overrideprotected void onDestroy() {// TODO Auto-generated method stub super.onDestroy(); try {if(os != null)os.write(("QUIT\n").getBytes());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} if (mp3 != null) {mp3.stop();mp3.release();mp3 = null;}}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {// TODO Auto-generated method stubif (keyCode == KeyEvent.KEYCODE_BACK) {new AlertDialog.Builder(this).setIcon(R.drawable.menu_exit).setTitle("Notice").setMessage("Do you want to quit?").setNegativeButton("No",new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog,int which) {}}).setPositiveButton("Yes",new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog,int whichButton) {try {if(os != null)os.write(("QUIT\n").getBytes());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} //关闭程序ClientMainActivity.this.finish();Process.killProcess(Process.myPid());}}).show();return true;} else {return super.onKeyDown(keyCode, event);}}private void showMessage(String str){Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT).show();}}
大家求婚如有需要,可以尽情使用,O(∩_∩)O哈哈~
源码下载请点击。
0 0
- Android:手机做服务器控制多个手机客户端同时播放音乐(含源码)
- 使用手机控制PPT播放实现方法(含源码)
- 手机同时播放两个音乐 探讨二
- 手机同时播放两个音乐 探讨二
- 手机同时播放两个音乐 探讨二
- OpenWrt - MPDroid实现Android手机控制OpenWRT播放音乐
- 手机同时播放两个音乐之探讨一[JavaME]
- 手机同时播放两个音乐之探讨一[JavaME]
- 手机同时播放两个音乐之探讨一[JavaME]
- 手机E680同时播放两个音乐完美解决方案-真!
- mfc实现同时播放多个音乐
- android手机做服务端,多个手机进行交流
- Android 系统蓝牙 控制手机端音乐暂停 (AVRCP)
- Socket编程总结—Android手机服务器与多个Android手机客户端之间的通信(非阻塞)
- Socket编程总结—Android手机服务器与多个Android手机客户端之间的通信(非阻塞)
- Socket编程总结—Android手机服务器与多个Android手机客户端之间的通信(非阻塞)
- android手机控制电脑源码
- 【Android】Android手机控制电脑(PPT播放)
- 如何使运行于用户空间的CPU转入系统空间
- NSIS进阶教程(三)
- hbase HFile V3介绍
- Android逗比自学webservice(四)Eclipse Axis2插件的下载
- 十一周该天是本年的第几天
- Android:手机做服务器控制多个手机客户端同时播放音乐(含源码)
- windows命令提示符 参考 summarizing
- 将本地文件拷贝到hdfs上去,结果上错误:Name node is in safe mode
- 16 个 Linux 服务器监控命令
- 抛丸清理机的用途
- 使用WinHttp接口编程的心得
- android-ndk-r7的使用
- 求四个数的最大公约数
- 第十一周项目一星号图