一、前言:
一般情况下从TCP服务器读取数据是放在一个线程里读的,但是刷新界面又不得不放在线程外面,所以需要用消息传递把线程里从TCP里获得的数据传送出来,然后根据数据对页面进行相应的刷新。
二、业务逻辑:
这里包含2个layout,第一个用于登陆的(即输入服务器对应的IP和端口号),点击确定进行跳转到相应的监控界面,监控界面包括加热、关闭、和显示温度3个按钮,以及一个用于绘制温度的SurfaceView。
三、详细介绍:
3-1、2个activity介绍:
登陆页面对应的activity,从上面的代码可以看出:29~31行使用intent进行页面跳转,然后所有逻辑均在ControlActivity里实现了。
1 public class MainActivity extends ActionBarActivity 2 { 3 private final String TAG = "MainActivity"; 4 private EditText et01; 5 private EditText et02; 6 private Button btOK; 7 private Button btCancel; 8 public static String userIP = "192.168.1.130"; //IP和端口号 9 public static int userPort = 8000; 10 public static int wen_du; //当前温度 11 public static int shui_wei; //当前水位 12 public static int state; //当前状态0关闭;1烧水;2保温 13 @Override 14 protected void onCreate(Bundle savedInstanceState) { 15 super.onCreate(savedInstanceState); 16 setContentView(R.layout.activity_main); 17 et01 = (EditText)findViewById(R.id.et_01); 18 et02 = (EditText)findViewById(R.id.et_02); 19 btOK = (Button)findViewById(R.id.bt_OK); 20 btCancel = (Button)findViewById(R.id.bt_Cancel); 21 22 23 btOK.setOnClickListener(new OnClickListener(){ 24 public void onClick(View v) 25 { 26 //userIP = et01.getText().toString(); 27 //userPort = Integer.parseInt(et02.getText().toString()); 28 //跳到控制界面 29 Intent intent = new Intent(MainActivity.this,ControlActivity.class); 30 Log.i(TAG, "跳转前"); 31 startActivity(intent); 32 } 33 }); 34 btCancel.setOnClickListener(new OnClickListener(){ 35 public void onClick(View v) 36 { 37 et01.setText(""); 38 et02.setText(""); 39 } 40 }); 41 42 } 43 44 45 @Override 46 public boolean onCreateOptionsMenu(Menu menu) { 47 // Inflate the menu; this adds items to the action bar if it is present. 48 getMenuInflater().inflate(R.menu.main, menu); 49 return true; 50 } 51 52 @Override 53 public boolean onOptionsItemSelected(MenuItem item) { 54 // Handle action bar item clicks here. The action bar will 55 // automatically handle clicks on the Home/Up button, so long 56 // as you specify a parent activity in AndroidManifest.xml. 57 int id = item.getItemId(); 58 if (id == R.id.action_settings) { 59 return true; 60 } 61 return super.onOptionsItemSelected(item); 62 } 63 }
另一个activity的框架如下图:主要的有①、②、③三个函数,另外三个是Callback附带要实现的。其主要逻辑为:在onCreate中实例化按钮和surfaceView,然后对按钮进行事件绑定;每当按钮事件触发,则启动线程和TCP服务器进行通信;线程将处理的结果通过msg传给Handler,Handler根据相应消息来更新页面。
全部代码:1 public class ControlActivity extends Activity implements Callback { 2 3 private final String TAG = "ControlActivity"; 4 private final String mAddress = MainActivity.userIP; 5 private final int mPort = MainActivity.userPort; 6 private Socket socket = null; 7 private Button btHeat,btShut,btUpdata; 8 private SurfaceView mSurface; //绘图区 9 private SurfaceHolder mHolder; 10 //消息句柄(线程里无法进行界面更新,所以要把消息从线程里发送出来在消息句柄里进行处理) 11 public Handler myHandler = new Handler() { 12 @Override 13 public void handleMessage(Message msg) 14 { 15 Bundle bundle = msg.getData(); 16 String now = bundle.getString("msg"); 17 //SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式 18 if (msg.what == 0x01) 19 { 20 toast_show("饮水机开始加热!"); 21 } 22 else if (msg.what == 0x02) 23 { 24 toast_show("饮水机关闭!"); 25 } 26 else if (msg.what == 0x03) 27 { 28 toast_show("饮水机实时状态更新!"+" "+MainActivity.wen_du+" "+MainActivity.shui_wei); 29 draw(MainActivity.wen_du); 30 } 31 else 32 { 33 toast_show("出现错误!"); 34 } 35 } 36 //toast显示用 37 private void toast_show(String msg) { 38 Toast toast = Toast.makeText(getApplicationContext(), 39 msg, Toast.LENGTH_LONG); 40 toast.setGravity(Gravity.CENTER, 0, 0); 41 toast.show(); 42 } 43 //画图像 44 private void draw(int wen_du) { 45 int y = 260 - wen_du * 2; 46 Canvas canvas = mHolder.lockCanvas(); 47 Paint mPaint = new Paint(); 48 mPaint.setColor(Color.WHITE); 49 canvas.drawRect(40, 50, 60, 280, mPaint); 50 Paint paintCircle = new Paint(); 51 paintCircle.setColor(Color.RED); 52 Paint paintLine = new Paint(); 53 paintLine.setColor(Color.BLUE); 54 canvas.drawRect(40, y, 60, 280, paintCircle); 55 canvas.drawCircle(50, 300, 25, paintCircle); 56 int ydegree = 260; 57 int tem = 0;//刻度0~100 58 while (ydegree > 55) { 59 canvas.drawLine(60, ydegree, 67, ydegree, mPaint); 60 if (ydegree % 20 == 0) { 61 canvas.drawLine(60, ydegree, 72, ydegree, paintLine); 62 canvas.drawText(tem + "", 70, ydegree + 4, mPaint); 63 tem+=10; 64 } 65 ydegree = ydegree - 2; 66 } 67 mHolder.unlockCanvasAndPost(canvas);// 更新屏幕显示内容 68 } 69 }; 70 71 protected void onCreate(Bundle savedInstanceState) 72 { 73 super.onCreate(savedInstanceState); 74 setContentView(R.layout.control_activity); 75 btHeat = (Button)findViewById(R.id.bt_heat); 76 btShut = (Button)findViewById(R.id.bt_shut); 77 btUpdata = (Button)findViewById(R.id.bt_updata); 78 mSurface = (SurfaceView) findViewById(R.id.surface); 79 mHolder = mSurface.getHolder(); 80 mHolder.addCallback(this); 81 82 btHeat.setOnClickListener(new OnClickListener() { 83 @Override 84 public void onClick(View v) 85 { 86 String orderMsg="Heat"; 87 //启动线程 向服务器发送和接收信息 88 Log.i(TAG, "Start thread"); 89 new MyThread(orderMsg).start(); 90 } 91 }); 92 93 btHeat.setOnClickListener(new OnClickListener() { 94 @Override 95 public void onClick(View v) 96 { 97 String orderMsg="Heat"; 98 //启动线程 向服务器发送和接收信息 99 Log.i(TAG, "Start thread"); 100 new MyThread(orderMsg).start(); 101 } 102 }); 103 104 btShut.setOnClickListener(new OnClickListener() { 105 @Override 106 public void onClick(View v) 107 { 108 String orderMsg="Shut"; 109 //启动线程 向服务器发送和接收信息 110 Log.i(TAG, "Start thread"); 111 new MyThread(orderMsg).start(); 112 } 113 }); 114 115 btUpdata.setOnClickListener(new OnClickListener() { 116 @Override 117 public void onClick(View v) 118 { 119 String orderMsg="Updata"; 120 //启动线程 向服务器发送和接收信息 121 Log.i(TAG, "Start thread"); 122 new MyThread(orderMsg).start(); 123 } 124 }); 125 } 126 127 class MyThread extends Thread 128 { 129 String orderMsg; 130 MyThread(String str) 131 { 132 orderMsg=str; 133 } 134 @SuppressLint("SimpleDateFormat") 135 public void run() 136 { 137 OutputStream out = null; 138 InputStream in = null; 139 DataInputStream DataIn = null;//数据传输输入输出流 140 DataOutputStream DataOut = null; 141 byte data_of_get_server = 0;//从服务器返回的数据 142 Message msg = new Message();//消息 143 Bundle bundle = new Bundle(); 144 bundle.clear(); 145 try 146 { 147 socket = new Socket(); 148 socket.connect(new InetSocketAddress(mAddress, mPort), 8000); 149 150 //输入输出流实例化 151 out=socket.getOutputStream(); 152 in=socket.getInputStream(); 153 DataIn = new DataInputStream(in); 154 DataOut=new DataOutputStream(out); 155 156 //读取服务器的返回数据 157 //服务器采用单byte数据进行发送 158 /* 159 TCP客户端:输入命令从服务器获得数据 160 PS:服务器只接受1个char,返回也是一个char,上述数据均为16进制 161 */ 162 if(orderMsg.equals("Heat"))//加热命令 163 { 164 msg.what = 0x01;//消息类别 165 DataOut.writeByte('0'); 166 Log.i(TAG, "flush 前"); 167 out.flush(); 168 Log.i(TAG, "flush 后"); 169 data_of_get_server=DataIn.readByte(); 170 Log.i(TAG, "读取数据后"); 171 } 172 else if(orderMsg.equals("Shut")) 173 { 174 msg.what = 0x02;//消息类别 175 DataOut.writeByte('0');//停止加热 176 out.flush(); 177 data_of_get_server=DataIn.readByte(); 178 } 179 else if(orderMsg.equals("Updata")) 180 { 181 msg.what = 0x03;//消息类别 182 DataOut.writeByte('w');//刷新温度信息 183 out.flush(); 184 data_of_get_server=DataIn.readByte(); 185 MainActivity.wen_du=data_of_get_server; 186 187 DataOut.writeByte('s');//刷新深度信息 188 out.flush(); 189 data_of_get_server=DataIn.readByte(); 190 MainActivity.shui_wei=data_of_get_server; 191 } 192 //将消息发送给UI刷新消息句柄处 193 bundle.putByte("msg",data_of_get_server); 194 msg.setData(bundle); 195 myHandler.sendMessage(msg); 196 } 197 catch(Exception e){ 198 e.printStackTrace(); 199 //Intent intent = new Intent(ControlActivity.this,MainActivity.class); 200 //Log.i(TAG, "跳转前"); 201 //startActivity(intent); 202 //将消息发送给UI刷新消息句柄处 203 msg.what = 0x04;//消息类别 204 bundle.putByte("msg",data_of_get_server); 205 msg.setData(bundle); 206 myHandler.sendMessage(msg); 207 }finally{ 208 try{ 209 if(in!=null)in.close();Log.i(TAG, "读取数据后1"); 210 if(out!=null)out.close();Log.i(TAG, "读取数据后2"); 211 if(DataOut!=null)DataOut.close();Log.i(TAG, "读取数据后3"); 212 if(DataIn!=null)DataIn.close();Log.i(TAG, "读取数据后4"); 213 if(socket!=null)socket.close();Log.i(TAG, "读取数据后5"); 214 }catch(Exception e){} 215 } 216 } 217 } 218 219 @Override 220 public void surfaceCreated(SurfaceHolder holder) { 221 // TODO Auto-generated method stub 222 223 } 224 225 @Override 226 public void surfaceChanged(SurfaceHolder holder, int format, int width, 227 int height) { 228 // TODO Auto-generated method stub 229 230 } 231 232 @Override 233 public void surfaceDestroyed(SurfaceHolder holder) { 234 // TODO Auto-generated method stub 235 236 } 237 }