安卓也是具有网络编程这一板块的,我们先从线程通讯说起,因为安卓自4.0之后就有一个特性,就是主线程不可以发送网络请求,而子线程不可以更新界面,所以我们想要学会网络编程,必须先掌握线程之间的通讯;
这个是主线程和子线程通讯的媒介,之前我们在制作轮播图的时候用到过这个,可以用它来定时,定时的发送一条信息给主线程,然后主线程根据信息的类型来更新界面:
/*hanlder= MyHanlder(WeakReference(this))*/
//1.3 非静态内部类:使用WeakReference防止内存泄漏
private class MyHanlder(var wk:WeakReference<MainActivity>):Handler(Looper.getMainLooper()){
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
var activity = wk.get()
if(activity!=null){
if(msg.what==0){
activity.count++
activity.tv_count.setText(activity.count.toString())
}else if(msg.what==1){
activity.isback=false
}
}
}
}
在kotlin中,我们可以这样创建一个自己的handler的内部类,因为直接使用handler虽然方便,但是有一个问题就是会导致内存泄漏,handler会默认隐式引用activity,在我们关闭了项目之后并不会被销毁,所以我们就是用了弱引用(WeakReference),只要是通过这个对象引用过得对象,在销毁了引用对象之后,也就是这里的mainactivity,就会被回收,所以不会导致内存泄露;注意这里的写法,我们通过get()可以拿到隐式引用的activity对象,就可以对里面的属性进行更新;但是要判断一下是否为null值
一般我们创建一个子线程可以这样:
Thread(){
while(flag){
Thread.sleep(1000)
message.what=0
myHanlder.sendEmptyMessage(0)
}
}.start()
当然也可以使用实现Runnable接口的方法;
安卓提供了两种发送请求的方式:一个是HttpURLConnection对象,一个是HttpClient(但是这种已经被淘汰了),我们就学习一下HttpURLConnection是如何发送请求的,之前我们说过,我们发送请求只能在子线程,所以我们要创建一个子线程,但是我们需要修改一些配置,因为默认andorid studio 是不允许发送请求的,我们需要在清单文件中添加上这两句:2
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hanlderpractice">
//允许发送网络请求
<uses-permission android:name="android.permission.INTERNET"/>
application>
manifest>
加上去之后我们再写我们的代码
1、创建URL:
var httpurl: String = "http://10.0.2.2:5000/api/user/" + parame1
var url: URL = URL(httpurl)
var conn: HttpURLConnection = url.openConnection() as HttpURLConnection
我们创建一个字符串,这是我们的网址,然后使用URL封装成一个请求对象,调用他的函数openConnection并且将返回值强转为一个
HttpURLConnection对象,然后我们就可以将请求过来的数据存储下来:
conn.requestMethod = "GET"
conn.connectTimeout = 5000
conn.readTimeout = 5000
var code: Int = conn.responseCode
if (code == 200) {
var inputStream: InputStream = conn.inputStream
var byteArray: ByteArray = ByteArray(1024)
var length: Int
var result: String = ""
inputStream.use {
length = it.read(byteArray)
result = String(byteArray)
Log.d(TAG, "$result: ")
}
inputStream.close()
}
然后设置一下访问超时时间和阅读超时时间,返回码,我们使用这个返回的请求码判断是否为200,这是请求成功的代码,然后创建一个输入流对象,我们就使用这个输入流将请求下来的数据存储到二进制数组中,然后通过日志打印出来就可以了;最后不要忘了关闭这个流;
2、创建子线程,然后在单击事件里面启动
class HttpPractice : AppCompatActivity() {
lateinit var thread: Thread
lateinit var parame1: String
companion object {
private const val TAG = "HttpPractice"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_http_practice)
//1.1 创建子线程用来发送请求
parame1 = "[email protected]"
thread = Thread {
var httpurl: String = "http://10.0.2.2:5000/api/user/" + parame1
var url: URL = URL(httpurl)
var conn: HttpURLConnection = url.openConnection() as HttpURLConnection
conn.requestMethod = "GET"
conn.connectTimeout = 5000
conn.readTimeout = 5000
var code: Int = conn.responseCode
if (code == 200) {
var inputStream: InputStream = conn.inputStream
var byteArray: ByteArray = ByteArray(1024)
var length: Int
var result: String = ""
inputStream.use {
length = it.read(byteArray)
result = String(byteArray)
Log.d(TAG, "$result: ")
}
inputStream.close()
}
}
}
fun sendget(view: View) {
//2.1 发送请求,启动线程
thread.start()
}
}
如果是要带参数的get也很容易,我们这里也是使用了,就是在后面拼接上一个变量,填上我们想要的传递的参数就是了;
对了大家发送请求的时候window是访问本机的127.0.0.1得80端口,但是在安卓中不一样,我们访问的是10.0.2.2的5000端口,而且我们还得在本机启动一个服务器才行,大家如果没有本地服务器的话可以去我的公众号:代码栈回复安卓本地服务器拿取我们这个使用的服务器;
拿到文件,里面有一个叫做webapi的东西,还有一个PDF的文档,就是这个本地服务器的所有接口以及会返回的数据,我们参考这个文档就可以访问各种接口;
这里直接点击webapi.exe就可以启动了;