[安卓] 9、线程、VIEW、消息实现从TCP服务器获取数据动态加载显示

简介:


 一、前言:

一般情况下从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根据相应消息来更新页面。

  全部代码:

3-2、消息传递详细介绍:

如下,第9-10行要加入回调函数;12-21、23-32、34-43以及45-54分别是几个按钮的点击监听函数,其中对于不同的情况,通过设置orderMsg进行区别,然后启动相应的线程和服务器通信。

复制代码
 1 protected void onCreate(Bundle savedInstanceState) 
 2 {
 3     super.onCreate(savedInstanceState);
 4     setContentView(R.layout.control_activity);
 5     btHeat = (Button)findViewById(R.id.bt_heat);
 6     btShut = (Button)findViewById(R.id.bt_shut);
 7     btUpdata = (Button)findViewById(R.id.bt_updata);
 8     mSurface = (SurfaceView) findViewById(R.id.surface);  
 9     mHolder = mSurface.getHolder();  
10     mHolder.addCallback(this);  
11     
12     btHeat.setOnClickListener(new OnClickListener() {
13         @Override
14         public void onClick(View v) 
15         {
16             String orderMsg="Heat";
17             //启动线程 向服务器发送和接收信息
18             Log.i(TAG, "Start thread");
19             new MyThread(orderMsg).start();
20         }
21     });
22     
23     btHeat.setOnClickListener(new OnClickListener() {
24         @Override
25         public void onClick(View v) 
26         {
27             String orderMsg="Heat";
28             //启动线程 向服务器发送和接收信息
29             Log.i(TAG, "Start thread");
30             new MyThread(orderMsg).start();
31         }
32     });
33     
34     btShut.setOnClickListener(new OnClickListener() {
35         @Override
36         public void onClick(View v) 
37         {
38             String orderMsg="Shut";
39             //启动线程 向服务器发送和接收信息
40             Log.i(TAG, "Start thread");
41             new MyThread(orderMsg).start();
42         }
43     });
44     
45     btUpdata.setOnClickListener(new OnClickListener() {
46         @Override
47         public void onClick(View v) 
48         {
49             String orderMsg="Updata";
50             //启动线程 向服务器发送和接收信息
51             Log.i(TAG, "Start thread");
52             new MyThread(orderMsg).start();
53         }
54     });
55 }
复制代码

从上面知道,我们必须有一个MyThread的类:构造函数就是把上面说的用于区分命令的orderMsg赋值给MyThread成员变量,然后在run函数中:11-14行来定义用于和TCP服务器通信的输入输出流;第15行的变量是记录从服务器返回的数据(这里服务器每次只返回一个byte类,这个取决于通信协议的约定!);第16-18行实例化的msg、bundle用于传送消息,对应的第77-80行,想要发送消息要:①首先设置消息类别(这里出错消息类别为0x04:msg.what = 0x04;加热为0x01;停止加热为0x02等)②然后用bundle将信息合成bundle.putByte("msg",data_of_get_server);其中第一个string为key,第二个为value ③然后将msg的信息设置为handle,即:msg.setData(bundle); ④最后用myHandler将消息发出:myHandler.sendMessage(msg);

