9.0 Android中的网络技术

Android中网络相关的技术,主要分别两种,一种为直接显示网页,另外一种为获取服务器中的数据进行设置。

权限声明

访问网络是需要声明权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.webviewtest">

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

    ...

</manifest>

WebView的使用

通过WebView的控件,直接显示网页,不需要考虑网页中的具体数据。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        webView.settings.javaScriptEnabled=true
        webView.webViewClient = WebViewClient()
        webView.loadUrl("https://www.baidu.com")
    }

}

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

HttpURLConnection的使用

get获取数据

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sendRequestBtn.setOnClickListener {
            sendRequestWithHttpURLConnection()
        }
    }

    private fun sendRequestWithHttpURLConnection() {
        // 开启线程发起网络请求
        thread {
            var connection: HttpURLConnection? = null
            try {
                val response = StringBuilder()
                val url = URL("https://www.baidu.com")
                connection = url.openConnection() as HttpURLConnection
                connection.connectTimeout = 8000
                connection.readTimeout = 8000
                val input = connection.inputStream
                // 下面对获取到的输入流进行读取
                val reader = BufferedReader(InputStreamReader(input))
                reader.use {
                    reader.forEachLine {
                        response.append(it)
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                connection?.disconnect()
            }
        }
    }
    }
}

post发送数据

connection.requestMethod = "POST"
val output = DataOutputStream(connection.outputStream)
output.writeBytes("username=admin&password=123456")

okHttp的使用

项目主页地址:
https://github.com/square/okhttp
添加依赖:

dependencies {
    ...
    implementation 'com.squareup.okhttp3:okhttp:4.1.0'
}

版本根据官网中的最新版本进行添加

okHttp的具体用法

获取Client的实例

val client = OkHttpClient()

创建get的request实例

创建request,需要知道是否需要设置token

val request = Request.Builder()
        .url("https://www.baidu.com")
        .build()

获取response

同步获取

val response = client.newCall(request).execute()
val responseData = response.body?.string()

异步获取:

   client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                //响应失败
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
            //响应成功
            val responseData = response.body?.string()

            }
        });

发起Post的请求

val requestBody = FormBody.Builder()
        .add("username", "admin")
        .add("password", "123456")
        .build()
 val request = Request.Builder()
        .url("https://www.baidu.com")
        .post(requestBody)
        .build()

从Android 9.0系统开始,应用程序默认只允许使用HTTPS类型的网络请求,HTTP类型的网络请求因为有安全隐患默认不再被支持,如果使用的是HTTP,需要设置文件,res -> xml ->network_config.xml文件。

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

这段配置文件是允许我们以明文的方式在网络上传输数据,而HTTP使用的就是明文传输方式。
需要修改manifest文件中的内容,如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.networktest">
    ...
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:networkSecurityConfig="@xml/network_config">
        ...
    </application>
</manifest>

解析XML数据的两种方法:

①pull方法

方法parseXMLWithPull中的,即为使用Pull方法解析XML格式的数据

