zoukankan      html  css  js  c++  java
  • Android网络编程(一)

    网络编程

    网络图片查看

    网络图片查看器

    try {
            // 2.把网址字符串封装成一个URL
            URL url = new URL(path);
            // 3.获取连接对象
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    
            // 4.做参数设置,注意大写
            conn.setRequestMethod("GET");
            // 5.设置连接超时时间
            conn.setConnectTimeout(8000);
            // 设置读取超时时间
            conn.setReadTimeout(8000);
            // 发送请求,建立连接
            conn.connect();
            // 6. 获取返回码,判断请求返回状态
            if (conn.getResponseCode() == 200) {
                // 请求成功
                // 7.拿到服务器返回的流,里面的数据就是客户端请求的内容
                InputStream is = conn.getInputStream();
                // 在确定流中数据是图片的情况下可以使用Google提供的API直接生成图片,就不需要自己读取流了
    //====================================================================================================================
                //从流里读取数据就是在下载数据,如果网速过慢就会造成主线程阻塞(主线程阻塞在2.3可以,但是4.0+版本的Android会抛出异常)
                Bitmap bm = BitmapFactory.decodeStream(is);
    //====================================================================================================================
                ImageView iv = (ImageView) findViewById(R.id.imageView1);
                iv.setImageBitmap(bm);
            } else {
                Toast.makeText(this, "请求失败", Toast.LENGTH_SHORT).show();
            }
    
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    

    以上代码,注意细节~

    • (应用)主线程阻塞

      • 界面会停止刷新
      • 应用停止响应用户任何操作
      • 影响用户体验
    • 规范

      • 耗时的操作不要放在主线程((4.0以后的版本强制要求不可以放在主线程,要不就报错)放在子线程里面就可以了)

    ANR异常

    • application not responding(应用无响应)
    • 主线程长时间阻塞,会爆出ANR异常

    只有主线程才可以刷新UI(View)

    消息队列

    问题:怎么用子线程中处理过的数据去刷新UI
    

    MessageQueue 消息队列

    Looper 轮询器(会一直不停的检测消息队列里面是否有消息) * 消息队列没有数据,就什么都不干 * 消息队列消息,就扔给Handler去处理

    Handler * handleMessage()方法用来处理消息 - 重写该方法来处理我们的消息

    在主线程创建时会同时创建MessageQueue和Looper对象,但是Handler对象在程序员需要使用是,(程序员)自行创建。 只要消息队列有消息,handleMessage()方法就会在主线程调用

    子线程需要刷新UI,只需要往主线程的消息队列中发送一条数据即可


    栗子:

    public class MainActivity extends Activity {
        // 创建消息处理器
        Handler handler = new Handler() {
            // 重写handleMessage方法
            public void handleMessage(android.os.Message msg) {
                switch (msg.what) {
                case 0:
                    ImageView iv = (ImageView) findViewById(R.id.imageView1);
                    iv.setImageBitmap((Bitmap) msg.obj);
                    break;  
                case 1:
                    Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT)
                            .show();
                    break;
                }   
            };
        };  
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main); 
        }
    
        public void click(View V) {
            Thread t = new Thread() {
                @Override
                public void run() {
                    // 网址
                    String path = "http://192.168.15.27:8080/dd.jpg";
    
                    try {
                        // 2.把网址字符串封装成一个URL
                        URL url = new URL(path);
                        // 3.获取连接对象
                        HttpURLConnection conn = (HttpURLConnection) url
                                .openConnection();
    
                        // 4.做参数设置,注意大写
                        conn.setRequestMethod("GET");
                        // 5.设置连接超时时间
                        conn.setConnectTimeout(8000);
                        // 设置读取超时时间
                        conn.setReadTimeout(8000);
                        // 发送请求,建立连接
                        conn.connect();
                        // 6. 获取返回码,判断请求返回状态
                        if (conn.getResponseCode() == 200) {
                            // 请求成功
                            // 7.拿到服务器返回的流,里面的数据就是客户端请求的内容
                            InputStream is = conn.getInputStream();
                            // 在确定流中数据是图片的情况下可以使用Google提供的API直接生成图片,就不需要自己读取流了
                            Bitmap bm = BitmapFactory.decodeStream(is);
    
                            // ImageView iv = (ImageView)
                            // findViewById(R.id.imageView1);
                            // iv.setImageBitmap(bm);
    
                            // 发送消息至主线程消息队列
                            Message msg = new Message();
                            // 利用消息对象携带数据
                            msg.obj = bm;
                            // 设置状态标识(这里设置的是成功获取返回0)
                            msg.what = 0;
    
                            handler.sendMessage(msg);
    
                        } else {
    
                            // Message msg = new Message();
                            // msg.what = 0;
                            // handler.sendMessage(msg);
                            // 不需要携带数据时也可以发送空消息,参数what
                            handler.sendEmptyMessage(1);
                        }
    
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            };
            t.start();
    
        }
    }
    

    数据缓存到本地

    看代码

    public class MainActivity extends Activity {
    
    // 创建消息处理器
    Handler handler = new Handler() {
        // 重写handleMessage方法
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case 0:
                ImageView iv = (ImageView) findViewById(R.id.imageView1);
                iv.setImageBitmap((Bitmap) msg.obj);
                break;
            case 1:
                Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT)
                        .show();
                break;
            }
        };
    };
    
        …………
    
    public void click(View V) {
        // 网址
        final String path = "http://192.168.15.27:8080/dd.jpg";
        final File file = new File(getCacheDir(), getFileName(path));
        // 判断文件是否已将缓存到本地
        if (!file.exists()) {
            // 是 直接读取显示
            Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());
            ImageView iv = (ImageView) findViewById(R.id.imageView1);
            iv.setImageBitmap(bm);
    
        } else {
            Thread t = new Thread() {
                @Override
                public void run() {
                    try {
                        // 2.把网址字符串封装成一个URL
                        // 3.获取连接对象
                        // 4.做参数设置,注意大写
                        // 5.设置连接超时时间
                        // 设置读取超时时间
                        // 发送请求,建立连接
                        // 6. 获取返回码,判断请求返回状态
                        if (conn.getResponseCode() == 200) {
                            // 请求成功
                            // 7.拿到服务器返回的流,里面的数据就是客户端请求的内容
                            InputStream is = conn.getInputStream();
    
                            FileOutputStream fos = new FileOutputStream(file);
    
                            byte[] b = new byte[1024];
                            int len;
                            while ((len = is.read(b)) != -1) {
                                fos.write(b, 0, len);
                            }
                            fos.close();
                            //生成图片
                            Bitmap bm = BitmapFactory.decodeFile(file
                                    .getAbsolutePath());
    
                            // 在确定流中数据是图片的情况下可以使用Google提供的API直接生成图片,就不需要自己读取流了
                            // Bitmap bm = BitmapFactory.decodeStream(is);
                            // ImageView iv = (ImageView)
                            // 发送消息至主线程消息队列
                            // 利用消息对象携带数据
                            // 设置状态标识(这里设置的是成功获取返回0)
    
                            ………………
    
                        } else {
                            handler.sendEmptyMessage(1);
                        }
    
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
    
            };
            t.start();
    
        }
    }
    
    /**
     * 获取文件名
     * 
     * @param path
     * @return
     */
    public String getFileName(String path) {
        int index = path.lastIndexOf("/");
        return path.substring(index + 1);
    }
    


    获取开源代码的网站

    • code.google.com
    • github.com
    • 在github搜索smart-image-view
    • 下载开源项目smart-image-view
    • 使用自定义组件时,标签名字要写包名

      <com.loopj.android.image.SmartImageView/>
      
    • SmartImageView的使用

      SmartImageView siv = (SmartImageView) findViewById(R.id.siv);
      siv.setImageUrl("http://192.168.1.102:8080/dd.jpg");
      

    使用第三方ImageView(自己试)

    测试用第三方资源:android-smart-image-view-master.zip


    Html源文件查看器

    • 发送GET请求

      URL url = new URL(path);
      //获取连接对象
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      //设置连接属性
      conn.setRequestMethod("GET");
      conn.setConnectTimeout(5000);
      conn.setReadTimeout(5000);
      //建立连接,获取响应吗
      if(conn.getResponseCode() == 200){
      
      }
      
    • 获取服务器返回的流,从流中把html源码读取出来

      byte[] b = new byte[1024];
      int len = 0;
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      while((len = is.read(b)) != -1){
          //把读到的字节先写入字节数组输出流中存起来
          bos.write(b, 0, len);
      }
      //把字节数组输出流中的内容转换成字符串
      //默认使用utf-8
      text = new String(bos.toByteArray());
      

    新闻客户端实现

    注意:线程异步问题

    因为主线程不能执行网络下载等其他耗时的操作,而必须使用子线程去实现网络下载等操作,但是要注意这里面的线程异步问题。 如:主线程在刷新UI是调用了子线程没有处理完毕内容导致的空指针等异常

    ViewHolder * 避免了重复生成大量的view对象 * 先把布局文件中的所有的组件封装到ViewHolder对象中 * ViewHolder的对象会与View一起被缓存起来 * 需要的时候直接xxx


    乱码问题的解决

    解决乱码问题非常简单: 统一两遍的编码集。 android下默认编码 utf-8

    客户端: 中文和特殊字符 URLEncoder.encode(); 服务器端: 默认的编码 iso-8859-1 和 本地编码(gbk)

    发现 数据

    �� gbk->utf-8 ??? utf-8 -> iso-8859-1 编码不存在 锟脚达拷锟斤拷 无药可救 删除了重写。

    提交数据(乱码问题)

    GET方式提交数据

    • get方式提交的数据是直接拼接在url的末尾

      final String path = "http://192.168.1.104/Web/servlet/CheckLogin?name=" + name + "&pass=" + pass;
      
    • 发送get请求,代码和之前一样

      URL url = new URL(path);
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      conn.setRequestMethod("GET");
      conn.setReadTimeout(5000);
      conn.setConnectTimeout(5000);
      if(conn.getResponseCode() == 200){
      
      }
      
    • 浏览器在发送请求携带数据时会对数据进行URL编码,我们写代码时也需要为中文进行URL编码

      String path = "http://192.168.1.104/Web/servlet/CheckLogin?name=" + URLEncoder.encode(name) + "&pass=" + pass;
      

    GET方式提交数据的缺点: * 组拼http的URL的方式不安全。 * GET方式提交数据,对数据的长度是有要求的。http规范最大长度4K。

    POST方式提交数据

    • post提交数据是用流写给服务器的
    • 协议头中多了两个属性

      • Content-Type: application/x-www-form-urlencoded,描述提交的数据的mimetype
      • Content-Length: 32,描述提交的数据的长度

        //给请求头添加post多出来的两个属性
        String data = "name=" + URLEncoder.encode(name) + "&pass=" + pass;
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", data.length() + "");
        
    • 设置允许打开post请求的流

      conn.setDoOutput(true);
      
    • 获取连接对象的输出流,往流里写要提交给服务器的数据

      OutputStream os = conn.getOutputStream();
      os.write(data.getBytes());
      

    POST方式提交数据的优缺点: * 代码写起来麻烦 注意4个细节。

    优点: * 安全。 * 提交数据的长度没有限制。

  • 相关阅读:
    Linux du命令
    log
    为什么基址不会变?
    游戏辅助分类
    什么是nProtect?
    Linux启动过程详解
    Restorator 2018 v3.90汉化注册版 含注册码汉化激活教程
    LoadLibrary(C:softIDA 7.0IDA 7.0pluginspython64.dll) error: 找不到指定的模块。 C:softIDA 7.0IDA 7.0pluginspython64.dll: can't load file LoadLibrary(C:softIDA 7.0IDA 7.0pluginspython64.dll) erro
    windows 安装python2.7
    ida 下载
  • 原文地址:https://www.cnblogs.com/istarry/p/4426050.html
Copyright © 2011-2022 走看看