目录
一、安卓Socket客户端
.java
package com.example.ycy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void handlerMessage(){
try {
//1.创建客户端套接字,填充ip地址和端口号
Socket client = new Socket("192.168.0.15",8888);
//2.获取输出流,用来发送数据
OutputStream out = client.getOutputStream();
String message = "message from Andriod";
//4.发送数据
//用getBytes()方法将字符串转化为字节数组
out.write(message.getBytes());
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void sendMessage(View v){
new Thread(new Runnable() { //网络线程不能跑在主线程,需要再创建一个线程
@Override
public void run() {
// TODO Auto-generated method stub
handlerMessage();
}
}).start();
}
}
.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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="sendMessage"
android:text="发送消息"
/>
</RelativeLayout>
效果显示:
注意:
网络访问不能在主线程(UI线程)中进行,否则程序会崩溃,要创建线程来发起网络访问。
二、安卓Socket客户端优化(小车遥控器拓展)
代码:
package com.example.ycy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void handlerMessage(final String message){
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
//1.创建客户端套接字,填充ip地址和端口号
Socket client = new Socket("192.168.0.15",8888);
//2.获取输出流,用来发送数据
OutputStream out = client.getOutputStream();
//4.发送数据
//用getBytes()方法将字符串转化为字节数组
out.write(message.getBytes());
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public void sendMessage(View v){
switch(v.getId()){
case R.id.fw:
handlerMessage("goForward");
break;
case R.id.bc:
handlerMessage("goBack");
break;
case R.id.lf:
handlerMessage("goLeft");
break;
case R.id.rt:
handlerMessage("goRight");
break;
}
}
}
效果显示:
三、Android非UI线程修改空间程序崩溃问题
如果我们想要不断刷新修改一个控件(比如文本控件)的内容,我们应该如何做呢?
既然要刷新,就必然会用到 sleep() 方法去睡眠等待刷新时间,但是在之前我们曾经出错过,sleep() 方法不能出现在 UI 线程里,否则程序会崩溃,那么我们就再创建一个线程来刷新修改控件内容:
.java
package com.example.ycy;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
public TextView textView; //关联TextView控件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView); //关联TextView控件
}
public void changeText(View v){
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
textView.setText("yangchenyanghandsome");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
}
.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" >
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView"
android:layout_below="@+id/textView"
android:layout_marginTop="34dp"
android:onClick="changeText"
android:text="修改文本" />
</RelativeLayout>
运行结果:
我们可以看到,程序又崩溃了。怎么办呢?
一种新的解决办法:Handler类(倒计时软件)
既然再新线程内不能修改控件,那么我们利用 Handler类 去处理 UI 线程和新线程无法处理的业务,就是在新线程中,我们将新线程不能处理的业务封装在重写了的 Handler类 中的 handleMessage() 方法中, 当在新线程中需要执行响应业务的时候,我们通过给 Handler 类的对象发送消息,触发这个事件,让handleMessage() 方法去处理响应的业务,这样就能解决这个问题,这里我们通过应用 Handler类 将以上功能修改为倒计时软件:
.java
package com.example.ycy;
import android.app.Activity;
import android.content.Intent;
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; //关联TextView控件
public Handler h;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView); //关联TextView控件
h = new Handler(){ //匿名内部类,UI主线程的家里的电话,接到电话去处理一些其他进程无法处理的事件
@Override
public void handleMessage(Message msg) { //区分事件类型
// TODO Auto-generated method stub
super.handleMessage(msg);
textView.setText(msg.what+"s");
}
};
}
public void changeText(View v){
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 10; i >= 0; i--) {
Message msg = new Message(); //为了传递参数i
msg.what = i;
//打电话把UI线程不能处理的事情交给UI线程的Handler去做
h.sendMessage(msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
}
.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"
android:background="#000000"
>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="50dp"
android:textColor="#ffffff"
android:text="10s" />
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:onClick="changeText"
android:background="#ffffff"
android:text="Begin" />
</RelativeLayout>
效果显示:
点击 Begin 前:
点击 Begin 后:
倒计时完毕:
四、Android网络接收数据并刷新界面(综合练习)
.java
package com.example.ycy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
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 {
Handler handler;
TextView tx;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tx = (TextView) findViewById(R.id.tx);
//这里是关于Handler处理文本框变化的代码
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
Bundle b = msg.getData(); //先把Bundle获取
String string = b.getString("msg"); //再把b中的msg读出来
tx.setText(string);
}
};
}
public void handlerMessage(final String message, final Handler h){
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
//1.创建客户端套接字,填充IP地址和端口号
Socket client = new Socket("192.168.0.15",8880);
//2.获取输出流,用来发送数据
OutputStream out = client.getOutputStream();
//4.发送数据
//用getBytes()方法将字符串转化为字节数组
out.write(message.getBytes());
//5.接收数据
InputStream in = client.getInputStream();
byte[] data = new byte[128];
int len = 0;
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); //把b放在msg中
h.sendMessage(msg); //触发Handler处理机制
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public void sendMessage(View v){
switch(v.getId()){
case R.id.fw:
handlerMessage("goForward",handler);
break;
}
}
}
.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/fw"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="sendMessage"
android:textColor="#ffffff"
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>
效果显示:
五、WebView控件之自制浏览器APP
.java
package com.example.ycy;
import android.os.Bundle;
import android.app.Activity;
import android.view.KeyEvent;
import android.view.Menu;
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);
//关联输入框控件
final EditText ed = (EditText) findViewById(R.id.ed);
//创建浏览器客户端,防止页面访问浏览器发生跳转
wb.setWebViewClient(new WebViewClient());
//输入框调用动作监听方法
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);
//如果监听到回车,返回true
return (event.getKeyCode() == KeyEvent.KEYCODE_ENTER);
}
});
}
}
.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>
注意要在 AndroidMainfest 中加上网络访问权限:
<uses-permission android:name="android.permission.INTERNET"/>
效果显示: