Android第一行代码 Day09笔记

9. 使用网络技术

9.1 WebView的用法

流程:

  1. 首先在布局文件中加入WebView标签
    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </WebView>
  1. 在主活动中获取并进行设置

    • webView.getSettings():设置浏览器的属性
    • webView.setWebViewClient(new WebViewClient()):当需要从一个网页跳转到另一个网页时,目标网页仍在当前WebView显示
    • webView.loadUrl():传入网址
    • 最后在Manifest文件中声明访问网络的权限: < uses-permission android:name=“android.permission.INTERNET”/>

代码示例:

        WebView webView = (WebView)findViewById(R.id.web_view);

        webView.getSettings().setJavaScriptEnabled(true);
        //当需要从一个网页跳转到另一个网页时,目标网页仍在当前WebView显示
        webView.setWebViewClient(new WebViewClient());
        webView.loadUrl("https://www.baidu.com");

9.2 使用HTTP协议访问网络

9.2.1 使用HttpURLConnection

HttpURLConnection的用法:

  1. 首先new出一个URL实例并传入目标网址
  2. 获取HttpURLConnection实例 使用(HttpURLConnection)url.openConnection()方法获取
  3. 通过connection实例进行一些设置
    connection.setRequestMethod(“GET”):设置请求方法,GET或POST
    connection.setConnectTimeout(8000):设置连接超时时间
    connection.setReadTimeout(8000):设置读取超时的时间
  4. 通过 connection.getInputStream()方法获取字节输入流,并对输入流进行读取
  5. 通过connection.disconnect()方法将连接关闭

代码示例:

    private void sendRequestWithHttpURLConnection() {
        //通常开启一个线程来发起网络请求

        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                BufferedReader reader = null; 

                //请求数据
                try {
                    URL url = new URL("https://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);
                    }

                    Log.d("MainActivity",response.toString());
                    //TODO: 将读取到的内容显示到界面上

                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    try {
                        if(reader!=null){
                            reader.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    if(connection!=null){
                        connection.disconnect();
                    }
                }

            }
        }).start();
    }

9.2.2 使用OkHttp

OkHttp的用法:

  1. 在Build.gradle文件中添加依赖: implementation ‘com.squareup.okhttp3:okhttp:3.4.1’
  2. 创建一个OkHttpClient的实例
  3. 创建一个Request对象: Request request = new Request.Builder()
                                                         .url(“网址”)
                                                         .build();
  4. 调用newCall()方法并传入刚才创建的Request对象,创建一个Call对象并调用execute()方法发送请求并获取服务器返回的数据,返回一个Response对象
  5. 调用response.body().string()方法获取返回的数据
  6. 如果是发POST请求,需要先创建一个RequestBody对象
    RequestBody body = new FormBody.Builder()
                         .add() 以键值对的形式存放数据
                         .build()
    在Request.Builder中再调用post()方法,并传入创建好的requestbody

代码示例:

  • 发送GET请求:
    private void sendRequestWithOkHttp(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    OkHttpClient client = new OkHttpClient();
                    Request request = new Request.Builder()
                            .url("https://www.baidu.com")
                            .build();
                    Response response = client.newCall(request).execute();
                    String resData = response.body().string();
                    //TODO: 将读取到的内容显示到界面上

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
  • 发送POST请求
    private void sendRequestWithOkHttp(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    OkHttpClient client = new OkHttpClient();
                    RequestBody requestBody = new FormBody.Builder()
                    		//添加请求参数
                            .add("username","admin")
                            .add("password","123456")
                            .build();
                    Request request = new Request.Builder()
                            .url("https://www.baidu.com")
                            .post(requestBody)
                            .build();
                    Response response = client.newCall(request).execute();
                    String resData = response.body().string();
                    //TODO: 将读取到的内容显示到界面上

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

9.3 解析XML格式数据

9.3.1 使用Pull解析方式

  1. 通过XmlPullParserFactory.newInstance()实例通过newPullParser()方法来获取 xmlPullParser对象
  2. 通过setInput()方法将服务器返回的XML数据设置进去,传入一个Reader对象
  3. 通过getEventType()方法得到当前的解析事件
  4. 利用while循环进行解析
    通过getName()得到当前节点的名字,
    根据switch(eventType):通过节点名对比,使用nextText()方法获取当前节点的具体内容
    case XmlPullParser.START_TAG: 开始解析某个节点
    case XmlPullParser.END_TAG:完成解析某个节点
    调用next()方法获取下一个解析事件即更新eventType

代码示例:

    //Pull解析xml
    private void parseXMLWithPull(String resData) {
        try {
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(new StringReader(resData)); //将xml数据传给xmlPullParser
			//得到当前的解析事件
            int eventType = xmlPullParser.getEventType();
            //定义好要解析的标签的名称
            String id = "";
            String name = "";
            String version = "";

            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("MainActivity","id is "+id);
                            Log.d("MainActivity","name is "+name);
                            Log.d("MainActivity","version is "+version);
                        }
                        break;
                    }
                    default:
                        break;
                }

                eventType = xmlPullParser.next();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

9.3.2 使用SAX解析方式

  1. 首先新建一个类继承自DefaultHandler,并重写父类的5个方法
    定义StringBuilder对象和nodeName对象

    1. startDocument():在开始XML解析的时候调用
      初始化StringBuilder对象
    2. startElement():在开始解析某个节点时调用
      记录当前节点名 nodeName = localName
    3. characters():获取节点内容时,多次调用
      根据当前的节点名判断获取对应节点具体内容
    4. endElement():在完成解析某个节点的时候调用
      在解析完一个节点后,通过setLength(0)方法将StringBuilder对象清空,以防影响下一个节点的解析
    5. endDocument():在完成整个XML解析的时候调用
  2. 通过SAXParserFactory.newInstance()获取factory的实例再通过factory.newSAXParser().getXMLReader()方法获取 XML
    将contentHandler的实例通过setContentHandler()方法设置到XMLReader中
    开始执行解析 parse(new InputSource(new StringReader(data)));

代码示例:

  • 新建类继承自DefaultHandler
public class ContentHandler extends DefaultHandler {

    private String nodeName;
    private StringBuilder id;
    private StringBuilder name;
    private StringBuilder version;

    // 在开始XML解析的时候调用
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        id = new StringBuilder();
        name = new StringBuilder();
        version = new StringBuilder();
    }

    //在开始解析某个节点时调用
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);

        //记录当前节点名
        nodeName = localName;
    }


    //在完成解析某个节点的时候调用
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);

        if("app".equals(localName)){
            Log.d("ContentHandler","id is "+id.toString().trim());
            Log.d("ContentHandler","name is "+name.toString().trim());
            Log.d("ContentHandler","version is "+version.toString().trim());

            //最后将StringBuilder清空掉
            id.setLength(0);
            name.setLength(0);
            version.setLength(0);
        }

    }

    //在完成整个XML解析的时候调用
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();


    }


    //获取节点内容时,多次调用
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        //根据当前的节点名判断将内容添加到哪一个StringBuilder对象中
        if("id".equals(nodeName)){
            id.append(ch,start,length);
        }else if("name".equals(nodeName)){
            name.append(ch,start,length);
        }else if("version".equals(nodeName)){
            version.append(ch,start,length);
        }
    }
}
  • 在主活动中使用
