该博文中内容通过老师上课的内容对于Android下的网络通信编程等内容进行总结;
1、Android网络编程初识
2、Android实现HTML源码查看
3、Android实现网络图片查看
4、Android实现与服务器上JavaWeb项目交互
1、Android网络编程初识
- Android手机终端作为客户端发送Http请求到终端服务器上,并且当发送请求到服务器,如果请求成功,响应码:200;服务器会通过客户端返回请求并且处理后的信息数据,一般情况下,在正式项目中多用JSON,不会使用没有规定格式的文本信息;
- 注意事项:Android的网络操作在Android4之后,就不能够将Android的网络操作写在主线程中除了会直接造成应用崩溃之外,还因为一旦造成主线程阻塞,应用会停止刷新界面,停止响应用户任何操作,用户体验非常差,所以耗时操作不要写在主线程中;
- 将于网路连接部分写在子线程中,再通过handler实现了通信的相关操作。
2、Html源文件查看器(掌握)
- 发送GET请求
public class MainActivity extends Activity {
private Handler handler;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) this.findViewById(R.id.tv);
handler = new Handler() {
//重写消息队列方法
@Override
public void handleMessage(Message msg) {
tv.setText((String) msg.obj);
}
};
}
public void click(View view) {
final String path = "http://192.168.1.109:8080/baidu.html";
Thread thread = new Thread() {
@Override
public void run() {
try {
//使用网址创建URL
URL url = new URL(path);
//获取连接对象做设置
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置请求方式
conn.setRequestMethod("GET");
//设置超时时间
conn.setConnectTimeout(8000);
//设置读取超时的时间
conn.setReadTimeout(8000);
//连接
conn.connect();
//连接成功
if(conn.getResponseCode() == 200) {
System.out.println("Connected======");
InputStream is = conn.getInputStream();
String text = StreamTool.getTextFromStream(is);
Message msg = handler.obtainMessage();
msg.obj = text;
handler.sendMessage(msg);
} else if(conn.getResponseCode() == 404) {
}
} catch (MalformedURLException e) {
System.out.println("MalFormed Exception=");
} catch (IOException e) {
System.out.println("IOException");
}
}
};
thread.start();
}
}
- 在上面的代码中获取服务器返回的流,从流中把html源码读取出来
InputStream is = conn.getInputStream();
String text = StreamTool.getTextFromStream(is);
Message msg = handler.obtainMessage();
msg.obj = text;
handler.sendMessage(msg);
////////////////////////
handler = new Handler() {
//重写消息队列方法
@Override
public void handleMessage(Message msg) {
tv.setText((String) msg.obj);
}
};
- 乱码的处理
- 乱码的出现是因为服务器和客户端码之间的编码表的不一致所导致的,所以自己写一个专门处理乱码的工具类方便调用
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class StreamTool {
public static String getTextFromStream(InputStream is) {
byte[] buffer = new byte[1024];
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
while((len = is.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
//利用字节数组输出流转换成字节数组,然后用字节数组构造成为一个字符串
String text = new String(bos.toByteArray());
return text;
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
3、Android实现网络图片查看
- 确定图片的网址
- 实现功能
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
/** * 几个知识点必须要掌握的: * 1、4.3版本以上的编程规范,否则谷歌会强制不予执行,应为为了用户体验不会让主线程出现长时间的阻塞,否则会造成用户体验变差; * 2、在新创建出来的线程中不可以直接使用UI否则会出现 * 11-25 02:27:08.884: E/AndroidRuntime(7093): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() * 错误,是因为在子线程中会丢失对于UI的相关的参数设置 * 3、消息队列相关的概念必须要很好的掌握,在主线程开始创建的是会提供对应的详细队列的机制,并且会用Logger消息轮询器进行检索访问 * @author DELL * */
public class MainActivity extends Activity {
private ImageView iv;
private Bitmap bm;
@SuppressLint("HandlerLeak")
Handler handler = new Handler() {
//只要消息队列中有消息,此方法就会在主线程中执行
public void handleMessage(android.os.Message msg) {
//在这里进行消息队列的刷新,从而达到刷新UI的目的
switch (msg.what) {
case 1:
iv = (ImageView) findViewById(R.id.iv);
iv.setImageBitmap((Bitmap)msg.obj);
break;
case 2:
Toast.makeText(MainActivity.this, "加载视图失败", Toast.LENGTH_SHORT).show();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//版本在4.0以上必须要使用的两个操作
//1、事件添加的时候需要新建线程
//2、设置builder
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
}
/** * 注意一点只有主线程可以刷新UI * @param view */
public void clickload(View view) {
final String path = "http://192.168.2.197:8080/img/e.jpg";
final File file = new File(getCacheDir(),getFileNameFromPath(path));
if(file.exists()) {
System.out.println("============缓存获取==============");
bm = BitmapFactory.decodeFile(file.getAbsolutePath());
Message msg = new Message();
msg.obj = bm;
msg.what = 1;
handler.sendMessage(msg);
} else {
System.out.println("============网络获取==============");
Thread thread = new Thread(){
@Override
public void run() {
try { //发送http请求的操作步骤
//1、创建URL对象
URL url = new URL(path);
//2、获取连接对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//3、设置一些属性
//设置请求方式,注意大写
conn.setRequestMethod("GET");
//设置请求超时
conn.setConnectTimeout(8000);
//设置读取超时
conn.setReadTimeout(8000);
//4、发送请求建立连接
conn.connect(); /*可能阻塞的位置*/
//5、判断请求是否成功
if(conn.getResponseCode() == 200) { /*可能阻塞的位置*/
//获取服务器返回的刘,流中就是客户端的请求数据
System.out.println("====true");
InputStream is = conn.getInputStream();
//现在需要我们自己读取流中的数据,读取1K,就可以把1K写到本地文件缓存起来
byte[] buffer = new byte[1024];
int len ;
FileOutputStream fos = new FileOutputStream(file);
while((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.close();
//缓存时候已经将缓存中的数据读取完了,所以流中取不到任何数据
// bm = BitmapFactory.decodeStream(is);
bm = BitmapFactory.decodeFile(file.getAbsolutePath());
//当子线程需要刷新UI的时候,只需要发送一条消息到消息队列
//发送消息的方法,在另一端接受消息队列
Message msg = new Message();
//消息对象本身是可以携带数据的
msg.obj = bm;
//使用what标注消息是什么类型
msg.what = 1;//我自身定义1表示成功
handler.sendMessage(msg);
} else {
//创建消息对象
//如果消息池中有消息,取出消息池中第一条消息
//返回,如果没有,就new一个消息返回
Message msg = handler.obtainMessage();
msg.what = 2;//我自身定义2表示加载失败
handler.sendMessage(msg);
System.out.println("====false");
}
} catch (MalformedURLException e) {
e.printStackTrace();
Log.e("MalformedURLException", "URL创建过程出错");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("IOException", "HttpURLConnection出错");
}
}
};
thread.start();
}
}
//路径获取图片文件名称
public String getFileNameFromPath(String path) {
int index = path.lastIndexOf("/");
return path.substring(index+1);
}
}
4、Android实现与服务器上JavaWeb项目交互
- 普通方式:使用GET方式提交表单
- 首先实现一个工具类:
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
public class Tools {
public static String getTextFromStream(InputStream is) {
byte[] buffer = new byte[1024];
int len;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
while((len = is.read(buffer))!=-1) {
bos.write(buffer,0,len);
}
String text = new String(bos.toByteArray(),"utf-8");
return text;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
- 服务端
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
System.out.println("======GET======");
String username = request.getParameter("username");
String password = request.getParameter("password");
username = new String(username.getBytes("ISO-8859-1"),"utf-8");
password = new String(password.getBytes("ISO-8859-1"),"utf-8");
username = username.trim();
password = password.trim();
System.out.println(username + " " + password);
if("admin".equalsIgnoreCase(username)) {
response.getWriter().print("登陆成功");
} else {
response.getWriter().print("登陆失败");
}
}
- Android 客户端
public class MainActivity extends Activity {
private EditText et_username;
private EditText et_password;
private String username;
private String password;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Toast.makeText(MainActivity.this, (String) msg.obj, Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_username = (EditText) this.findViewById(R.id.username);
et_password = (EditText) this.findViewById(R.id.password);
}
public void login(View view) {
username = et_username.getText().toString().trim();
password = et_password.getText().toString().trim();
Thread thread = new Thread() {
String path = "http://192.168.1.105:8080/AndroidWebServerDemo/Login?username=+"+URLDecoder.decode(username)+"+&password=+"+URLDecoder.decode(password);
@Override
public void run() {
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(8000);
conn.setReadTimeout(8000);
conn.setRequestMethod("GET");
conn.connect();
if(conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
String text = Tools.getTextFromStream(is);
System.out.println(text);
Message msg = new Message();
msg.obj = text;
msg.what = 1;
handler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
}
}
- 普通方式:使用POST方式提交表单
- 服务端
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
System.out.println("======POST======");
String username = request.getParameter("username");
String password = request.getParameter("password");
// username = new String(username.getBytes("ISO-8859-1"),"utf-8");
// password = new String(password.getBytes("ISO-8859-1"),"utf-8");
username = username.trim();
password = password.trim();
System.out.println(username + " " + password);
if("admin".equalsIgnoreCase(username)) {
response.getWriter().print("登陆成功");
} else {
response.getWriter().print("登陆失败");
}
}
- Android 客户端
- readTool类与上文中GET方式的Tool相同
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.android.getmethod.R;
import com.android.postmethod.read.tools.Tools;
public class MainActivity extends Activity {
private EditText et_username;
private EditText et_password;
private String username;
private String password;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Toast.makeText(MainActivity.this, (String) msg.obj, Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_username = (EditText) this.findViewById(R.id.username);
et_password = (EditText) this.findViewById(R.id.password);
}
public void login(View view) {
username = et_username.getText().toString().trim();
password = et_password.getText().toString().trim();
Thread thread = new Thread() {
String path = "http://192.168.1.105:8080/AndroidWebServerDemo1/Login";
@Override
public void run() {
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(8000);
conn.setReadTimeout(8000);
conn.setRequestMethod("POST");
//添加POST请求头中自动添加的属性
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
//方便服务器端的程序员,通过程序的这个数据知道数据的大小
//实现动态的大小长度
String content_text = "username="+ URLEncoder.encode(username) + "&password=" + password;
//流中数据的长度
conn.setRequestProperty("Content-Length", content_text.length()+"");
//打开连接对象的输出流
conn.setDoOutput(true);
//把数据写入到输入流中
OutputStream os = conn.getOutputStream();
//将数据写入到输出流中
os.write(content_text.getBytes());
conn.connect();
if(conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
String text = Tools.getTextFromStream(is);
System.out.println(text);
Message msg = new Message();
msg.obj = text;
msg.what = 1;
handler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
}
}
- 使用HTTPClient的方式实现与服务器的数据交互
- GET方式(HTTPClient)
public class MainActivity extends Activity {
private EditText et_username;
private EditText et_password;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String text = (String) msg.obj;
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_username = (EditText) this.findViewById(R.id.username);
et_password = (EditText) this.findViewById(R.id.password);
}
public void login(View view) {
//获取用户输入的账号密码
Thread thread = new Thread() {
String username = et_username.getText().toString();
String password = et_password.getText().toString();
final String path = "http://192.168.1.105:8080/AndroidWebServerDemo1/Login?" +
"username="+username+"&password="+password;
public void run() {
System.out.println("=============================================="+path);
//创建HttpClient对象
HttpClient client = new DefaultHttpClient();
//创建get请求对象
HttpGet get = new HttpGet(path);
try {
//使用client发送get请求
HttpResponse response = client.execute(get);
//获取状态行
StatusLine line = response.getStatusLine();
//获取状态码
if(line.getStatusCode() == 200) {
System.out.println("==============================================200");
//获取实体对象
InputStream is = response.getEntity().getContent();
String text = Tools.getTextFromStream(is);
Message msg = handler.obtainMessage();
msg.obj = text;
handler.sendMessage(msg);
} else {
System.out.println("=============================================="+line.getStatusCode());
}
} catch (Exception e) {
System.out.println("==============================================错误");
e.printStackTrace();
}
};
};
thread.start();
}
}
- POST 方式(HTTPClient)
public class MainActivity extends Activity {
private EditText et_username;
private EditText et_password;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String text = (String) msg.obj;
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_username = (EditText) this.findViewById(R.id.username);
et_password = (EditText) this.findViewById(R.id.password);
}
public void login(View view) {
//获取用户输入的账号密码
Thread thread = new Thread() {
String username = et_username.getText().toString();
String password = et_password.getText().toString();
final String path = "http://192.168.1.105:8080/AndroidWebServerDemo1/Login";
public void run() {
System.out.println("====="+path);
//创建HttpClient对象
HttpClient client = new DefaultHttpClient();
//创建post请求对象
HttpPost post = new HttpPost(path);
//将数据封装到post中
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
//arg0:表单的名字
//arg1:表单中的值
BasicNameValuePair bnvp1 = new BasicNameValuePair("username", username);
BasicNameValuePair bnvp2 = new BasicNameValuePair("password", password);
parameters.add(bnvp1);
parameters.add(bnvp2);
//创建实体对象
UrlEncodedFormEntity entity = null;
try {
//将集合对象封装到实体中
entity = new UrlEncodedFormEntity(parameters,"utf-8");
post.setEntity(entity);
//数据响应
HttpResponse response = client.execute(post);
if(response.getStatusLine().getStatusCode() == 200) {
InputStream is = response.getEntity().getContent();
String text = Tools.getTextFromStream(is);
Message msg = handler.obtainMessage();
msg.obj = text;
msg.what = 1;
handler.sendMessage(msg);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
};
};
thread.start();
}
}