这是我参与「第四届青训营 」笔记创作活动的第1天
安卓开发基础知识要掌握俩大板块:基础组件、通信组件。
- 基础组件:界面组件、服务组件、广播组件和数据组件。
- 通信组件:Handler、Binder
1.界面组件
1.1 Activity
Activity:界面容器。
1.1.1 生命周期
- 当一个Activity启动的时候:会调用onCreate->onStart->onResume。
- 当一个Activity销毁的时候:会调用onPause->onStop->onDestroy(有时候调用不到,如系统杀死)。
- 其中onStart和onStop是和界面是否可见相关的。
- 以及onResume和onPause是和界面是否操作相关的。
测试题 1:Activity A跳转Activity B的时候会发生什么事情?
A:onCreate->onStart->onResume->onPause
B:onCreate->onStart->onResume
A:onStop
测试题 2:Activity B销毁掉跳转回A的时候会发生什么事情?
B:onPause
A:onRestart->onStart->onResume
B:onStop->onDestroy
为什么要再Paused后去创建另外一个Activity呢,是因为这样可以提高另外一个组件的加载时间,再创建加载后才销毁自己才是最好的方案。所以我们再该组件Stop中去操作自己的事情是最好的,这样不影响创建另一个组件的效率。
异常声明周期的情况:
在发生异常情况的时候,需要通过以下回调函数进行数据的保存恢复处理。
onSaveInstanceState(Bundle outState)
:在Buddle中存储相关信息,该函数在onResume前调用。
onRestoreInstanceState(Bundle savedInstanceState)
:从Buddle中提取相关信息,该函数在onStart后调用。
们知道在重写onSaveInstanceState
和onRestoreInstanceState
的时候,默认代码是这样的:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//ousState.setXXX(k,v);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//savedInstanceState.getXXX(k,v);
}
当然也可以在AndroidManifest.xml
通过配置对应Activity中的configChange
属性使得在当前Activity运行时候发生以下情况不用销毁重建Activity。
configChange
:local
(语言改变)、fontScale
(字体大小改变)、orientation
(方向改变)、keyboardHidden
(键盘隐藏)。
配置改变的回调函数:onConfigurationChanged()
1.1.2 基本方法
注册->布局->绑定
Intent的调用:显式调用和隐式调用。
- 显示调用:
Intent(当前.this,跳转.class);
- 隐式调用中所查找的Activity,默认都自带一个Category:
<category android:name="android.intent.category.DEFAULT"/>
,所以如果不指定Category的话,需要在AndroidManifest.xml
中检查该Category是否已经添加在Intent-filter
中。
1.1.3 启动模式
android:lanuchMode
-
Standard:正常模式,允许Activity重复
-
SingleTop:栈顶复用,不允许栈顶有连续重复的Activity
-
SingleTask:栈内复用,不允许栈内有连续重复的Activity
-
SingleInstance:全局复用,不允许系统全局内有连续重复的Activity
1.2 Fragment
Fragment:页面容器,解决碎片化。
1.2.1 生命周期
1.2.2 基本用法
step 1.创建布局文件。
step 2.创建Fragment子类并绑定布局文件。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank2, container, false);
}
step 3.加载:静态加载和动态加载。
- 静态加载:直接在所需要的Activity布局文件里面声明片段就可以了。在
android:name
中输入Fragment所在子类路径。切记,一定要写android:id
。
通过这种方式,Activity可以直接通过findViewById()
调用到Fragment。Fragment也可以通过getActivity()
获得所绑定容器的Activity,也可以继续套娃,获得所绑定容器的其他Fragment。
<fragment
android:name="com.example.fragmentbase.BlankFragment"
android:id="@+id/BlankFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
- 动态加载:类似于JDBC的事务管理。
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.framelayout1,fragment); //我这里是有个业务,通过FrameLayout切换Fragment
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
1.2.3 与Activity交互
- 组件获取:
1.Fragment获取Activity中的组件:getActivity().findViewId(R.id.xxx)
2.Activity获取Fragment中的组件:getFragmentManager().findFragmentByid(R.id.Fagment_xxx)
- 数据传递:
1.Activity数据传给Fragment:
//Activity中创建Fragment前存入Bundle中
Bundle bundle=new Bundle();
bundle.putString("messqge","xinxi");
BlankFragment bf=new BlankFragment();
bf.setArguments(bundle);
//在onCreateView()中获取Bundle,解析数据
Bundle arguments = getArguments();
String msg= arguments.getString("messqge");
2.Fragment数据传给Activity:
a.通过对象直接传递
b.通过viewmodle/eventbus/handler/broadcast等通信
2 服务组件
Service :Android实现程序后台运行的解决方案。
- startService:启动不关心
- bindService:启动需交互
2.1 生命周期
onCreate()
:Service第一次创建的时候调用。onStartCommand()
:Service每一次创建的时候调用。onDestroy()
:Service销毁的时候调用。
2.2 基本用法
2.2.1:注册Service
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
2.2.2:创建Service子类
class MyService : Service() {
val TAG="MyService";
override fun onCreate() {
super.onCreate()
Log.d(TAG, "onCreate: ")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
Log.d(TAG, "StartCommand: ")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "Destroyed: ")
}
override fun onBind(intent: Intent?): IBinder? {
TODO("Not yet implemented")
}
}
2.2.3:通过Intent启动Service
val intent=Intent(this,MyService::class.java);
startService(intent);//启动
//stopService(intent);//停止
2.3 与Activity的交互通信
为什么需要通信?让Service可控。而不是启动了Service之后就和Activity没有关系了。那这时候就需要使用onBind()方法了。
class MyService : Service() {
//1.定义Binder子类,并实现getService()方法,返回Service对象
class TestBinder:Binder(){
private val res:Int=0;
fun testMsg(){
Log.d("TestBinder", "testMsg: ")
}
fun getRes():Int{
return res;
}
}
//2.实现Service类onBind()方法,返回上述Binder对象
override fun onBind(intent: Intent?): IBinder? {
Log.d("MyService", "onBind: ")
return TestBinder();
}
}
//3.实例化ServiceConnection对象,实现onServiceConnected方法,从中获取到Service实例
var testBinder : MyService.TestBinder?=null;
val conn=object:ServiceConnection{
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
testBinder=service as MyService.TestBinder;
testBinder?.testMsg();
//println(testBinder?.getRes());
Log.d("MyService", "onServiceConnected: "+testBinder?.getRes())
}
override fun onServiceDisconnected(name: ComponentName?) {
//只有发生异常断开的时候才会执行这个回调,如果Service是正常Destroy不会执行该回调
}
}
//4.Activity中调用bindService方法,并传递步骤3的ServiceConnection对象,将流程跑起来
val intent=Intent(this,MyService::class.java);
bindService(intent,conn, BIND_AUTO_CREATE);//绑定
//unbindService(conn)//解绑
3 广播组件
Broadcast
3.1 基本用法
3.1.2 动态注册
val intentFilter=IntentFilter()
intentFilter.addAction("xxx")
//myReceiver是实现了BroadcastReceiver类并重写onReceive()的对象
context.registerReceiver(myReceiver,intentFilter)
3.1.3 静态注册
可以在程序未启动的时候也能接受广播。
//1.注册,在AndroidManifest.xml中使用<receiver.../><intent-filter.../>
<receiver
android:name=".MyTimeReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.testmeaage.MY_BROADCAST"></action>
</intent-filter>
</receiver>
//2.创建,建立相应的BroadcastReceiver实现类
class MyTimeReceiver : BroadcastReceiver() {
//3.接收,在步骤2类中的onReceive中接收广播
override fun onReceive(context: Context, intent: Intent) {
// This method is called when the BroadcastReceiver is receiving an Intent broadcast.
Log.d("TimeReciver", "onReceive: ")
Toast.makeText(context,"Time changed",Toast.LENGTH_LONG).show();
}
}
val intent=Intent("com.example.testmeaage.MY_BROADCAST");
intent.setPackage(packageName)
//发送广播
sendBroadcast(intent);
需要注意的静态注册的BroadcastReceiver是无法接收隐式广播的,默认情况下我们发出的自定义广播恰恰都是隐式广播。因此一定要调用setPackage(packageName)
,指定这条广播是发送给哪个应用程序,从而让它变成一条显示广播。
3.2 常用系统广播
//充电状态,或者电池的电量发生变化。电池的充电状态、电荷级别改变,不能通过组建声明接收这个广播,只有通过Context.registerReceiver()注册
Intent.ACTION_BATTERY_CHANGED;
//设备当前设置被改变时发出的广播(包括的改变:界面语言,设备方向,等,请参考Configuration.java)
Intent.ACTION_CONFIGURATION_CHANGED;
//在系统启动完成后,这个动作被广播一次(只有一次)。
Intent.ACTION_BOOT_COMPLETED;
//成功的安装APK之后//广播:设备上新安装了一个应用程序包。//一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_ADDED;
//一个已存在的应用程序包已经改变,包括包名
Intent.ACTION_PACKAGE_CHANGED;
//触发一个下载并且完成安装时发出的广播,比如在电子市场里下载应用
Intent.ACTION_PACKAGE_INSTALL;
//成功的删除某个APK之后发出的广播, 一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_REMOVED;
//替换一个现有的安装包时发出的广播(不管现在安装的APP比之前的新还是旧,都会发出此广播)
Intent.ACTION_PACKAGE_REPLACED;
//用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_RESTARTED;
//屏幕被关闭之后的广播
Intent.ACTION_SCREEN_OFF;
//屏幕被打开之后的广播
Intent.ACTION_SCREEN_ON;
4 数据组件
4.1 ContentProvider
4.2 Intent
context.startActivity(Intent)
context.startService(Intent)
context.sendBroadCast(Intent)
4.2.1 基本用法:Activity中有具体使用方法,显式+隐式。
隐式需要注意的是:每个隐式Intent,都有一个默认的Category。
4.2.2 系统能力:
电话、短信、网页、邮件、地图、拍照、设置、市场
使用:StartActivity(Intent);
5 通信组件
5.1 Handler
class MainActivity : AppCompatActivity() {
val alterText=1;
//1.创建:新建handler,实现handleMessage()
val handler=object: Handler(Looper.getMainLooper()){
//4.处理:在handler的handleMessage中处理更新UI
override fun handleMessage(msg: Message) {
when(msg.what){
alterText->text1.text="Hello"
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_1.setOnClickListener({
//2.构造Message,设置what
val msg=Message();
msg.what=alterText;
//3.发送:子线程调用sendMessage(Message)发送Message
handler.sendMessage(msg);
})
}
}
搭配着原理图看看就懂了
Note:一个线程只能有一个Looper对象