Android基础之二——网络编程(一)
来源:互联网 发布:二叉树层次遍历 python 编辑:程序博客网 时间:2024/05/21 11:10
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 android.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、connectTimeOut
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; } }};@Overrideprotected 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-Length conn.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基础之二——网络编程(一)
- android基础之二——网络编程(二)
- 【Android基础】二、网络编程
- Android网络编程基础(二)
- Android网络编程(一)之Socket基础
- Android开发之基础------------------网络编程(一)
- Java基础—网络编程(二)
- Android基础之网络编程
- Java基础—网络编程(一)
- Java基础—网络编程(一)
- Android网络编程基础(一) - 基础知识
- Android网络编程基础(一)
- 网络编程基础<二>
- 网络编程基础一
- 网络编程基础一
- Android之Http网络编程(二)
- Android开发之网络编程(二)
- 网络编程基础(二)——使用UDP
- Android大图片裁剪终极解决方案(中:从相册截图)
- C#public/protected/private/internal/protected internal
- SearchView
- 重载运算与类型转换
- springmvc与struts2的区别
- Android基础之二——网络编程(一)
- 前端性能的一些理解
- [Lintcode]Merge Sorted Array
- 已知线段端点坐标,求线段上等距离的点坐标序列
- Android控件AutoCompleteTextView-自动匹配
- C#聊天程序基于HP-SOCKET V1.1最终版
- tiny4412下的Exynos4412 iROM 启动分析
- [Matlab]使用Simulink进行UDP通讯1
- 详解Android中AsyncTask的使用