经过两三个星期的艰难调试,自己渣渣所以进步慢勿笑。这项工作对练习Java Socket和Java Thread很有帮助。
抱着练习涨经验的心态,写了三个版本的用安卓手机远程控制电脑的程序,可以作为PPT助手使用,也可以直接控制操作电脑,类似的功能应用商店都有APP下载,其中猎豹wifi的那个远程遥控就很不错,如果增加文件传输可需可以替代QQ里我的电脑功能,这里只是复现最简单的功能,有些粗敝,但还是学到了不少的东西,所以总结一下以免忘记了,再贴一些自己以前不知道的代码供以后查阅。
三个版本分别是基于TCP协议带有屏幕映射的鼠标控制器,基于UDP协议用触摸屏控制鼠标位移不带屏幕共享和基于UDP用手机的陀螺仪角速度控制鼠标位移,其中以第三种方案具有独创性,具体介绍请看我的另一篇博文,此文主要介绍第一种方案和一些经典代码。
此设计采用客户服务器的通信方式,客户端(手机)输入服务器端(电脑)的IP地址和端口号即可建立手机与电脑的通信,电脑将屏幕截图和鼠标指针的位置发给手机(不断刷新),手机显示电脑屏幕画面并通过触摸手机或者按键可以实现对电脑上鼠标的漫游和点击功能,并能实现实时显示。类似一个远程控制吧。先看效果图吧
工程文件可以到我的资源下载http://download.csdn.net/detail/u010297828/8785219。
第二个工程文件:http://download.csdn.net/detail/u010297828/8785583
启示:
1.尽量将开辟读写线程来处理数据,主线程只负责UI更新;读写数据线程需要循环执行时最好需要休眠在开启下一次运行,否则数据更新过快导致阻塞;Java Socket.accept()本身就是一个阻塞线程,如果没有客户端响应则一直阻塞等待;
2.获得本机IP的java代码,一般一个主机会有多个IP,而这段代码是获得本机所有IP
public void getServerIp() {
String address;
Enumeration netInterfaces;
NetworkInterface ni;
Enumeration cardipaddress;
InetAddress ip;
try {
netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
ni = (NetworkInterface) netInterfaces.nextElement();
cardipaddress = ni.getInetAddresses();
while (cardipaddress.hasMoreElements()) {
ip = (InetAddress) cardipaddress.nextElement();
if (!ip.getHostAddress().equalsIgnoreCase("127.0.0.1")) {
address = ip.getHostAddress();
localIPCheck.addItem(address);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
3.java.awt.Robot类
Robot类可以完成很多工作,尤其是鼠标动作,如下,还有哦keyPress等方法
mRobot.mousePress(InputEvent.BUTTON1_MASK);// 按下左键
mRobot.mouseRelease(InputEvent.BUTTON1_MASK);// 释放左键
mRobot.delay(5);
mRobot.mousePress(InputEvent.BUTTON3_MASK);// 按下右键
mRobot.mouseRelease(InputEvent.BUTTON3_MASK);// 释放右键
mRobot.mouseMove(int x,int y);//鼠标移动到(x,y)处
BufferedImage cursor = ImageIO.read(new File(imgPath));//将图片加载到内存中
Point point = MouseInfo.getPointerInfo().getLocation();
BufferedImage bfImg = robot.createScreenCapture(screenRect);//获取电脑屏幕截图但不包含光标
bfImg.createGraphics().drawImage(cursor,point.x,point.y,null);//将cursor画到(x,y)的位置
4.获取屏幕矩形
private Dimension dimension;
private int pcScreenWidth,pcScreenHeight;
private Rectangle screenRect;
dimension = Toolkit.getDefaultToolkit().getScreenSize();//获取屏幕大小
pcScreenWidth = dimension.width;
pcScreenHeight = dimension.height;
screenRect = new Rectangle(pcScreenWidth,pcScreenHeight);
5.android手机检查网络状态
manifest中配置:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
//检查网络状态
ConnectivityManager con=(ConnectivityManager)getSystemService(LoginActivity.CONNECTIVITY_SERVICE);
boolean wifi=con.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnectedOrConnecting();
boolean internet=con.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isConnectedOrConnecting();
if(wifi|internet){
//执行相关操作
new LoginThread().start();
}else{
Toast.makeText(getApplicationContext(),
"亲,网络连了么?", Toast.LENGTH_LONG).show();
}
6.sharedpreferences的使用,用来保存用户名等
//检测本地是否保存有ADD和PORT,如果保存则显示出来
SharedPreferences preferences = this.getSharedPreferences(Constant.FILE_NAME,MODE_PRIVATE);
ADD = preferences.getString("ADD", null); //defValue Value to return if this preference does not exist.
PORT = preferences.getInt("PORT", 20155);
if (ADD !=null){ //ADD内有返回值
serverIPText.setText(ADD);
portNumText.setText(String.valueOf(PORT));
}
//将此刻的数值保存在本地
serverIP = serverIPText.getText().toString();
portNum = Integer.parseInt(portNumText.getText().toString());
SharedPreferences sp = getSharedPreferences(
Constant.FILE_NAME, MODE_PRIVATE);
Editor editor = sp.edit();
editor.putString("ADD", serverIP);
editor.putInt("PORT", portNum);
editor.commit();
7.获取手机的分辨率
private DisplayMetrics dm;
private int phoneScreenWidth, phoneScreenHeight;
dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
phoneScreenWidth = dm.widthPixels;
phoneScreenHeight = dm.heightPixels;
8.SurfaceView实例,画图函数
public void draw() {
Canvas canvas = mHolder.lockCanvas();
if (canvas == null || mHolder == null){
return;
}
if (bitmap != null){
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(bitmap, RectSrc, RectDst, null);
}
mHolder.unlockCanvasAndPost(canvas);
}
9.横屏设置
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"//设置全屏
android:launchMode="singleTask"
android:screenOrientation="landscape" //横屏
10.返回键对话框
public boolean onKeyDown(int keyCode, KeyEvent e) {
// Log.i("keyCode", String.valueOf(keyCode));
// Log.i("e.getUnicodeChar", String.valueOf(e.getUnicodeChar()));
// Log.i("toString()", e.toString());
// 按下键盘上返回按钮
if (keyCode == KeyEvent.KEYCODE_BACK) {
new AlertDialog.Builder(this)
.setTitle("Quit")
.setMessage("Quit?")
.setNegativeButton("No",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
})
.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
Intent exit = new Intent(Intent.ACTION_MAIN);
exit.addCategory(Intent.CATEGORY_HOME);
exit.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(exit);
System.exit(0);
}
}).show();
} else {
sendThread.setKeyValue((char) e.getUnicodeChar());
}
return true;
}
11.弹出对话框
// 设置服务器IP和Port
public void config_server(){
LayoutInflater inflater = (LayoutInflater) MainActivity.this.
getSystemService(LAYOUT_INFLATER_SERVICE);
final View view = inflater.inflate(R.layout.dialog, null);
serverIPText = (EditText)view.findViewById(R.id.editText1);
portNumText = (EditText)view.findViewById(R.id.editText2);
save_ip();
new AlertDialog.Builder(MainActivity.this).setTitle("set PC")
.setView(view)
.setPositiveButton("OK",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface v, int arg1){
}
}).show();
}
12.Sensor的注册和使用
private SensorManager sensorManager;
private Sensor sensorGyro;
private SensorEventListener mySensorEventListener;
sensorGyro = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
sensorManager.registerListener(mySensorEventListener, sensorGyro,
SensorManager.SENSOR_DELAY_GAME);
sensorManager.unregisterListener(mySensorEventListener);
private void sensorAction() {
// TODO Auto-generated method stub
sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mySensorEventListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
//获得值之后,你就可以进行相应的处理啦
if (sendThread != null) {
sendThread.setPointX((int)(6*z));
sendThread.setPointY((int)(8*x));
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
};
}