"Android中的访问网络"-Android面试必问"精华技能点"汇总

Android中的访问网络


一.Android如何访问网络?

1.自带的HttpClientConnction,简称HttpClient

  • 5.0之前一直使用的网络框架,但是5.0之后谷歌大爷就不推荐使用了,推荐了谁呢?就行下面那位.

2.自带的HttpUrlConnection

  • 现在谷歌官网建议使用HttpUrlConnction框架,HttpURLConnection 原则上要比 httpclient快 ,但是httpclient分装了很多很好的东东,可以拿来就用,无需重复制造轮子。

1.Android使用HttpUrlConnection进行GET请求

(请点击访问图文+代码详细演示GET请求)

1.Android使用HttpUrlConnection进行POST请求

(请点击访问图文+代码详细演示POST请求)


二.如何解析服务器传来的JSON文件?

在我们的tomcat服务器里的Root目录放入我们的文件夹和文件:

1.解析Json对象

过程:
1.访问网络;
2.get或者post获取流文件;
3.流文件转成字符串形式;
4.通过JsonObject(JsonStr)得到对象;
5.再通过对象get("键")就能获取到想要的值;
  • json名字是student.json,内容为:
{"name":"XiaoMing", "age":18, "city":"ShenZheng"}
  • 解析代码
private void parseJson() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            // student: {"name":"XiaoMing", "age":18, "city":"ShenZheng"}
            try {
                // url
                URL url = new URL("http://10.0.2.2:8080/json/json/student.json");        
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                // time
                conn.setConnectTimeout(3000);
                conn.setReadTimeout(3000);
                // getOrPost
                conn.setRequestMethod("GET");
                InputStream is = conn.getInputStream();
                // 刘变成字符串后续处理
                String JsonStr = DataUtils.Stream2String(is);
                 /*--------------JsonObject--------------*/
                //变成对象JsonObject
                 JSONObject object = new JSONObject(JsonStr);
                 String name = object.getString("name");
                 int age = object.getInt("age");
                 String city = object.getString("city");
                 System.out.println("name = " + name + ", age = " + age + ", city = " + city);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

输出结果:

System.out: name = XiaoMing, age = 18, city = ShenZheng

2.解析Json数组,及数组中对象

  • 文件名字为students.json,内容如下
[
    {"name":"XiaoMing", "age":18, "city":"ShenZheng"},
    {"name":"XiaoMing2", "age":19, "city":"ShenZheng2"},
    {"name":"XiaoMing3", "age":20, "city":"ShenZheng3"}
]
  • 解析过程和上面的区别:
    得到字符串后通过JsonArray(jsonStr)得到数组,数组里是一个一个对象.

想更改路径:

URL url = new URL("http://10.0.2.2:8080/json/json/student.json");
  • 代码如下
/*--------------JsonArray--------------*/
// 变成JsonArray
JSONArray array = new JSONArray(JsonStr);
// 获取第几组对象
for (int i = 0; i < array.length(); i++) {
    JSONObject object = array.getJSONObject(i);
    System.out.println(
            "   name : " + object.get("name") +
            ",  age : " + object.get("age") +
            ",  city : " + object.get("city"));
}

输出结果:

System.out:    name : XiaoMing, age : 18,   city : ShenZheng
System.out:    name : XiaoMing2,    age : 19,   city : ShenZheng2
System.out:    name : XiaoMing3,    age : 20,   city : ShenZheng3

2.解析Json数组里的Json对象,再解析Json对象里的Json数组,再得到对象.

  • json的名字为studentss.json,内容如下(格式必须要正确,括号逗号):
[
    {"name":"XiaoMing", "age":18, "city":"ShenZheng"},
    {"name":"XiaoMing2", "age":19, "city":"ShenZheng2"},
    {"name":"XiaoMing3", "age":20, "city":"ShenZheng3"},
    {"money":
      [
        {"area":"A","totalmoney":16000,"before":15000,"other":1000},
        {"area":"B","totalmoney":16000,"before":16000,"other":1000},
        {"area":"C","totalmoney":15000,"before":14000,"other":1000}
      ]
    }
]
  • 解析过程:
  • 通过观察发现:

    • 1.数组的长度是4,前三组一样都是json对象,所以可以做相同出来
    • 2.第四组特殊,先获取数组的第四个对象,然后获取对象里的数组,然后再循环数组里的对象在解析即可.
  • 代码如下

/*--------------JsonArray++ --------------*/

// 获取数组中的数组(有4组,前三组一样,第四组不同)
JSONArray array = new JSONArray(JsonStr);
//先解析同样的前三组
for (int i = 0; i < array.length() - 1; i++) {
    JSONObject object = array.getJSONObject(i);
    System.out.println(
            "   name : " + object.get("name") + 
            ",  age : " + object.get("age") + 
            ",  city : " + object.get("city"));
}
//从数组中获取"对象"最后一个
JSONObject obj = array.getJSONObject(array.length() - 1);
//有从"对象中获取数组"
JSONArray arrayy = obj.getJSONArray("money");
for (int a = 0; a < arrayy.length(); a++) {
    JSONObject object = arrayy.getJSONObject(a);
    System.out.println(
            "   area = " + object.get("area") + 
            ", totalmoney = " + object.get("totalmoney") +
            ", before = " + object.get("before") + 
            ",  other = " + object.get("other"));
}

输出结果:

System.out: name : XiaoMing,    age : 18,   city : ShenZheng
System.out: name : XiaoMing2,   age : 19,   city : ShenZheng2
System.out: name : XiaoMing3,   age : 20,   city : ShenZheng3
System.out: area = A, totalmoney = 14000, before = 15000,  other = 1000
System.out: area = B, totalmoney = 15000, before = 16000,  other = 1000
System.out: area = C, totalmoney = 13000, before = 14000,  other = 1000

三.如何生成的JSON文件?

1.生成json对象-通过Map:

  • 过程:

    • 1.通过一个 Map添加不同的键和值.
    • 2.json对象构造传入即可

2.生成json对象-直接put添加:

  • 过程:
    • 直接通过json对象put键和值即可

3.生成json数组-Map结合List

  • 过程:
    • 1.通过多个 Map添加不同 的键和值
    • 2.新建一个 List,并添加这多个 Map

代码如下:

/**
     * 生成Json
     */
    private void createJson() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
            /*--------------生成json对象:通过HashMap--------------*/
                    HashMap<String, String> hm = new HashMap<>();
                    hm.put("name", "小何");
                    hm.put("age", "18");
                    hm.put("score", "99");
                    // Json对象构造传入
                    JSONObject object = new JSONObject(hm);
                    System.out.println(
                            "name = " + object.get("name") + 
                            ", age = " + object.get("age") + 
                            ", score = " + object.get("score"));

            /*------------生成json对象:直接通过对象.put----------------*/
                    JSONObject objec = new JSONObject();
                    objec.put("name", "小何");
                    objec.put("age", "18");
                    objec.put("score", "99");

                    System.out.println(
                            "name = " + objec.get("name") + 
                            ", age = " + objec.get("age") + 
                            ", score = " + objec.get("score"));
            /*------生成Json数组:通过HashMap生成对象,再通过ArrayList添加过个对象,最终Json数组构造传入------*/
                    Map<String, String> m1 = new HashMap<>();
                    m1.put("name", "小何");
                    m1.put("age", "18");
                    m1.put("score", "99");
                    Map<String, String> m2 = new HashMap<>();
                    m2.put("name", "小路");
                    m2.put("age", "18");
                    m2.put("score", "99");
                    Map<String, String> m3 = new HashMap<>();
                    m3.put("name", "小高");
                    m3.put("age", "18");
                    m3.put("score", "99");

                    List<Map<String, String>> list = new ArrayList<>();
                    list.add(m1);
                    list.add(m2);
                    list.add(m3);
                    JSONArray array = new JSONArray(list);

                    for (int i = 0; i < array.length(); i++) {
                        JSONObject obj = array.getJSONObject(i);
                        System.out.println(
                                obj.get("name") + ", " + 
                                obj.get("age") + ", " + 
                                obj.get("score"));
                    }
                    /*---------------增强版,添加对象,以及包含数组的对象-------------*/
                    //lis先放前两个对象
                    List<Map> lis = new ArrayList<Map>();
                    Map h1 = new HashMap();
                    h1.put("name", "小明");
                    h1.put("age", 11);
                    Map h2 = new HashMap();
                    h2.put("name", "小明");
                    h2.put("age", 11);
                    lis.add(h1);
                    lis.add(h2);
                    //有数组的对象
                    Map h3 = new HashMap();
                    h3.put("info", lis);
                    //listAll放三个对象,第三个对象里有数组
                    List listAll = new ArrayList();
                    listAll.add(h1);
                    listAll.add(h2);
                    listAll.add(h3);

                    JSONArray jsonArray = new JSONArray(listAll);
                    //通过toString 就能得到json内容;
                    String s = jsonArray.toString();
                    System.out.println(s);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

打印结果:

/*--------------生成json对象:通过HashMap--------------*/
07-11 03:33:03.420 30275-30289/? I/System.out: name = 小何, age = 18, score = 99
/*------------生成json对象:直接通过对象.put----------------*/
07-11 03:33:03.420 30275-30289/? I/System.out: name = 小何, age = 18, score = 99
/*---------生成Json数组:通过HashMap生成对象,再通过ArrayList添加过个对象,最终Json数组构造传入---------*/
07-11 03:33:03.424 30275-30289/? I/System.out: 小何, 18, 99
07-11 03:33:03.424 30275-30289/? I/System.out: 小路, 18, 99
07-11 03:33:03.424 30275-30289/? I/System.out: 小高, 18, 99
07-11 03:33:03.424 30275-30289/? 
/*---------------增强版,添加对象,以及包含数组的对象-------------*/
I/System.out: 
[
    {"name":"小明","age":11},
    {"name":"小明","age":11},
    {"info":
        [
            {"name":"小明","age":11},
            {"name":"小明","age":11}
        ]
    }
]

四.如何解析服务器传来的XML格式的数据?

(在服务器放好文件,然后get/post请求获取数据,接着解析)

  • 1.获取pull解析对象.
  • 2.设置读取流,以及格式
  • 2.获取解析对象的类型.
  • 4.循环从头部开始,即while循环不等于最后文档/文件类型.
  • 5.获取标签名,然后如果等于自己想要的内容,就输出下一个文本
  • 6.然后解析完一个类型接着下一个类型:type = pull.next();

xml文件名为sutdent.xml,内容如下

<students>
    <student>
        <name>zhangsan</name>
        <age>18</age>
        <score>98</score>
    </student>
    <student>
        <name>lishi</name>
        <age>29</age>
        <score>97</score>
    </student>
</students>

解析的代码如下:

/*--------------解析XML--------------*/
try {
    // 1.获取Pull解析工具对象
    XmlPullParser pull = Xml.newPullParser();
    // 2.设置输入流,编码
    pull.setInput(is, "utf-8");
    //3.获取类型
    int type = pull.getEventType();
    //解析循环到底
    while (type != XmlPullParser.END_DOCUMENT) {//不是最后一个文件
        //<name>zhangsan</name>只考虑第name后面取
            //5.获取标签名
            if ("name".equals(pull.getName())) {
                //获取下一个文本
                String name = pull.nextText();
                System.out.println(name);
            } else if ("age".equals(pull.getName())) {
                String age = pull.nextText();
                System.out.println(age);
            } else if ("score".equals(pull.getName())) {
                String score = pull.nextText();
                System.out.println(score);
            }
        //4.解析下一个事件,来到了开头,如果忘记写就不能往下了,一个都读不到.死循环
        type = pull.next();
    }
} catch (Exception e) {
    e.printStackTrace();
}

输出结果为:

System.out: zhangsan
System.out: 18
System.out: 98
System.out: lishi
System.out: 29
System.out: 97

五.如何生成的XML文件?

步骤:

  • 1.获取序列化对象
  • 2.设置输出流以及格式
  • 3.声明开始文档/文件
  • 4.开始写开始标签和结束标签(有多少写多少,只要对应即可)
  • 5.最后声明一个结束文档即可

需求:

想要生成一个如下的xml

<?xml version="1.0" encoding="UTF-8"?>
<students>
    <student>
        <name>zhangsan</name>
        <age>18</age>
        <score>98</score>
    </student>
    <student>
        <name>lishi</name>
        <age>29</age>
        <score>97</score>
    </student>
</students>

代码如下:

private void createXML() {
    /*--------------生成xml--------------*/
    try {
        //1.生成序列化对象,刚才是解析,这里是序列化
        XmlSerializer ser = Xml.newSerializer();
        //2.设置输出流
        File dir = new File("data/data/" + getPackageName() + "/" + "xml/");
        if (!dir.exists()) {
            dir.mkdir();
        }
        File file = new File(dir, "create.xml");
        FileOutputStream fos = new FileOutputStream(file);
        //先指定输出位置,否则下面的开始文档会空指针.
        ser.setOutput(fos, "utf-8");
        //3.声明开始文件(包含编码格式,还有是否独立)
        ser.startDocument("utf-8", true);
    /*
    <?xml version="1.0" encoding="UTF-8"?>
    <students>
        <student>
            <name>zhangsan</name>
            <age>18</age>
            <score>98</score>
        </student>
        <student>
            <name>lishi</name>
            <age>29</age>
            <score>97</score>
        </student>
    </students>
    */
            //4.开始标签
            ser.startTag("", "students");
                ser.startTag("", "student");
                    ser.startTag("", "name");
                        //内容:text
                        ser.text("zhangshan");
                    ser.endTag("", "name");
                    //5.结束标签
                    ser.startTag("", "age");
                        ser.text("18");
                    ser.endTag("", "age");
                    ser.startTag("", "score");
                        ser.text("98");
                    ser.endTag("", "score");
                ser.endTag("", "student");
                    ser.startTag("", "student");
                        ser.startTag("", "name");
                    ser.text("lishi");
                    ser.endTag("", "name");
                    ser.startTag("", "age");
                        ser.text("29");
                    ser.endTag("", "age");
                    ser.startTag("", "score");
                        ser.text("97");
                    ser.endTag("", "score");
                ser.endTag("", "student");
            ser.endTag("", "students");
            //6.结束文件:加上结束文档,否则输出不了
        ser.endDocument();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

生成文件:
这里写图片描述

文件内容为:

<?xmlversion='1.0'encoding='utf-8'standalone='yes'?>
<students>
    <student>
        <name>zhangshan</name>
        <age>18</age>
        <score>98</score>
    </student>
    <student>
        <name>lishi</name>
        <age>29</age>
        <score>97</score>
    </student>
</students>

四.如何从”本地和网络上”加载一个大图片显示到界面,而且要避免OOM?

  • 思路:

    • 归根结底就是不要把图片马上存到内存,而是放置符合屏幕或者自定义大小的图片.
    • 1.目的都是获取图片的信息,然后获取然后再根据我们的自定义比例,重新再设置图片并加载到内存
    • 2.要区别本地加载大图片和网络加载大图片
      • 1.本地加载大图片:可以同同一个option,同一个解析
      • 2.网络加载大图片:要进行两次访问:
        • 第一次获取图片的不存入内存,而是只要获取长宽
        • 第二次获取图片,设定比例,然后存入内存,最终显示图片
  • 设置图片比例,选择长的一边比例占据;
    这里写图片描述

读取本地图片:

详细代码如下:

/**
 * 读取本地发图片的方法:
 * 
 * 用标准的做法即可:
 * 
 * 1.图片不存入内存,只想获取宽高 just = true;
 * 2.解析图片,并且带入"选项",就可以下一步获取比例了
 * 3.获取图片和屏幕的比例,并设置"选项"的比例;
 * 4.存入内存 just = false;
 * 5.再解析图片->显示即可;
 */
private void reateLocalPic() {
    new Thread(new Runnable() {
        @Override
        public void run() {
    /*--------------不存内存,获取比例--------------*/
            BitmapFactory.Options opt = new BitmapFactory.Options();
            //1.
            opt.inJustDecodeBounds = true;
            String path = "data/data/" + getPackageName() + "/files/" + "big.png";
            //2.
            BitmapFactory.decodeFile(path, opt);
            //3.
            int outHeight = opt.outHeight;
            int outWidth = opt.outWidth;
            Display display = getWindowManager().getDefaultDisplay();
            int height = display.getHeight();
            int width = display.getWidth();
            int sH = (int) (outHeight / (float) height + 0.5f);
            int sW = (int) (outWidth / (float) width + 0.5f);
            int sample = 1;//原来的大小
            if (sH > 1 && sW > 1) {
                sample = sH > sW ? sH : sW;
            }
            opt.inSampleSize = sample;
    /*------------存入内存,显示图片----------------*/
            //4.
            opt.inJustDecodeBounds = false;
            //5.
            final Bitmap bitmap = BitmapFactory.decodeFile(path, opt);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mIv.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

读取网络图片:

详细代码如下:

/**
     * 读取网络图片:
     * 思维和读取本地是一样的,但是注意:
     * 但是当计算出缩放比再通过
     * 1.设置比例,
     * 2.存入内存,
     * 3.解析流放入选项,一样的过程时,发现居然不显示图片:
     * <p/>
     * 日志发现输出一行SkImageDecoder::Factory returned null信息,返回的是空对象,
     * 原因:
     * 代码中两次使用了BitmapFactory.decodeStream(is, outPadding, options)方法,
     * 即两次使用了同一个InputStream流对象,
     * 在第二次使用时流的起始位置已经移动到末尾了,所以返回的是空
     * <p/>
     * 解决:
     * 访问两次网络:
     * 第一次获取流,不存内存获取图片比例
     * 第二次获取流,设置比例,存内存,显示图片
     */
    private void readNetPic() {

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    /**
                     * 第一次访问网络,获取图片的大小和屏幕的比例
                     * 获取适应屏幕的图片的大小
                     */
                    /*--------------第一次访问:不存内存,获取比例--------------*/
                    URL url = new URL("http://10.0.2.2:8080/json/imgs/big.png");
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    // time
                    conn.setConnectTimeout(3000);
                    conn.setReadTimeout(3000);
                    // getOrPost
                    conn.setRequestMethod("GET");
                    InputStream is = conn.getInputStream();
                    //获取屏幕高宽
                    Display display = getWindowManager().getDefaultDisplay();

                    int okH = display.getHeight();//也是目标尺寸
                    int okW = display.getWidth();

                    System.out.println("屏幕 高 : " + okH + ", 屏幕 宽 : " + okW);
                    BitmapFactory.Options opt = new BitmapFactory.Options();
                    //只获取图片信息
                    opt.inJustDecodeBounds = true;
                    //解析并放入选项下面才能获取图片的高,否则空指针
                    BitmapFactory.decodeStream(is, null, opt);
                    //读取图片的高,宽
                    int outHeight = opt.outHeight;
                    int outWidth = opt.outWidth;
                    System.out.println("图片 高 : " + outHeight + ", 图片 宽 : " + outWidth);
                    //求图片的高和屏幕的高的比例,宽度也一样
                    int sh = (int) (outHeight / (float) okH + 0.5f);
                    int sw = (int) (outWidth / (float) okW + 0.5f);
                    //对比比例大的,最好了比喻:竖直的屏幕,横向的大图,保存的当然是大的横向才能显示完.
                    System.out.println("高度比 : " + sh + ", 宽度比 : " + sw);
                    int sample = 1;
                    if (sh >= 1 && sw >= 1) {
                        sample = sh > sw ? sh : sw;
                    }
                    /*--------------第二次访问:存内存,设置比例,显示图片--------------*/
                    setPicAndShow(sample);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            /**
             * 第二次请求,显示图片
             * @param sample
             * @throws Exception
             */
            private void setPicAndShow(int sample) throws Exception {
                URL url = new URL("http://10.0.2.2:8080/json/imgs/big.png");
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                // time
                conn.setConnectTimeout(3000);
                conn.setReadTimeout(3000);
                // getOrPost
                conn.setRequestMethod("GET");
                InputStream is = conn.getInputStream();

                BitmapFactory.Options opt = new BitmapFactory.Options();
                //设置比例
                opt.inSampleSize = sample;
                System.out.println(sample);
                //出人内存
                opt.inJustDecodeBounds = false;
                final Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mIv.setImageBitmap(bitmap);
                    }
                });
            }
        }).start();
    }

五.如何播放网络视频?

VideoView封装了类对MediaPlayer进行调用,前者是个控件,后者是播放音频/视频的具体内部部件
VideoView 调用了 MediaPlayer 来播放视频,提供了一些视频播放的辅助功能。

1.播放本地和网上音乐

(网上资源加权限)
1.获取MediaPlayer对象
2.对象准备
(或者直接采用异步准备+准备监听+把播放内容放到监听里即可)
3.对象播放
4.后续的进度保存可以自定义设置

2.播放本地和网上视频

(网上资源要加权限)

  • 1.用VideoView控件
    • 1.设置路径
    • 2.设置控制器
    • 3.控制器设置绑定View(控件),
    • 4.控件设置控制器
    • 5.开始即可
  • 2.用MediaPlayer和SurView结合
    • 1.设置和获取Serview控件
    • 2.得到控件的控制器holder
    • 3.控制器设置回调-创建和销毁
    • 4.在回调的创建里创建mediaplayer
    • 5.才销毁的时候存sp进度
    • 6.下次先获取进度再播放
  • *

3.万能第三方开源播放器 vitamioPlayer

兼容性好,几乎兼容所有的格式;生命周期和mediaplayer一样,非常好用


六.常见的访问网络API都有哪些?

xUtils:

老牌控件:底层是httpclient

volley:

谷歌2013发布,使得更快,简单,健壮.

okhttp:

谷歌工程师写的
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值