安卓网络编程(Socket、WebView控件)

本文档展示了如何使用Java开发Socket服务端和客户端,包括安卓客户端的Socket编程,以及如何在安卓中接收网络数据并实时更新UI。讲解了在安卓中使用Handler解决非UI线程修改控件的问题,并给出了网络数据接收后更新TextView的示例。同时提到了安卓webView的使用,用于展示网页内容。
摘要由CSDN通过智能技术生成

JavaSocket服务端开发

在这里插入图片描述

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;


public class Test {
	public static void main(String[] args) {

		//创建套接字,ip,端口号
		try {//try...catch是JAVA内部错误管理机制,写完new ServerSocket就会自动提示 点击add就自动添加进来  
			ServerSocket socket = new ServerSocket(8888);
			System.out.println("socket套接字创建成功,等待连接");
			
			//不断和新客户端建立连接
			while(true){//死循环写法  和C区别
				final Socket con = socket.accept();
				System.out.println("有客户端接入");

				//new Thread(...).start()  有客户端接入就创建线程去对接
				new Thread(new Runnable() {
					//写完自动跳出这个run函数 补全这个线程要做的事情	
					public void run() {
						// TODO Auto-generated method stub
						InputStream in;
						try {
							//由于con的定义是在try外面的 鼠标放在上面,点击改变作用域  前面自动出现final关键字
							in = con.getInputStream();//获取输入流,用来读取数据  类似C中读取fd
							int len = 0;//定义写到try...catch里面 注意作用域
							byte[] data = new byte[128];
							len = in.read(data);//读取放到data里面
							                                     //输出data中从0到第len个字节 因为data中有128字节,防止输出多余乱码
							System.out.println("读到消息:"+new String(data,0,len));//输出里面直接写data输出可能会乱码
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					
					}
				}).start();
				
				
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

运行代码验证:
在这里插入图片描述

JavaSocket客户端开发

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;


public class Test {
	public static void main(String[] args) {
		
		try {//try...catch也是自动产生的错误捕捉机制
			Socket client = new Socket("192.168.1.11", 8080);//这样就和客户端建立连接了
			OutputStream out = client.getOutputStream();//获得数据发送通道
			
			Scanner sc = new Scanner(System.in);
			String message = sc.next();//获取字符串用next() 如果客户端发送的内容有空格,空格及后面的字符串就收不到了
			
			out.write(message.getBytes());//发送通道,发送数据  会提示你API的使用方法,根据规则进行填充就行
			
			
			//接收客户端的消息
			InputStream in = client.getInputStream();//获得数据接受通道
			int len;
			byte[] data = new byte[128];
			len = in.read(data);//接受通道接受数据
			System.out.println("获得服务端返回数据是:"+new String(data,0,len));
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

上面写的socket通信代码,只能发送、接收一次,这没关系,因为安卓机制就是UI不断刷新,点击APP按键就建立一次新的连接了。

安卓Socket客户端开发

运行效果:
在这里插入图片描述

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/fh"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/turnLeft"
        android:layout_centerHorizontal="true"
        android:onClick="sendMessage"
        android:text="前进" />

    <Button
        android:id="@+id/turnR"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/fh"
        android:layout_marginLeft="32dp"
        android:layout_toRightOf="@+id/fh"
        android:onClick="sendMessage"
        android:text="右转" />

    <Button
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/fh"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="175dp"
        android:onClick="sendMessage"
        android:text="后退" />

    <Button
        android:id="@+id/turnLeft"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/back"
        android:layout_marginBottom="61dp"
        android:layout_toLeftOf="@+id/fh"
        android:onClick="sendMessage"
        android:text="左转" />

</RelativeLayout>

MainActivity.java

package com.example.socket.sgkbc;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

import com.example.socket.sgkbc.nets.NetUtils;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	public void sendMessage(View v) {

		switch (v.getId()) {
			case R.id.fh:
				NetUtils.sendMessageHandler("gofoward");
				break;
			case R.id.back:
				NetUtils.sendMessageHandler("goback");
				break;
			case R.id.turnLeft:
				NetUtils.sendMessageHandler("goLeft");
				break;
			case R.id.turnR:
				NetUtils.sendMessageHandler("goRight");
				break;

		}

	}

}

NetUtils.java

package com.example.socket.sgkbc.nets;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class NetUtils {

	public static void sendMessageHandler(final String command) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub

				try {
					Socket client = new Socket("192.168.101.158", 8888);
					OutputStream out = client.getOutputStream();// 获得数据发送通道
					out.write(command.getBytes());// 发送通道,发送数据

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();

	}

}

接收消息显示到控件上(解决安卓线程无法修改控件问题)

问题引入:
1、在安卓里开辟线程,要另起新建线程(不要直接使用ui的线程)。前面页面跳转有讲到,要在ui线程外操控ui,否则会崩溃。
2、新创建的线程只能修改一次控件内容(使用textView.setText(…)),安卓的线刷机制下用循环去不停改变控件显示内容会提示崩溃,只有初始线程可以。我们在网络通信里面需要不停去修改text控件的显示内容,我们需要解决非UI线程控制控件这个问题。解决的办法就是是使用Handler这个类。

下面我们来制作一个倒计时软件,实现非UI线程对控件的修改。

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
  	android:background="#000000"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="40dp"
        android:textColor="#ffffff"
        android:textStyle="bold"
        android:text="10s" />

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="testFunc"
        android:text="begin" />

</RelativeLayout>

MainActivity.java

package com.example.sgkbc;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {

	public TextView textView;//定义控件 为了关联到控件    ctl+shift+O 控件导包
	
	public Handler h;//导包ctl+shift+o 选择OS的那个包
	
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
                  //根据提示类型强转			
        textView = (TextView) findViewById(R.id.textView); //通过ID关联到控件
       
        h = new Handler(){//有点像UI主线程的家里的电话,处理一些其他进程无法处理的事件。
        	@Override
        	public void handleMessage(Message msg) {//一旦“接到电话”就会被调用
        		// TODO Auto-generated method stub
        		super.handleMessage(msg);
        		textView.setText(msg.what+"s");//设置text控件显示内容
        	}
        };
    }
    
    public void testFunc(View V)
    {
    	//new Thread(new Runnable() {} ).start();	
    	new Thread(new Runnable() {//安卓里开辟线程  要另起新建线程
    							   //(不要直接使用ui的线程) 前面页面跳转有讲到 ui线程外操控ui
				
				@Override
				public void run() {
					for (int i = 10; i >=0 ; i--) {	
							Message msg = new Message();
							msg.what = i;
							//"打电话"  将要处理的事件交给UI线程的Handler去做。 有点像进程间通信
							h.sendMessage(msg);
			    		try {
			    			//每隔一秒发一次消息 通知你修改UI
							Thread.sleep(1000);//sleep的try...catch机制  安卓的sleep都是线程机制实现的 
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}).start();	
    } 
    
}

点击begin,开始倒计时10秒。运行效果如下:
在这里插入图片描述

另外,我们不断点击begin,可以不断使用这个定时器,我们并没有把按钮控件放到一个循环里面,这是因为安卓的不断刷新界面机制。

Android网络接收数据并刷新界面显示

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   	android:background="#000000"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/fh"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="sendMessage"
        android:text="发起网络请求" />
    
    <TextView 
        android:id="@+id/tx"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="35dp"
        android:layout_centerInParent="true"
        android:textColor="#ffffff"
        />

</RelativeLayout>

MainActivity.java

package com.example.socket.sgkbc;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.TextView;

import com.example.socket.sgkbc.nets.NetUtils;

public class MainActivity extends Activity {

	Handler handler;
	TextView tx;//定义控件  为了关联到xml中的Text控件
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		    //强制转换 根据提示
		tx = (TextView) findViewById(R.id.tx);//关联到这个控件 通过ID号
		
		handler = new Handler(){
				@Override
				public void handleMessage(Message msg) {
					// TODO Auto-generated method stub
					super.handleMessage(msg);
					
					Bundle b = msg.getData();
					String string  = b.getString("msg");
					
					tx.setText(string);
				}
		};
	}

	public void sendMessage(View v) {

		switch (v.getId()) {
			case R.id.fh:
				NetUtils.sendMessageHandler("gofoward",handler);
				break;
	
		}

	}

}

NetUtils.java

package com.example.socket.sgkbc.nets;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class NetUtils {
                        //“打电话”
	public static void sendMessageHandler(final String command, final Handler h) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub

				try {
					Socket client = new Socket("192.168.0.7", 8888);
					OutputStream out = client.getOutputStream();// 获得数据发送通道
					out.write(command.getBytes());// 发送通道,发送数据
					
					
					int len;
					
					InputStream in = client.getInputStream();//获得数据接收通道
					byte[] data = new byte[128];
					len = in.read(data);
					String str = new String(data,0,len);
					Message msg = new Message();
					
					Bundle b = new Bundle();
					b.putString("msg", str);//获得到的东西放进来
					msg.setData(b);//msg通过setData把Bundle放进来
					
					h.sendMessage(msg);
					

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();

	}

}

运行效果:
在这里插入图片描述

安卓webView

显示网址、上网,也可用作显示视频监控画面等。
参照博文:Android WebView 的使用(超详细用法)

控件位置:
在这里插入图片描述

首先需要打开internet访问权限:
方法一:直接敲代码
在这里插入图片描述
方法二:手动添加权限,上面的权限代码将自动填充。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

xml代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    tools:context=".MainActivity" >

    <LinearLayout 
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        
        >
        <EditText 
            android:id="@+id/ed"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:hint="请输入网址"
            />
    </LinearLayout>
    
    
    <WebView
        android:layout_below="@id/ll"
        android:id="@+id/webView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

在这里插入图片描述
java代码:

package com.example.sgkbc.baidu;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
                         //根据提示强转
        final WebView wb = (WebView) findViewById(R.id.webView1);
        //系统默认会通过手机浏览器打开网页,为了能够直接通过WebView显示网页,则必须设置
        wb.setWebViewClient(new WebViewClient());
        
        final EditText ed = (EditText) findViewById(R.id.ed);
        ed.setOnEditorActionListener(new TextView.OnEditorActionListener() {
			
			@Override
				public boolean onEditorAction(TextView arg0, int arg1, KeyEvent event) {
				// TODO Auto-generated method stub
				String str = ed.getText().toString();
				wb.loadUrl(str);//加载的网址 
	
				return (event.getKeyCode() == KeyEvent.KEYCODE_ENTER); 
			}
		});
                     
        
    }

}

运行:输入百度网址,回车效果如下。
在这里插入图片描述

智能家居你APP页面开发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行稳方能走远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值