//SAX方式解析XML
    private void parseXMLWithSAX(String resData) {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            XMLReader xmlReader =  factory.newSAXParser().getXMLReader();

            ContentHandler handler = new ContentHandler();

            //将contentHandler的实例设置到XMLReader中
            xmlReader.setContentHandler(handler);
            //开始执行解析
            xmlReader.parse(new InputSource(new StringReader(resData)));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

9.4 解析JSON格式数据

9.4.1 使用JSONObject

  1. 如果服务器中JSON数据为一个JSON对象,那么将json字符串传入JSONObject的构造方法中
  2. 如果服务器中JSON数据为一个JSON数组,那么将数据传入到 JSONArray对象中
  3. 循环遍历 JSONArray,通过jsonArray.getJSONObject(i)取出的对象都是一个JSONObject对象
  4. 再通过getString()方法将其中的数据取出

代码示例:

    private void parseJSONWithJSONObject(String resData) {

        try {
        	//JSON对象
        	//JSONObject object = new JSONObject(resData);
			//JSON数组
            JSONArray jsonArray = new JSONArray(resData);
            for(int i=0;i<jsonArray.length();i++){
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String id = jsonObject.getString("id");
                String name = jsonObject.getString("name");
                String version = jsonObject.getString("version");

                Log.d("ParseJSONActivity","id is "+id);
                Log.d("ParseJSONActivity","name is "+name);
                Log.d("ParseJSONActivity","version is "+version);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

9.4.2 使用GSON

  1. 首先在build.gradle文件中添加依赖 implementation ‘com.google.code.gson:gson:2.7’
  2. 定义一个要解析的数据的实体类
  3. 如果要解析是一个JSON对象则使用
    Gson gson = new Gson();
    通过 gson.fromJson(data,实体类.class)获取解析后的对象
  4. 如果是要解析一个JSON数组则使用
    Gson gson = new Gson();
    List<实体类> list = gson.fromJson(data,new TypeToken<List<实体类>>(){}.getType());

代码示例:

  • 实体类
public class App {
    private String id;
    private String name;
    private String version;
}
  • 对JSON数组进行解析
    private void parseJSONWithGSON(String resData) {

        Gson gson = new Gson();
        List<App> appList = gson.fromJson(resData,new TypeToken<List<App>>(){}.getType());
        for(App app:appList){
            Log.d("ParseJSONActivity","id is "+app.getId());
            Log.d("ParseJSONActivity","name is "+app.getName());
            Log.d("ParseJSONActivity","version is "+app.getVersion());
        }
    }

9.5 网络编程的最佳实践

  • 创建一个用于回调的接口
public interface HttpCallbackListener {
    void onFinish(String response);// 表示当服务器响应成功时调用
    void onError(Exception e);// 表示当服务器出现错误时调用
}
  • 创建一个用于发起网络请求的Util类
public class HttpUtil {
	
	//使用HttpURLConnection发送
    public static void sendHttpRequest(final String address,final HttpCallbackListener listener){

        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                BufferedReader reader = null;
                try {
                    URL url = new URL(address);
                    connection = (HttpURLConnection)url.openConnection();

                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    connection.setDoInput(true);
                    connection.setDoOutput(true);

                    InputStream in = connection.getInputStream();
                    reader = new BufferedReader(new InputStreamReader(in));

                    StringBuilder response = new StringBuilder();
                    String line;
                    while((line = reader.readLine())!=null){
                        response.append(line);
                    }

                    if(listener!=null){
                        //回调onFinish()方法
                        listener.onFinish(response.toString());
                    }

                } catch (Exception e) {
                    if(listener!=null){

                        listener.onError(e);
                    }
                } finally {
                    try {
                        if(reader!=null){
                            reader.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    if(connection!=null){
                        connection.disconnect();
                    }
                }
            }
        }).start();

    }

	//使用OkHttp发送
    public static void sendOkHttpRequest(String address,okhttp3.Callback callback){
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(address)
                .build();

        client.newCall(request).enqueue(callback);
    }
}
  • 在主活动中进行使用
/**
 * 回调接口还是在子线程运行,所以不能进行UI操作
 */
public class HttpUtilTestActivity extends AppCompatActivity {

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



        //调用 sendHttpRequest()方法
        String address = "https://www.baidu.com";
        HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {
            @Override
            public void onFinish(String response) {
                //根据返回内容执行具体的逻辑
            }

            @Override
            public void onError(Exception e) {
                //对异常情况进行处理
            }
        });


        //调用 sendOkHttpRequest()方法
        HttpUtil.sendOkHttpRequest(address,new okhttp3.Callback(){

            @Override
            public void onFailure(Call call, IOException e) {
                //对异常情况进行处理
            }

            //得到服务器返回的具体内容
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String responseData = response.body().string();
                Log.d("HttpUtilTestActivity",responseData);
            }
        });
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值