9 (上)看看精彩的世界--使用网络技术

image.jpg
  • WebView的用法
  • 使用HttpURLConnection
  • 使用OkHttp
  • Pull解析方式

9.1 WebView的用法

WebView控件,借助它我们就可以在自己的应用程序里嵌入一个浏览器,从而非常轻松地展示各种各样的网页。

public class MainActivity extends AppCompatActivity
{

    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = (WebView) findViewById(R.id.web_view);
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webView.setWebViewClient(new WebViewClient());
        webView.loadUrl("http://www.baidu.com");
    }
}

调用WebView的getSettings()方法可以去设置一些浏览器的属性,调用了setJavaScriptEnabled()方法来让WebView支持JavaScript脚本。

我们调用了WebView的setWebViewClient()方法,并传入了一个WebViewClient实例。这段代码的作用是,当需要从一个网页跳转到另一个网页时,我们希望目标网页仍然在当前WebView中显示,而不是打开系统浏览器。

调用WebView的loadUrl()方法,并将网址传入,即可展示相应网页的内容。

由于本程序使用到了网络功能,而访问网络是需要申明权限的。

<uses-permission android:name="android.permission.INTERNET"/>

9.2 使用HTTP协议访问网络

对于HTTP协议,它的工作原理非常简单,就是客服端向服务器发出一条HTTP请求,服务器收到请求之后会返回一些数据给客服端,然后客服端再对这些数据进行解析和处理就可以了。

使用HttpURLConnection

我们就学习一下现在官方建议使用的HttpURLConnection的用法

首先需要获取到HttpURLConnection的实例,一般只需new出一个URL对象,并传入目标的网络地址,然后调用一下openConnection()方法即可。

 URL url = new URL("http://www.baidu.com");
connection = (HttpURLConnection) url.openConnection();

在得到了HttpURLConnection的实例之后,我们可以设置一下HTTP请求所使用的方法。常用的方法主要有两个:GET和POSTGET表示希望从服务器那里获取数据而POST则表示希望提交数据给服务器

connection.setRequestMethod("GET");

接下来就可以进行一些自由的定制了,比如设置连接超时,读取超时的毫秒数,以及服务器希望得到的一些消息头等。

connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);

之后再调用getInputStream()方法就可以获取到服务器返回的输入流了,剩下的任务就是对输入流进行读取。

InputStream in = connection.getInputStream();

最后可以调用disconnect()方法将这个HTTP连接关闭掉。

connection.disconnect();

整体代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener
{

    private TextView responseText;
    private Button sendRequest;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sendRequest = (Button) findViewById(R.id.send_request);
        responseText = (TextView) findViewById(R.id.response_text);
        sendRequest.setOnClickListener(this);

    }

    @Override
    public void onClick(View v)
    {
        switch (v.getId())
        {
            case R.id.send_request:
                setSendRequestWithHttpURLConnection();
                break;
            default:
                break;
        }
    }

    private void setSendRequestWithHttpURLConnection()
    {
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                HttpURLConnection connection = null;
                BufferedReader reader = null;
                try
                {
                    URL url = new URL("http://www.baidu.com");
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    InputStream in = connection.getInputStream();
                    //下面对获取到的输入流进行读取
                    reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null)
                    {
                        response.append(line);
                    }
                    showResponse(response.toString());
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
                finally
                {
                    if (reader != null)
                    {
                        try
                        {
                            reader.close();
                        } catch (IOException e)
                        {
                            e.printStackTrace();
                        }
                    }
                    if (connection != null)
                    {
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }

    private void showResponse(final String response)
    {
        runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                //在这里进行UI操作,将结果显示到界面上
                responseText.setText(response);
            }
        });
    }
    
}

在Send Request按钮的点击事件里调用了sendRequestWithHttpURLConnection()方法,在这个方法中先是开启了一个子线程,然后在子线程里使用HttpURLConnection发出一条HTTP请求,请求的目标地址就是百度的首页。接着利用BufferedReader对服务器返回的流进行读取,并将结果传入到了showResponse()方法中。而在showResponse()方法中则是调用了一个runOnUiThread()方法,然后在这个方法的匿名类参数中进行操作,将返回的数据显示到界面上。那么这里为什么要用这个runOnUiThread()方法呢?这是因为Android不允许在子线程中进行UI操作的,我们需要通过这个方法将线程切换到主线程,然后再更新UI元素。

如果是想要提交数据给服务器应该怎么办呢?只要将HTTP请求的方法改成POST,并在获取输入流之前把要提交的数据写出即可。注意每条数据都要以键值对的形式存在,数据与数据之间用"&"符号隔开,比如说我们想要向服务器提交用户名和密码

connection.setRequestMethod("POST");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("username=admin&password=123456");

9.2 使用OkHttp

在项目中添加OkHttp库的依赖。

compile 'com.squareup.okhttp3:okhttp:3.6.0'

添加上诉依赖会自动下载两个库,一个是OkHttp库,一个是OKio库,后者是前者的通信基础。

