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方式优点: 安全;数据量大;

0 0
原创粉丝点击