11月10日Android学习笔记
读取网络数据
获取网络请求属于耗时操作。在Android主线程当中不允许出现耗时操作,开启异步线程,解决获取网络请求的问题。
获取网络请求必须在子线程当中完成,UI控件的设置必须在主线程当中完成。
线程知识点回顾
开启新线程
- 创建Thread子类对象,调用start方法,启动新线程
- 编写Runnable实现类,创建Runnable子类的对象,
new Thread(new MyRunnable).start()
创建新线程对象
1 | //创建新的线程对象 |
线程的生命周期
线程的生命周期: 新建—–>>就绪—–>>运行<==>阻塞——>>消亡
当调用t1.start()
方法时,让线程处于就绪状态,有cpu的执行资格,但是没有执行权力。
原生读取网络数据
配置网络访问权限
AndroidManifest.xml
1 |
|
读取流
1 | private String getStringByConnection(String path) { |
线程中开启读取方法
1 | private void loadDatas() { |
UI的更新(线程间通信)
只有UI线程才能更新控件内容,在子线程当中更新UI会出现bug
但是从子线程获取网络数据,然后通过线程间通信,可以将数据传递给主线程,然后在主线程更新UI控件
步骤
创建一个线程间通信类,该类可以在子线程当中发送消息,然后在主线程中接收消息。
发送消息和接收消息得是同一个handler对象1
2
3
4
5
6
7Handler handler = new Handler(new Handler.Callback() {
public boolean handleMessage( { Message msg)
//可以接收消息的方法
return false;
}
});在子线程发送消息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void run() {
//表示让当前线程可以作为loop线程,此时该子线程可以创建Handler对象,发送消息
Looper.myLooper();
Looper.loop();
//编写获取网络数据的过程
String msg = HttpUtils.getStringByConnection(url);
//将要发送的数据封装到message当中
Message message = handler.obtainMessage();
//区别消息的标识号
message.what = 1;
message.obj = msg;
handler.sendMessage(message);
Log.i("lsh", "run: msg====" + msg);
}在主线程接收消息
1
2
3
4
5
6
7
8
9
public boolean handleMessage( { Message message)
//可以接收消息的方法
if (message.what == 1) {
String str = (String) message.obj;
binding.mainTv.setText(str);
}
return false;
}回到主线程执行任务
在子线程的run方法中执行runOnIoThread()
即可1
2
3
4
5
6
7//回到主线程执行任务
runOnUiThread(new Runnable() {
public void run() {
adapter.notifyDataSetChanged();
}
});1
2
3
4
5
6
7
8
9
10
11
12
13Handler handler2 = new Handler();
new Thread(){
public void run() {
String json = "ksdfjalkjf";
handler2.post(new Runnable() {
public void run() {
//回到主线程执行
}
});
}
}.start();
Handler,Looper,Message,MessageQueue之间的关系
答:从应用的角度举例,可以把地铁当中的安检机看作是一个线程,然后安检机中的传送带就就当中Looper对象,因为有这个传送带,安检机才能无限循环进行安检,接受安检的人就相当于handler对象,在传送带上放置包裹即 Message,然后在传送带到达指定地点后,提示给放置包裹的人接受包裹。
从源码的角度讲,线程当中可以通过Looper.prepare()
方法,在线程当中定义looper
对象,使线程能够循环。然后通过调用Looper.loop()
的方法使他循环起来。然后Looper上有一个封装的MessageQueue
对象,用来处理循环消息,调用handler的sendMessage
方法,把message消息的target属性设置为当前handler,然后在调用messagequeue
当中enqueueMessage
方法把消息放置在消息队列上,然后调用handler
的dispatchMessage
分发这条消息,放置这条消息的handler能够获取到此消息, 通过handleMessage方法。
视图绑定
不用写findViewById
流程
build.gradle
中添加viewBinding
1
2
3
4
5
6
7
8android {
namespace 'com.xyl.app1110'
compileSdk 32
viewBinding {
enabled true
}
...
}每一个view上设置id
在Activity类中声明
ActivityMainBinding
对象,如1
ActivityMainBinding binding;
在
onCreate()
方法中获取绑定对象binding = ActivityMainBinding.inflate(getLayoutInflater());
或binding = ItemFoodlvBingding.bind(view)
—在adapter的用于getView()
的ViewHolder
中使用1
2
3
4
5
6
7protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View rootView = binding.getRoot();
setContentView(rootView);
binding.mainTv.setText("今天是个好天气");
}
三级缓存
三级缓存:
从网络上获取图片或者复杂的数据,可以先从内存当中查找,是否有这个图片,有就显示,没有就查找本地存储文件,如果本地存储有这个图片,就读入内存,然后显示,如果没有这个图片,就上网下载这个图片,下载成功,存放到本地存储,存放到内存,显示图片。
如果下载失败,显示错误图片。