OkHttp的具体用法

首先需要创建一个OkHttpClient的实例。

OkHttpClient okHttpClient = new OkHttpClient();

接下来如果想要发起一条HTTP请求,就需要创建一个Request的对象。

Request request = new Request.Builder()
              .url("http://www.baidu.com")
              .build();

我们可以在最终的build()方法之前连缀很多其他方法来丰富这个Request对象。比如可以通过url()方法来设置目标的网络地址。

之后调用OkHttpClient的newCall()方法来创建一个Call()对象,并调用它的execute()方法来发送请求并获取服务器返回的数据,其中Response对象就是服务器返回的数据了。

Response response = okHttpClient.newCall(request).execute();

String responeData = response.body().string();

如果是发起一条POST请求会比GET请求稍微复杂一点,我们需要先构建出一个RequestBody对象来存放待提交的参数。

RequestBody requestBody = new FormBody.Builder()
                .add("username","admin")
                .add("password","123456")
                .build();

然后在Request.Builder中调用一下post()方法,将RequestBody对象传入。

Request request = new Request.Builder()
            .url("http://www.baidu.com")
            .post(requestBody)
            .build();

接下来就和GET请求一样了,调用execute()方法来发送请求并获取服务器返回的数据即可。
整体代码:

private void sendRequestWithOkHttp()
    {
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    OkHttpClient okHttpClient = new OkHttpClient();
                    Request request = new Request.Builder()
                            .url("http://www.baidu.com")
                            .build();
                    Response response = okHttpClient.newCall(request).execute();
                    showResponse(response.body().string());
                } catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }).start();
    }

9.3 解析XML格式文件

安装Apache软件,现存入一个XML文件

<apps>
    <app>
        <id>1</id>
        <name>Google Maps</name>
        <version>1.0</version>
    </app>

    <app>
        <id>2</id>
        <name>Chrome</name>
        <version>2.1</version>
    </app>

    <app>
        <id>3</id>
        <name>Google Play</name>
        <version>2.3</version>
    </app>
</apps>

Pull解析方式

Request request = new Request.Builder()
        .url("http://192.168.1.101/get_data.xml")
        .build();

这里将HTTP请求的地址改成了http://192.168.1.101/get_data.xml192.168.1.101是电脑本机的IP地址。

如果是模拟器的话,http://10.0.2.2/get_data.xml10.0.2.2对于模拟器来说就是电脑本机的IP地址。

private void parseXMLWithPull(String xmlData) {
        try {
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(new StringReader(xmlData));
            int eventType = xmlPullParser.getEventType();
            String id = "";
            String name = "";
            String version = "";

            // 获取pull解析器对应事件类型
            while (eventType != XmlPullParser.END_DOCUMENT) {
                String nodeName = xmlPullParser.getName();
                switch (eventType) {
                    //开始解析某个节点
                    case XmlPullParser.START_TAG: {

                        if ("id".equals(nodeName)) {
                            id = xmlPullParser.nextText();
                        } else if ("name".equals(nodeName)) {
                            name = xmlPullParser.nextText();
                        } else if ("version".equals(nodeName)) {
                            version = xmlPullParser.nextText();
                        }
                        break;
                    }
                    case XmlPullParser.END_TAG: {
                        if ("app".equals(nodeName)) {
                            Log.d(TAG, "id is : "+id);
                            Log.d(TAG, "name is : "+name);
                            Log.d(TAG, "version is : "+version);
                        }
                        break;
                    }
                    default:
                        break;
                }
                eventType = xmlPullParser.next();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

看下parseXMLWithPull()方法,首先要获取到一个XmlPullParserFactory的实例,并借助这个实例得到XmlPullParser对象,然后调用XmlPullParsersetInput()方法将服务器返回的XML数据设置进去就可以开始解析了。

  • eventType: 事件类型
  • START_DOCUMENT: 表示读到文档的开始位置,
  • START_TAG:表示读到文档中的元素开始位置,如id
  • END_DOCUMENT:表示读到文档结束的位置
  • END_TAG: 表示读到文档中的元素结束位置

通过getEventType()可以得到当前的解析事件,然后在一个while循环中不断地进行解析,如果当前的解析事件不等于XmlPullParser.END_DOCUMENT,说明解析工作还没完成,调用next()方法后可以获取下一个解析事件。

while循环中,我们通过getName()方法得到当前节点的名字,如果发现节点名等于id,nameversion,就调用nextText()方法来获取节点内具体的内容。

附录:
使用XmlPullParser解析xml文件
通过XmlPullParser类解析xml

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,837评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,934评论 6 13
  • 曾经闭口不谈的黑历史会在多年后的无数个夜里一夜又一夜地袭击你的睡眠。 那时才明白,躲避不能让过去成为过去。让过去成...
    我是胖胖阅读 190评论 0 0
  • vhjhhuisnwbbjjsjbbdbjsjj
    仇志轩阅读 197评论 0 5