您的位置:首页 > 理论基础 > 计算机网络

Android基础之二——网络编程(一)

2016-02-21 22:11 387 查看

01_网络图片查看器(重点)

向服务器端发送请求的常用方式:GET、POST

步骤:
1、创建一个URL,打开一个HTTP的连接;

2、设置请求头信息;

3、获取服务器端返回的响应数据,判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;4、把二进制流数据转换成一个图片,并显示在Imageview;

模版代码:
//          1、创建一个URL,打开一个HTTP的连接;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//          2、设置请求头信息;
conn.setRequestMethod("GET");//默认是GET方式,大写
conn.setConnectTimeout(3000);
//              conn.setRequestProperty("Accept-Encoding", "gzip, deflate");

//          3、获取服务器端返回的响应数据,判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;
int code = conn.getResponseCode();
if(code == 200){
//获取返回的二进制数据流
InputStream is = conn.getInputStream();
//                  4、把二进制流数据转换成一个图片,并显示在Imageview;
Bitmap bm = BitmapFactory.decodeStream(is);
iv.setImageBitmap(bm);

}else{
//提示用户信息
Toast.makeText(this, "服务器端返回数据失败", 0).show();

}


android.os.NetworkOnMainThreadException:网络在主线程上的异常

android4.0之后,google为了让UI界面运行的更加流畅,强制要求访问网络的操作不能再主线程中进行。这样就避免了在主线程因为访问网络时间太长,导致界面卡死等现象的发生。

运行activity的线程就是主线程(UI线程),oncreate、单击事件的响应方法都是运行在主线程里面的。

02_子线程不能修改UI界面

Only the original thread that created a view hierarchy can touch its views:
只有创建UI界面的线程才能修改UI界面,谁创建的界面谁才能修改。

子线程不能直接修改UI界面,只有主线程(UI线程)才能修改UI界面。
子线程可以修改UI界面,修改UI界面之后,系统会自动判断当前线程是不是主线程,如果不是主线程,就会立即终止程序的运行。

03_消息处理机制的原理(重点)

步骤:
1、创建handler对象

private Handler handler = new Handler(){
//接收消息、处理消息
public void handleMessage(Message msg) {

};
};

2、得到handler的引用,向主线程发送一个消息

// iv.setImageBitmap(bm);
//把消息放入消息盒子中
Message msg = new Message();
msg.obj = bm;
//向主线程发送一个消息
handler.sendMessage(msg);

3、handler修改UI界面

private Handler handler = new Handler(){
//接收消息、处理消息
public void handleMessage(Message msg) {
Bitmap bm = (Bitmap) msg.obj;

iv.setImageBitmap(bm);
};
};


handler的工作机制原理( Handler、message、Looper三者之间的关系):
前提知识:
所有使用UI界面的操作系统,后台都在运行着一个死循环,它在不停地监听和接收用户发出的指令,一旦接收到指令,就马上执行。

我们的应用程序一旦运行起来,系统就会给它提供一个轮询器Looper,Looper内部维护了一个消息队列(MessageQueue)。当子线程调用handler的sendMessage方法发送消息(Message)的,会把消息放到消息队列里。Looper不停的从消息队列中去消息,取到消息后会马上发送给handler,handler来修改UI界面。


04_网络HTML查看器

代码:
package com.itheima.htmlview;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import andr
4000
oid.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.itheima.htmlview.utils.StreamTools;