复制代码
 1 class MyThread extends Thread 
 2 {
 3     String orderMsg;
 4     MyThread(String str)
 5     {
 6         orderMsg=str;
 7     }
 8     @SuppressLint("SimpleDateFormat")
 9     public void run()
10     {
11         OutputStream out = null;
12         InputStream in = null;
13         DataInputStream DataIn = null;//数据传输输入输出流
14         DataOutputStream DataOut = null;
15         byte data_of_get_server = 0;//从服务器返回的数据
16         Message msg = new Message();//消息
17         Bundle bundle = new Bundle();
18         bundle.clear();
19         try
20         {
21             socket = new Socket();
22             socket.connect(new InetSocketAddress(mAddress, mPort), 8000);
23     
24             //输入输出流实例化
25             out=socket.getOutputStream();
26             in=socket.getInputStream();
27             DataIn = new DataInputStream(in);
28             DataOut=new DataOutputStream(out);
29             
30             //读取服务器的返回数据
31             //服务器采用单byte数据进行发送
32             /*
33             TCP客户端:输入命令从服务器获得数据
34             PS:服务器只接受1个char,返回也是一个char,上述数据均为16进制
35             */
36             if(orderMsg.equals("Heat"))//加热命令
37             {
38                 msg.what = 0x01;//消息类别
39                 DataOut.writeByte('0');    
40                 Log.i(TAG, "flush 前");
41                 out.flush();
42                 Log.i(TAG, "flush 后");
43                 data_of_get_server=DataIn.readByte();
44                 Log.i(TAG, "读取数据后");
45             }
46             else if(orderMsg.equals("Shut"))
47             {
48                 msg.what = 0x02;//消息类别
49                 DataOut.writeByte('0');//停止加热
50                 out.flush();
51                 data_of_get_server=DataIn.readByte();
52             }
53             else if(orderMsg.equals("Updata"))
54             {
55                 msg.what = 0x03;//消息类别
56                 DataOut.writeByte('w');//刷新温度信息
57                 out.flush();
58                 data_of_get_server=DataIn.readByte();
59                 MainActivity.wen_du=data_of_get_server;
60                 
61                 DataOut.writeByte('s');//刷新深度信息
62                 out.flush();
63                 data_of_get_server=DataIn.readByte();
64                 MainActivity.shui_wei=data_of_get_server;
65             }
66             //将消息发送给UI刷新消息句柄处
67             bundle.putByte("msg",data_of_get_server);
68             msg.setData(bundle);
69             myHandler.sendMessage(msg);
70         }
71         catch(Exception e){
72             e.printStackTrace();
73             //Intent intent = new Intent(ControlActivity.this,MainActivity.class);
74             //Log.i(TAG, "跳转前");
75             //startActivity(intent);
76             //将消息发送给UI刷新消息句柄处
77             msg.what = 0x04;//消息类别
78             bundle.putByte("msg",data_of_get_server);
79             msg.setData(bundle);
80             myHandler.sendMessage(msg);
81         }finally{
82             try{
83                 if(in!=null)in.close();Log.i(TAG, "读取数据后1");
84                 if(out!=null)out.close();Log.i(TAG, "读取数据后2");    
85                 if(DataOut!=null)DataOut.close();Log.i(TAG, "读取数据后3");
86                 if(DataIn!=null)DataIn.close();Log.i(TAG, "读取数据后4");
87                 if(socket!=null)socket.close();Log.i(TAG, "读取数据后5");
88             }catch(Exception e){}
89         }
90     }
91 }
复制代码

接下来就是myHandler了:第6-7行是取消息的过程,其和放消息有种逆过程的感觉,首先用bundle取出消息:Bundle bundle = msg.getData(); 然后通过String now = bundle.getString("msg");获得键值为“msg”的value,然后分类处理即可。其中toast_show是自己封装的用于显示toast消息的函数,draw是用来绘制那个温度计的函数。

