简单例子开头: 网络http请求网站源码数据并显示
注意点:访问网络需要加Internet权限:
android.permission.INTERNET
简单的步骤:
使用UrlConnection请求一个url地址获取内容:
//1.创建一个Url对象
URL url = new URL(url_str);
//2.获取一个UrlConnection对象
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
//3.为UrlConnection对象设置一些请求的参数,请求方式,连接的超时时间
connection.setRequestMethod("GET");//设置请求方式
connection.setConnectTimeout(1000*10);//设置超时时间
//4.在获取url请求的数据前需要判断响应码,200 :成功,206:访问部分数据成功 300:跳转或重定向 400:错误 500:服务器异常
int code = connection.getResponseCode();
if(code == 200){
//5.获取有效数据,并将获取的流数据解析成String
InputStream inputStream = connection.getInputStream();
String result = StreamUtils.streamToString(inputStream);
}
注意:
(1)主线程不能够做耗时的操作,网络请求就是耗时的操作需要放到子线程做。
(2)子线程不能更新控件的内容(更新Ui)。所以产生了矛盾,解决办法就是使用Handler(处理消息机制).
(3)子线程一定不能更新UI?是错的, SurfaceView :多媒体视频播放 ,可以在子线程中更新UI;Progress(进度)相关的控件:也是可以在子线程中更新Ui;
审计机制:activity完全显示的时候审计机制才会去检测子线程有没有更新Ui. 当activity没有完全显示的时候子线程可以更新UI
******消息机制原理*****
Handler、Looper、MessageQuene之间的关系。
每一个线程最多有一个Looper、一个Looper里边含有一个MessageQuene。
Handler每次将消息发送到MessageQuene中,Looper用过一个死循环不断的从MessageQuene中获取消息,获取后,根据Message的target分发给对应的Handler进行处理。
Handler:消息机制的写法(重要)
使用Handler的步骤:
1.主线程中创建一个Handler
private Handler handler = new Handler(){
//重写handler的handlermessage方法 public void handleMessage(android.os.Message msg) { }; };
2.重写handler的handlermessage方法
3.子线程中创建一个Message对象,将获取的数据绑定给msg
Message msg = new Message(); //另一种方式:Message msg = Messge.obtain; msg.obj = result;
4.handler对象在子线程中将message发送给主线程
handler.sendMessage(msg);
5. 主线程中handlermessage重写的方法中 接受子线程发来的数据,就可以做更新UI的操作。
String result= (String) msg.obj;
下面是一个例子:
布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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:orientation="vertical" tools:context="com.example.yb.myapplication.HttpUrlActivity"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ed_url"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/bt_httpRequest" android:text="请求网页数据"/> <ScrollView android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv_httpResponse"/> </ScrollView> </LinearLayout>
在Activity里面
public class HttpUrlActivity extends AppCompatActivity implements View.OnClickListener { private Context mcontext; private TextView tv_httpResponse1; private EditText ed_url; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_http_url); mcontext=this; Button bt_httpRequest = (Button)findViewById(R.id.bt_httpRequest); ed_url = (EditText) findViewById(R.id.ed_url); tv_httpResponse1 = (TextView) findViewById(R.id.tv_httpResponse); bt_httpRequest.setOnClickListener(this); } //H.1在主线程中创建一个handler对象 ,这里是匿名内部类 Handler handler=new Handler(){ //H.2重新handleMessage方法 @Override public void handleMessage(Message msg) { //H.5 接受子线程发来的 数据,处理数据 String result= (String) msg.obj; //H.6当前线程是主线程,可以做UI的更新 //5显示到TextView tv_httpResponse1.setText(result); } }; @Override public void onClick(View v) { final String url_str = ed_url.getText().toString().trim(); if (TextUtils.isEmpty(url_str)) { Toast.makeText(mcontext, "url不能为空", Toast.LENGTH_SHORT).show(); return; } //匿名内部类可以用于接口上,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现。 // 最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口。 //创建一个子线程做网络请求 new Thread(new Runnable() { @Override public void run() { try { //四.请求url地址 //1创建一个url对象 URL url = new URL(url_str); //2获取一个urlConnection对象 HttpURLConnection con = (HttpURLConnection) url.openConnection(); //3设置urlConnection的参数:请求时间,请求方式 con.setRequestMethod("GET"); con.setConnectTimeout(1000 * 10); //超时时间 //4根据请求的结果的响应码来判断,200成功,206部分数据访问成功。400错误,500服务器异常 int code = con.getResponseCode(); if (code == 200) { //获取数据,并返回的流数据解析为String InputStream inputStream = con.getInputStream(); //将获取的读取流解析为String字符串 String result=StreamUtil.stremToString(inputStream); //H.3 子线程创建一个Message对象,为了携带子线程获取的数据给主线程 Message msg=new Message(); msg.obj=result; //H.4使用handler对象将消息发送给主线程 handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); } } }).start(); } }
创建一个工具类StreamUtil ,里面写入把读取流转为String返回
public class StreamUtil { /** * 获取的读取流转为String返回 * * @param inputStream */ public static String stremToString(InputStream in) { String result=""; try { //创建一个字节数组写入流 ByteArrayOutputStream out=new ByteArrayOutputStream(); byte[] buffer=new byte[1024]; int length=0; while((length=in.read(buffer))!=-1){ //如果返回-1 则表示数据读取完成了。 out.write(buffer,0,length);//写入数据 out.flush(); } result=out.toString();//写入流转为字符串 out.close(); } catch (Exception e) { e.printStackTrace(); } return result; } }
其他的消息处理:
使用handler直接post到主线程,handler需要在主线程创建
//延迟多少毫米执行runnable。 new Handler().postDelayed(new Runnable() { @Override public void run() { tv_simple.setText("我被更新了"); } }, 1000*5);
应用场景:广告展示后,做页面跳转。