• Android总结四(Handler、网络编程)


    一、耗时操作

      1.什么是ANR

        在应用程序的主线程中执行一段耗时的代码, 就有可能出现ANR异常.

        耗时的代码未执行结束时, 界面会卡住, 用户对界面进行了操作, 10秒之后耗时代码如果还未结束, 就会出现ANR异常

      2.怎么避免ANR

        主线程中不要执行耗时的代码

        如果一定要做耗时的事情, 开启新线程, 在新线程中执行

      3.UI Thread

        安卓手机中主线程负责刷新界面, 以及处理用户的操作

        应用程序的界面都是由主线程创建的

        界面的修改也只能在主线程中执行

      4.Handler

        有的时候我们需要执行一些耗时的代码, 会开启新线程, 这时又需要更新界面, 必须在主线程中操作, 那么就需要使用Handler来进行线程之间的通信

        1)sendMessage():

          新线程向主线程发送一个包含数据的消息, 主线程获取消息中的数据

          在主线程中创建Handler子类对象, 重写handleMessage()方法

          新线程中可以使用Handler的引用调用sendMessage()方法, 发送一个Message对象

          只要执行了sendMessage()方法, 那么主线程会自动执行handleMessage()方法, 收到Message对象

        2)post():

          新线程向主线程发送一段代码, 主线程直接执行

          在主线程中创建Handler对象

          新线程中可以使用Handler调用post()方法发送一个Runnable对象

          主线程会自动执行Runable的run()

      5.示例代码

    sendMessage:

    package com.gnnuit.anr;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.os.SystemClock;
    import android.app.Activity;
    import android.view.Menu;
    import android.view.View;
    import android.widget.TextView;
    
    public class SendMessageActivity extends Activity {
    
        private TextView tv;
        private Handler handler = new Handler() {
            public void handleMessage(android.os.Message msg) {// 该方法在sendMessage()方法之后执行, 形参就是发送过来的Message对象
                tv.setText(msg.obj + "");// 主线程更新界面
            };
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        public void go(View v) {
            new Thread() {
                public void run() {
                    for (int i = 1; i < 10; i++) {
                        System.out.println(i + "");
                        SystemClock.sleep(1000);
                        // Message msg = new Message(); // 创建消息对象,此种方法效率不高
                        Message msg = handler.obtainMessage(); // 从消息池中获取一个Message
                        msg.obj = i;// 把数据放在消息对象中
                        handler.sendMessage(msg);// 在新线程中发送消息对象, 主线程会自动执行handleMessage()方法
                    }
                };
            }.start();
        }
    
    }

    post:

    package com.gnnuit.anr;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.SystemClock;
    import android.app.Activity;
    import android.view.Menu;
    import android.view.View;
    import android.widget.TextView;
    
    public class PostActivity extends Activity {
    
        private TextView tv;
        private Handler handler = new Handler();
        private int i;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        public void go(View v) {
            System.out.println("go:" + Thread.currentThread().getName() + "");
            new Thread() {
                public void run() {
                    System.out.println("for:" + Thread.currentThread().getName() + "");
                    for (i = 1;; i++) {
                        System.out.println(i + "");
                        handler.post(new Runnable() {// 在新线程中使用Handler向主线程发送一段代码, 主线程自动执行run()方法
    
                            @Override
                            public void run() {
                                System.out.println("run:" + Thread.currentThread().getName() + "");
                                tv.setText(i + "");
                            }
                        });
                        SystemClock.sleep(1000);
                    }
                };
            }.start();
        }
    
    }

     二、网络编程

      1.获取网络文本

        使用URL封装一个地址

        openConnection()得到HttpUrlConnection对象

        getResponseCode()得到响应码

        getInputStream()得到输入流读取数据

        注意: 安卓4.0以后联网需要开启新线程, 在新线程中操作界面还需要使用Handler

        示例代码:

    package com.gnnuit.nettext;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.app.Activity;
    import android.view.Menu;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.TextView;
    import android.widget.Toast;
    
    public class ClassicActivity extends Activity {
    
        private EditText et;
        private TextView tv;
        private Handler handler = new Handler();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            et = (EditText) findViewById(R.id.et);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        public void go(View v) {
    
            new Thread() {
                public void run() {
                    try {
                        TextService service = new TextService();
                        String path = et.getText().toString().trim();// 从EditText获取地址
                        final String text = service.getText(path);// 访问网络, 得到文本
                        handler.post(new Runnable() {
    
                            @Override
                            public void run() {
                                tv.setText(text);// 设置到TextView中
                            }
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                        handler.post(new Runnable() {
    
                            @Override
                            public void run() {
                                Toast.makeText(getApplicationContext(), "网络连接失败", Toast.LENGTH_SHORT).show();
                            }
                        });
                    }
                };
            }.start();
        }
    
    }

    TextService.java

    package com.gnnuit.nettext;
    
    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    import android.accounts.NetworkErrorException;
    
    public class TextService {
    
        public String getText(String path) throws Exception {
            URL url = new URL(path);// 把路径封装成URL对象
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 打开连接对象(还未联网)
            conn.setReadTimeout(5000);// 设置超时时间, 如果连接超过5000毫秒未响应, 就抛出异常
    
            int code = conn.getResponseCode();// 获取响应码(真正联网)
            if (code == 200) {// 如果成功
                InputStream is = conn.getInputStream();// 获取输入流
                ByteArrayOutputStream os = new ByteArrayOutputStream();// 可以写出数据到内存的输出流
                byte[] buffer = new byte[8192];
                int length;
                while ((length = is.read(buffer)) != -1) {// 从网络读取数据
                    os.write(buffer, 0, length);// 向内存写出数据
                }
                is.close();
                os.close();
                conn.disconnect();
                byte[] bytes = os.toByteArray();// 把写到内存的数据读取出来
                String text = new String(bytes);// 解码为字符串(默认UTF-8)
                return text;
            }
            conn.disconnect();
            throw new NetworkErrorException("服务器正忙:" + code);
        }
    
    }

      2.AsyncHttpClient

        AsyncHttpClient是一个开源项目, 可以自动创建新线程联网, 不论成功或失败都会在主线程执行回调函数

      示例代码:

    package com.gnnuit.nettext;
    
    import org.apache.http.Header;
    
    import com.loopj.android.http.AsyncHttpClient;
    import com.loopj.android.http.TextHttpResponseHandler;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.Menu;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.TextView;
    import android.widget.Toast;
    
    public class AsyncActivity extends Activity {
    
        private EditText et;
        private TextView tv;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            et = (EditText) findViewById(R.id.et);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        public void go(View v) {
            String path = et.getText().toString().trim();
            AsyncHttpClient client = new AsyncHttpClient();
            client.get(path, new TextHttpResponseHandler() {
    
                @Override
                public void onSuccess(int statusCode, Header[] headers, String responseString) {
                    tv.setText(responseString);
                }
    
                @Override
                public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                    Toast.makeText(getApplicationContext(), "服务器忙" + statusCode, Toast.LENGTH_SHORT).show();
                    throwable.printStackTrace();
                }
            });
        }
    
    }

      3.获取网络图片

        使用AsyncHttpClient获取图片数据

        由于图片数据通常较大, 应该使用缓存, 当数据接收到之后保存在本地

        下次再访问相同路径时添加请求头, If-Modified-Since, 传递文件的最后修改时间

        服务端如果响应304, 就读取本地数据, 如果响应200, 代表服务端数据已更新, 重新从服务端读取

        注意: 也可以使用SmartImageView, 但是如果服务端同名文件更新, 有Bug

    package com.gnnuit.netimage;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.URLEncoder;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Locale;
    
    import org.apache.http.Header;
    
    import com.loopj.android.http.AsyncHttpClient;
    import com.loopj.android.http.AsyncHttpResponseHandler;
    import com.loopj.android.image.SmartImageView;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.view.Menu;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.ImageView;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    
        //private com.loopj.android.image.SmartImageView iv;
        private EditText et;
        private ImageView iv;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            et = (EditText) findViewById(R.id.et);
            //iv = (SmartImageView) findViewById(R.id.iv);
            iv=(ImageView) findViewById(R.id.iv);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        public void go(View v) throws Exception {
            // iv.setImageUrl(et.getText().toString().trim());//
    
            String path = et.getText().toString().trim();                                    // 获取网络地址
            final File file = new File(getCacheDir(), URLEncoder.encode(path, "UTF-8"));    // 定义缓存文件的路径
            
            AsyncHttpClient client = new AsyncHttpClient();    
            if (file.exists())                                                                // 如果缓存文件存在
                client.addHeader("If-Modified-Since", format(file.lastModified()));            // 添加请求头
            
            client.get(path, new AsyncHttpResponseHandler() {
                public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                    if (statusCode == 200) {
                        Bitmap bm = BitmapFactory.decodeByteArray(responseBody, 0, responseBody.length);    // 获取网络数据
                        iv.setImageBitmap(bm);
                        try {
                            FileOutputStream out = new FileOutputStream(file);
                            out.write(responseBody);    // 保存到本地
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                    if (statusCode == 304) {
                        Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());    // 从缓存文件读取数据
                        iv.setImageBitmap(bm);
                    } else
                        Toast.makeText(getApplicationContext(), "网络错误: " + statusCode, Toast.LENGTH_SHORT).show();
                }
            });
        }
        
        public String format(long ms) {
            Date date = new Date(ms);
            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
            String s = format.format(date);
            return s;
        }
    
    }

      3.获取网络XML

        使用AsyncHttpClient和TextHttpResponseHandler获取文本数据

        使用XmlPullParser和StringReader解析XML生成JavaBean

      4.获取网络JSON

        使用AsyncHttpClient和JsonHttpResponseHandler获取JSONArray

        使用JSONArray和JSONObject解析JSON生成JavaBean

    示例代码:

    package com.gnnuit.netxml;
    
    import java.io.StringReader;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.http.Header;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    import org.xmlpull.v1.XmlPullParser;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Xml;
    import android.view.View;
    import android.widget.Toast;
    
    import com.loopj.android.http.AsyncHttpClient;
    import com.loopj.android.http.JsonHttpResponseHandler;
    import com.loopj.android.http.TextHttpResponseHandler;
    
    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        
        public void getXml(View v) {
            new AsyncHttpClient().get("http://192.168.1.251:8080/WebServer/persons.xml", new TextHttpResponseHandler() {
                public void onSuccess(int statusCode, Header[] headers, String responseString) {
                    List<Person> persons = parseXml(responseString);
                    for (Person p : persons) 
                        System.out.println(p);
                    Toast.makeText(getApplicationContext(), "获取XML成功", Toast.LENGTH_SHORT).show();
                }
                public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                }
            });
        }
        
        public void getJson(View v) {
            new AsyncHttpClient().get("http://192.168.1.251:8080/WebServer/persons.js", new JsonHttpResponseHandler() {
                public void onSuccess(int statusCode, Header[] headers, JSONArray arr) {
                    try {
                        for (int i = 0; i < arr.length(); i++ ) {    // 遍历JSONArray
                            JSONObject obj = arr.getJSONObject(i);    // 得到每一个JSONObject
                            int id = obj.getInt("id");                // 获取每个JSONObject中的数据, 封装成Person
                            String name = obj.getString("name");
                            int age = obj.getInt("age");
                            Person p = new Person(id, name, age);
                            System.out.println(p);
                        }
                        Toast.makeText(getApplicationContext(), "获取JSON成功!!!", Toast.LENGTH_SHORT).show();
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            });
            
            /*
            new AsyncHttpClient().get("http://192.168.1.251:8080/WebServer/persons.js", new TextHttpResponseHandler() {
                public void onSuccess(int statusCode, Header[] headers, String responseString) {
                    List<Person> persons = parseJson(responseString);
                    for (Person p : persons) 
                        System.out.println(p);
                    Toast.makeText(getApplicationContext(), "获取JSON成功", Toast.LENGTH_SHORT).show();
                }
                public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                }
            });
            */
        }
        
        @SuppressWarnings("unused")
        private List<Person> parseJson(String json) {
            List<Person> persons = new ArrayList<Person>();
            try {
                JSONArray arr = new JSONArray(json);        // 把字符串封装成一个JSONArray
                for (int i = 0; i < arr.length(); i++ ) {    // 遍历JSONArray
                    JSONObject obj = arr.getJSONObject(i);    // 得到每一个JSONObject
                    int id = obj.getInt("id");                // 获取每个JSONObject中的数据, 封装成Person
                    String name = obj.getString("name");
                    int age = obj.getInt("age");
                    Person p = new Person(id, name, age);
                    persons.add(p);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return persons;
        }
        
        private List<Person> parseXml(String xml) {
            List<Person> persons = new ArrayList<Person>();
            try {
                XmlPullParser parser = Xml.newPullParser();
                parser.setInput(new StringReader(xml));
                Person p = null;
                for (int type = parser.getEventType(); type != XmlPullParser.END_DOCUMENT; type = parser.next()) {
                    if (type == XmlPullParser.START_TAG) {
                        if ("person".equals(parser.getName())) {        // 如果开始的是person, 创建对象, 获取id数据
                            String id = parser.getAttributeValue(0);
                            p = new Person();
                            p.setId(Integer.parseInt(id));
                            persons.add(p);
                        } else if ("name".equals(parser.getName())) {    // 如果开始的是name, 获取下一个文本
                            String name = parser.nextText();
                            p.setName(name);
                        } else if ("age".equals(parser.getName())) {    // 如果开始的是age, 获取下一个文本
                            String age = parser.nextText();
                            p.setAge(Integer.parseInt(age));
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return persons;
        }
    
    }
  • 相关阅读:
    SQL 二进制和字符互转
    拒绝了对对象 'sp_OACreate' (数据库 'mssqlsystemresource',架构 'sys')的 EXECUTE 权限。
    SQL SERVER 正则替换
    SQL SERVER 算法执行效率
    webmin 安装
    MySQL5.6 PERFORMANCE_SCHEMA 说明
    flex 属性
    CSS 实现左侧固定,右侧自适应两栏布局的方法
    项目前端知识点
    为data中的某一个对象添加一个属性不起作用——this.$set的正确使用
  • 原文地址:https://www.cnblogs.com/FlySheep/p/3841190.html
Copyright © 2020-2023  润新知