复制代码
 1 //消息句柄(线程里无法进行界面更新,所以要把消息从线程里发送出来在消息句柄里进行处理)
 2 public Handler myHandler = new Handler() {
 3     @Override
 4     public void handleMessage(Message msg) 
 5     {
 6         Bundle bundle = msg.getData();
 7         String now = bundle.getString("msg");
 8         //SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
 9         if (msg.what == 0x01) 
10         {
11             toast_show("饮水机开始加热!");
12         }
13         else if (msg.what == 0x02) 
14         {
15             toast_show("饮水机关闭!");
16         }
17         else if (msg.what == 0x03) 
18         {
19             toast_show("饮水机实时状态更新!"+"  "+MainActivity.wen_du+"  "+MainActivity.shui_wei);
20             draw(MainActivity.wen_du);
21         }
22         else
23         {
24             toast_show("出现错误!");
25         }
26     }
27     //toast显示用
28     private void toast_show(String msg) {
29         Toast toast = Toast.makeText(getApplicationContext(),
30                  msg, Toast.LENGTH_LONG);
31         toast.setGravity(Gravity.CENTER, 0, 0);
32         toast.show();
33     }
34     //画图像
35     private void draw(int wen_du) {  
36         int y = 260 - wen_du * 2;  
37         Canvas canvas = mHolder.lockCanvas();  
38         Paint mPaint = new Paint();  
39         mPaint.setColor(Color.WHITE);  
40         canvas.drawRect(40, 50, 60, 280, mPaint);  
41         Paint paintCircle = new Paint();  
42         paintCircle.setColor(Color.RED);  
43         Paint paintLine = new Paint();  
44         paintLine.setColor(Color.BLUE);  
45         canvas.drawRect(40, y, 60, 280, paintCircle);  
46         canvas.drawCircle(50, 300, 25, paintCircle);  
47         int ydegree = 260;  
48         int tem = 0;//刻度0~100
49         while (ydegree > 55) {  
50             canvas.drawLine(60, ydegree, 67, ydegree, mPaint);  
51             if (ydegree % 20 == 0) {  
52                 canvas.drawLine(60, ydegree, 72, ydegree, paintLine);  
53                 canvas.drawText(tem + "", 70, ydegree + 4, mPaint);  
54                 tem+=10;  
55             }  
56             ydegree = ydegree - 2;  
57         }  
58         mHolder.unlockCanvasAndPost(canvas);// 更新屏幕显示内容  
59     }  
60 };
复制代码

 

 

 

 本文链接:http://www.cnblogs.com/zjutlitao/p/4230360.html

 更多精彩:http://www.cnblogs.com/zjutlitao/

 工程链接:http://pan.baidu.com/s/1i3zhMVr 

 GitHub链接:https://github.com/beautifulzzzz/SmartDrink 



本文转自beautifulzzzz博客园博客,原文链接:http://www.cnblogs.com/zjutlitao/p/4230360.html,如需转载请自行联系原作者

相关文章
|
8天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
28天前
|
存储 前端开发 Java
【C++ 多线程 】C++并发编程:精细控制数据打印顺序的策略
【C++ 多线程 】C++并发编程:精细控制数据打印顺序的策略
43 1
|
2月前
|
存储 安全 PHP
通过eXtplorer+cpolar,搭建个人云存储并实现访问内网服务器数据
通过eXtplorer+cpolar,搭建个人云存储并实现访问内网服务器数据
39 0
|
2月前
|
网络协议 安全 测试技术
手撕测试tcp服务器效率工具——以epoll和io_uring对比为例
手撕测试tcp服务器效率工具——以epoll和io_uring对比为例
40 2
|
3天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android's AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
5 0
|
3天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
5 0
|
17天前
|
XML Java Android开发
Android每点击一次按钮就添加一条数据
Android每点击一次按钮就添加一条数据
21 1
|
22天前
|
弹性计算 网络安全 虚拟化
ECS数据问题之升级配置预防数据丢失如何解决
ECS(Elastic Compute Service,弹性计算服务)是云计算服务提供商提供的一种基础云服务,允许用户在云端获取和配置虚拟服务器。以下是ECS服务使用中的一些常见问题及其解答的合集:
|
25天前
|
安全 数据处理 C#
C# Post数据或文件到指定的服务器进行接收
C# Post数据或文件到指定的服务器进行接收
|
1月前
|
消息中间件 关系型数据库 MySQL
Flink CDC产品常见问题之把flink cdc同步的数据写入到目标服务器失败如何解决
Flink CDC(Change Data Capture)是一个基于Apache Flink的实时数据变更捕获库,用于实现数据库的实时同步和变更流的处理;在本汇总中,我们组织了关于Flink CDC产品在实践中用户经常提出的问题及其解答,目的是辅助用户更好地理解和应用这一技术,优化实时数据处理流程。