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

本文介绍了Android网络编程的基础知识,包括使用GET、POST方法发送请求,创建网络图片查看器,理解子线程与UI线程交互的限制,以及消息处理机制。重点讲解了smartImageView的使用和网络数据的提交,提供了相关代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;

        }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值