public class MainActivity extends Activity {

private EditText et_path;
private TextView tv;

//1、创建handler
private Handler handler = new Handler(){
//3、handler修改UI界面
public void handleMessage(Message msg) {
String result = (String) msg.obj;

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

et_path = (EditText) findViewById(R.id.et_path);

tv = (TextView) findViewById(R.id.tv);
}

public void click(View view){
final String path = et_path.getText().toString().trim();

if(TextUtils.isEmpty(path)){
Toast.makeText(this, "请输入html页面的网络地址", 0).show();
return;
}else{
//从网络上获取数据,并显示在TextView上

new Thread(){
public void run() {
try {
//1、创建一个URL,打开一个HTTP的连接;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//2、设置请求头信息;
conn.setRequestMethod("GET");//默认是GET方式,大写
conn.setConnectTimeout(3000);
//conn.setRequestProperty("Accept-Encoding", "gzip, deflate");

//3、获取服务器端返回的响应数据,判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;
int code = conn.getResponseCode();
if(code == 200){
//获取返回的二进制数据流
InputStream is = conn.getInputStream();
// 4、把二进制流数据转换成一个图片,并显示在Imageview;
// Bitmap bm = BitmapFactory.decodeStream(is);
String result = StreamTools.readStream(is);
//修改UI界面
//2、得到handler的引用,向主线程发送一个消息
//iv.setImageBitmap(bm);
//把消息放入消息盒子中
Message msg = new Message();
msg.obj = result;
//向主线程发送一个消息
handler.sendMessage(msg);

}else{
//提示用户信息
Toast.makeText(MainActivity.this, "服务器端返回数据失败", 0).show();
}

} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}
}

}

05_消息处理常用API

三个API:
new Thread(){
public void run() {

//1、第一个API:runOnUiThread
//join 合并
runOnUiThread(new Runnable() {

@Override
public void run() {
tv.setText("子线程修改UI界面");

}
});
//2、第二个API:postDelayed
handler.postDelayed(new Runnable() {

@Override
public void run() {
tv.setText("postDelayed子线程修改UI界面");

}
}, 1000);
//3、第三个API:postAtTime
//          handler.postAtTime(r, uptimeMillis);

};

}.start();


06_新闻客户端

步骤:


1、访问网络上一个xml文件,读取里面的xml格式数据;

2、解析xml的数据,解析其中新闻条目,把条目都放到list集合里;

3、把list中新闻条目显示在listView;

代码: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.lv);

//1、访问网络,获取xml的数据
new Thread(){

public void run() {
try {
//          1、创建一个URL,打开一个HTTP的连接;
URL url = new URL("http://192.168.13.41:8080/news.xml");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//              2、设置请求头信息;
conn.setRequestMethod("GET");//默认是GET方式,大写
conn.setConnectTimeout(3000);
//                  conn.setRequestProperty("Accept-Encoding", "gzip, deflate");

//              3、获取服务器端返回的响应数据,判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;
int code = conn.getResponseCode();
if(code == 200){
//获取返回的二进制数据流
InputStream is = conn.getInputStream();
//2、解析xml格式的数据到list集合
list = NewsItemParserService.parseNewsItems(is);

Message msg = Message.obtain();
msg.obj= list;
handler.sendMessage(msg);
}else{
//提示用户信息
Toast.makeText(MainActivity.this, "服务器端返回数据失败", 0).show();
}

} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}

/*
* 自顶一个数据适配器,用于给listview填充数据
*/
private class MyAdapter extends BaseAdapter{

@Override
public int getCount() {
return list.size();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
//填充数据到item布局界面
if(convertView != null){
view = convertView;
}else{
view = View.inflate(MainActivity.this, R.layout.item, null);

}

ImageView iv_image = (ImageView) view.findViewById(R.id.iv_image);

TextView tv_title = (TextView) view.findViewById(R.id.tv_title);

TextView tv_desc = (TextView) view.findViewById(R.id.tv_desc);

TextView tv_type = (TextView) view.findViewById(R.id.tv_type);

NewsItem item = list.get(position);

tv_title.setText(item.getTitle());

tv_desc.setText(item.getDescription());

if("1".equals(item.getType())){
tv_type.setText("评论:"+item.getComment());
tv_type.setTextColor(Color.BLACK);
}else if("2".equals(item.getType())){
tv_type.setText("视频");
tv_type.setTextColor(Color.BLUE);
}else if("3".equals(item.getType())){
tv_type.setText("专题");
tv_type.setTextColor(Color.RED);
}

return view;
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}

}


NewsItemParserService.java:
public class NewsItemParserService {

public static List<NewsItem> parseNewsItems(InputStream is){

List<NewsItem> list = new ArrayList<NewsItem>();

try {
XmlPullParser  parser = Xml.newPullParser();

parser.setInput(is, "UTF-8");
//得到解析事件的类型
int type = parser.getEventType();
NewsItem item = null;
while(type != XmlPullParser.END_DOCUMENT){
switch (type) {
case XmlPullParser.START_TAG://解析到开始标签的位置
if("item".equals(parser.getName())){
item = new NewsItem();
}else if("title".equals(parser.getName())){

String title = parser.nextText();
item.setTitle(title);
}else if("description".equals(parser.getName())){

String description = parser.nextText();
item.setDescription(description);
}else if("image".equals(parser.getName())){

String image = parser.nextText();
item.setImage(image);
}else if("type".equals(parser.getName())){

String newsType = parser.nextText();
item.setType(newsType);
}else if("comment".equals(parser.getName())){

String comment = parser.nextText();
item.setComment(comment);
}
break;

case XmlPullParser.END_TAG://解析到结束标签的位置
if("item".equals(parser.getName())){
list.add(item);

item = null;
}

break;
}

type = parser.next();
}
} catch (Exception e) {
e.printStackTrace();
}

return list;

}

}

07_使用smartImageView显示新闻图片(重点)

使用smartImageView开源框架步骤:
1、把smartImageView的源代码拷贝到自己Android工程的src的目录下;

2、在布局文件中使用SmartImageView控件,包名要拷全;

<com.itheima.smartimageview.SmartImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/siv" />

3、在代码中使用SmartImageView的setImageUrl方法:

public class MainActivity extends Activity {

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

siv = (SmartImageView) findViewById(R.id.siv);

siv.setImageUrl("http://192.168.13.41:8080/image/3.jpg");
}
}

08_smartImageView的工作原理

09_使用GET方式向服务器端提交数据(重点)

提交数据的方式:GET、POST;

访问网络提交数据,是把参数组拼到了URL地址的后面:
如: http://192.168.13.41:8080/web/servlet/LoginServlet?username=1234&password=abdsfds


步骤:
1、创建URL对象,打开HTTP的连接

2、设置请求头信息:
设置请求头:GET、con
ce27
nectTimeOut


3、发送数据:
以二进制流的形式向服务器端提交数据


4、获取服务器端返回的二进制数据流:
判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;


模版代码:MainActivity.java
package com.itheima.qqlogin;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.itheima.htmlview.utils.StreamTools;

public class MainActivity extends Activity {

protected static final int ERROR = 0;
protected static final int FAILED = 1;
protected static final int SUCCESS = 2;
private EditText et_qq;
private EditText et_pwd;

private Handler handler = new Handler(){
public void handleMessage(Message msg) {
String result = (String)msg.obj;
switch (msg.what) {
case SUCCESS:

Toast.makeText(MainActivity.this, result, 0).show();
break;

case FAILED:
Toast.makeText(MainActivity.this, result, 0).show();
break;

case ERROR:
Toast.makeText(MainActivity.this, result, 0).show();
break;

}

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

et_qq = (EditText) findViewById(R.id.et_qq);

et_pwd = (EditText) findViewById(R.id.et_pwd);
}

public void login(View view){
String qq = et_qq.getText().toString().trim();
String pwd = et_pwd.getText().toString().trim();

final String path ="http://192.168.13.41:8080/web/servlet/LoginServlet?username="+qq+"&password="+pwd;
if(TextUtils.isEmpty(qq) || TextUtils.isEmpty(pwd)){
Toast.makeText(this, "qq号码或者密码不能为空", 0).show();
return;
}else{
//访问网络,把数据提交给服务器上

new Thread(){
public void run() {
try {
// 1、创建一个URL,打开一个HTTP的连接;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 2、设置请求头信息;
conn.setRequestMethod("GET");//默认是GET方式,大写
conn.setConnectTimeout(3000);
// conn.setRequestProperty("Accept-Encoding", "gzip, deflate");

// 3、获取服务器端返回的响应数据,判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;int code = conn.getResponseCode();
if(code == 200){
//获取返回的二进制数据流
InputStream is = conn.getInputStream();
// 4、把二进制流数据转换成一个图片,并显示在Imageview;
// Bitmap bm = BitmapFactory.decodeStream(is);
String result = StreamTools.readStream(is);
//修改UI界面
//2、得到handler的引用,向主线程发送一个消息
// iv.setImageBitmap(bm);
//把消息放入消息盒子中

Message msg = new Message();
msg.what = SUCCESS;
msg.obj = result;
//向主线程发送一个消息
handler.sendMessage(msg);

}else{
//提示用户信息
Message msg = new Message();
msg.what = FAILED;
msg.obj = "服务器端返回数据失败";
//向主线程发送一个消息
handler.sendMessage(msg);
}

} catch (Exception e) {
//提示用户信息
Message msg = new Message();
msg.what = ERROR;
msg.obj = "访问网络失败";
//向主线程发送一个消息
handler.sendMessage(msg);
}
};
}.start();
}

}
}

10_使用POST方式提交数据(重点)

步骤:
1、创建URL对象,打开HTTP的连接

2、设置请求头信息:
设置请求头:POST、Content-Type Content-Length


3、发送数据:
以二进制流的形式向服务器端提交数据


4、获取服务器端返回的响应数据:
判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;


模版代码:
//          1、创建一个URL,打开一个HTTP的连接;
String data = "username="+qq+"&password="+pwd;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 2、设置请求头信息;
conn.setRequestMethod("POST");//默认是GET方式,大写
conn.setConnectTimeout(3000);
//设置请求头:POST、Content-Type Content-Lengthconn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", data.length()+"");
// conn.setRequestProperty("Accept-Encoding", "gzip, deflate");

//3、提交数据
//设置是否向服务器端写数据
conn.setDoOutput(true);
//使用输出流向服务器端写数据(提交数)
conn.getOutputStream().write(data.getBytes());

// 4、获取服务器端返回的响应数据,判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;int code = conn.getResponseCode();
if(code == 200){
//获取返回的二进制数据流
InputStream is = conn.getInputStream();
// 4、把二进制流数据转换成一个图片,并显示在Imageview;
// Bitmap bm = BitmapFactory.decodeStream(is);
String result = StreamTools.readStream(is);
//修改UI界面
//2、得到handler的引用,向主线程发送一个消息
// iv.setImageBitmap(bm);
//把消息放入消息盒子中

Message msg = new Message();
msg.what = SUCCESS;
msg.obj = result;
//向主线程发送一个消息
handler.sendMessage(msg);


使用GET、POST提数据的区别:

使用GET提数据缺点:不安全;数据长度有限:4kb,1kb; 如:http://192.168.13.41:8080/web/servlet/LoginServlet?username=1234&password=abdsfds

GET方式优点: 简单

使用POST提数据缺点:代码复杂;

POST方式优点: 安全;数据量大;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 网络编程