class MainActivity : AppCompatActivity() {
    ...
    private fun sendRequestWithOkHttp() {
        thread {
            try {
                val client = OkHttpClient()
                val request = Request.Builder()
                    // 指定访问的服务器地址是计算机本机
                    .url("http://10.0.2.2/get_data.xml")
                    .build()
                val response = client.newCall(request).execute()
                val responseData = response.body?.string()
                if (responseData != null) {
                    parseXMLWithPull(responseData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
    ...
    private fun parseXMLWithPull(xmlData: String) {
        try {
            val factory = XmlPullParserFactory.newInstance()
            val xmlPullParser = factory.newPullParser()
            xmlPullParser.setInput(StringReader(xmlData))
            var eventType = xmlPullParser.eventType
            var id = ""
            var name = ""
            var version = ""
            while (eventType != XmlPullParser.END_DOCUMENT) {
                val nodeName = xmlPullParser.name
                when (eventType) {
                    // 开始解析某个节点
                    XmlPullParser.START_TAG -> {
                        when (nodeName) {
                            "id" -> id = xmlPullParser.nextText()
                            "name" -> name = xmlPullParser.nextText()
                            "version" -> version = xmlPullParser.nextText()
                        }
                    }
                    // 完成解析某个节点
                    XmlPullParser.END_TAG -> {
                        if ("app" == nodeName) {
                            Log.d("MainActivity", "id is $id")
                            Log.d("MainActivity", "name is $name")
                            Log.d("MainActivity", "version is $version")
                        }
                    }
                }
                eventType = xmlPullParser.next()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

②SAX方法

class MainActivity : AppCompatActivity() {
    ...
    private fun sendRequestWithOkHttp() {
        thread {
            try {
                val client = OkHttpClient()
                val request = Request.Builder()
                    // 指定访问的服务器地址是计算机本机
                    .url("http://10.0.2.2/get_data.xml")
                    .build()
                val response = client.newCall(request).execute()
                val responseData = response.body?.string()
                if (responseData != null) {
                    parseXMLWithSAX(responseData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
    ...
    private fun parseXMLWithSAX(xmlData: String) {
        try {
            val factory = SAXParserFactory.newInstance()
            val xmlReader = factory.newSAXParser().XMLReader
            val handler = ContentHandler()
            // 将ContentHandler的实例设置到XMLReader中
            xmlReader.contentHandler = handler
            // 开始执行解析
            xmlReader.parse(InputSource(StringReader(xmlData)))
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

ContentHandler的定义:

class ContentHandler : DefaultHandler() {

    private var nodeName = ""

    private lateinit var id: StringBuilder

    private lateinit var name: StringBuilder

    private lateinit var version: StringBuilder

    override fun startDocument() {
        id = StringBuilder()
        name = StringBuilder()
        version = StringBuilder()
    }

    override fun startElement(uri: String, localName: String, qName: String, attributes:
        Attributes) {
        // 记录当前节点名
        nodeName = localName
        Log.d("ContentHandler", "uri is $uri")
        Log.d("ContentHandler", "localName is $localName")
        Log.d("ContentHandler", "qName is $qName")
        Log.d("ContentHandler", "attributes is $attributes")
    }

    override fun characters(ch: CharArray, start: Int, length: Int) {
        // 根据当前节点名判断将内容添加到哪一个StringBuilder对象中
        when (nodeName) {
            "id" -> id.append(ch, start, length)
            "name" -> name.append(ch, start, length)
            "version" -> version.append(ch, start, length)
        }
    }

    override fun endElement(uri: String, localName: String, qName: String) {
        if ("app" == 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)
        }
    }

    override fun endDocument() {
    }

}

id、name和version中都可能是包括回车或换行符的,需要调用trim。

解析JSON数据

官方提供的JSONObject,使用Google的开源库GSON。或者使用一些第三方的开源库如Jackson、FastJSON等。

①官方的JSONObject

......
    private fun parseJSONWithJSONObject(jsonData: String) {
        try {
            val jsonArray = JSONArray(jsonData)
            for (i in 0 until jsonArray.length()) {
                val jsonObject = jsonArray.getJSONObject(i)
                val id = jsonObject.getString("id")
                val name = jsonObject.getString("name")
                val version = jsonObject.getString("version")
                Log.d("MainActivity", "id is $id")
                Log.d("MainActivity", "name is $name")
                Log.d("MainActivity", "version is $version")
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

②使用GSON解析

添加依赖

dependencies {
    ...
    implementation 'com.google.code.gson:gson:2.8.5'
}

解析一段字符串
{“name”:“Tom”,“age”:20}
设置Person的类,直接进行转换

val gson = Gson()
val person = gson.fromJson(jsonData, Person::class.java)

解析字符串数组
需要借助TypeToken将期望解析成的数据类型传入fromJson()方法中

val typeOf = object : TypeToken<List<Person>>() {}.type
val people = gson.fromJson<List<Person>>(jsonData, typeOf)

jsonData为需要解析的字符串数组

网络请求回调方法:

interface HttpCallbackListener {
    fun onFinish(response: String)
    fun onError(e: Exception)
}
object HttpUtil {

    fun sendHttpRequest(address: String, listener: HttpCallbackListener) {
        thread {
            var connection: HttpURLConnection? = null
            try {
                val response = StringBuilder()
                val url = URL(address)
                connection = url.openConnection() as HttpURLConnection
                connection.connectTimeout = 8000
                connection.readTimeout = 8000
                val input = connection.inputStream
                val reader = BufferedReader(InputStreamReader(input))
                reader.use {
                    reader.forEachLine {
                        response.append(it)
                    }
                }
                // 回调onFinish()方法
                listener.onFinish(response.toString())
            } catch (e: Exception) {
                e.printStackTrace()
                // 回调onError()方法
                listener.onError(e)
            } finally {
                connection?.disconnect()
            }
        }
    }

}

使用json

object HttpUtil {
    ...
    fun sendOkHttpRequest(address: String, callback: okhttp3.Callback) {
        val client = OkHttpClient()
        val request = Request.Builder()
            .url(address)
            .build()
        client.newCall(request).enqueue(callback)
    }
}

使用

HttpUtil.sendOkHttpRequest(address, object : Callback {
    override fun onResponse(call: Call, response: Response) {
        // 得到服务器返回的具体内容
        val responseData = response.body?.string()
    }

    override fun onFailure(call: Call, e: IOException) {
        // 在这里对异常情况进行处理
    }
})

相关推荐

  1. 9.0 Android网络技术

    2024-06-09 19:18:06       9 阅读
  2. Android开发常见Hook技术有哪些?

    2024-06-09 19:18:06       38 阅读
  3. 全球化航程网络技术与安全策略

    2024-06-09 19:18:06       20 阅读
  4. 浅析人工智能技术网络安全领域应用

    2024-06-09 19:18:06       11 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-09 19:18:06       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-09 19:18:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-09 19:18:06       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-09 19:18:06       20 阅读

热门阅读

  1. 一个python 程序执行顺序

    2024-06-09 19:18:06       10 阅读
  2. LeetCode 1193, 45, 48

    2024-06-09 19:18:06       9 阅读
  3. IO数据流

    2024-06-09 19:18:06       9 阅读
  4. antd DatePicker 日期 与 时间 分开选择

    2024-06-09 19:18:06       10 阅读
  5. dockerfile,shell脚本,yaml文件如何配合

    2024-06-09 19:18:06       6 阅读
  6. C++数据结构——队列queue

    2024-06-09 19:18:06       9 阅读
  7. 网络安全法对个人保护的要求

    2024-06-09 19:18:06       10 阅读
  8. 【面试宝藏】Redis 常见面试题解析

    2024-06-09 19:18:06       10 阅读