Activity
1. 生命周期
正常情况下:
- 启动 Activity:系统先调用
onCreate()
,然后调用onstart()
,最后调用onResume()
,Activity 就此进入运行状态。 - 退出 Activity:系统先调用
onPause()
,然后调用onStop()
,最后调用onDestroy()
,Activity 就此销毁。 - 当前设备锁屏或者点击 Home 键使程序进入后台,依次执行
onPause()
、onStop()
, 重新回到 Activity,依次执行onRestart()
、onStart()
、onResume()
(Activity 不被回收的情况下)。 - 当前 Activity 被 Dialog 主题的 Activity 覆盖时,执行
onPause()
,回到前台执行onResume()
。 - 当 Activity 不在前台或者不可见时被系统回收后,再次回到此 Activity ,系统会依次执行
onCreate()
、onStart()
、onResume()
。 - 启动一个新 Activity,旧 Activity 会先执行
onPause()
,然后新 Activity 再启动。 - 按是否可见分类:
onStart()
、onStop()
。 - 按是否前台分类:
onResume()
、onPause
。
注意:当 Activity 弹出对话框时,并不会回调 onPause
。
异常情况下:
当系统内存不足,或者系统配置发生改变(如旋转方向),Activity 会被杀死。
- 由于是异常情况下终止的,系统会调用
onSaveInstanceState()
来保存当前 Activity 的状态,这个方法的调用时机是在onStop()
之前,当 Activity 重新创建后,系统会把销毁时保存的 Bundle 对象作为参数传递给onCreate()
和onRestoreInstanceState()
,建议在onRestoreInstanceState()
中做数据恢复,毕竟专门用来恢复实例状态的。另外,每个 View 本身都有onSaveInstanceState()
和onRestoreInstanceState()
方法,因此系统都会默认恢复 View 的基本状态。 - 防止重新创建 Activity:在 AndroidManifest.xml 中指定
android:configChanges="orientation"
,似乎有些设备需要多指定一个参数,即android:configChanges:="orientaion|screenSize"
。
2. 启动模式
总共 4 种启动模式:Standard,SingleTop,SingleTask,SingleInstance。
- Standard:默认的启动模式,在这种模式下,Activity 会进入启动它的 Activity 所在的任务栈。
- SingleTop:如果新 Activity 位于任务栈的栈顶时,Activity 不会被创建,并且它的
onNewIntent()
方法会被回调,其余生命周期方法均不会回调。 - SingleTask:如果 Activity 在一个任务栈中存在,那么多次启动此 Activity 都不会创建新实例,但系统会回调
onNewIntent()
。此外,位于此 Activity 之上的所有 Activity 均会出栈,此时 Activity 位于栈顶。 - SingleInstance:这种模式下的 Activity 只能单独存在于一个任务栈中,由于栈内复用特性,此后的请求均不会创建新的实例。
注意:默认情况下,所有 Activity 所需的任务栈的名字为应用的包名,可以在 AndroidManifest.xml 中通过android:taskAffinity=""
来指定任务栈。
Service
被启动的 Service 默认是在主线程下工作的,因此如果需要执行耗时操作,应当另开一个子线程来执行,以免阻塞主线程导致出现 ANR(Application Not Response)。任何 Activity 都可以控制同一个 Service,并且系统中也只会存在一个 Service 实例。
启动模式
1. startService()
- 普通模式:在这种模式下启动 Service 后,即使 Activity 销毁后,Service 也会在后台继续执行任务,直到在 Activity 中手动调用
stopService()
或者在在 Service 类中调用stopSelf()
,服务才会停止,Activity 无法与 Service 进行通信。 onCreate
中可以做一些初始化,onStartCommand()
中放置执行任务的代码,onDestroy()
中进行资源的释放。- 在这种方式下启动 Service,生命周期是
onCreate()
->onStartCommand()
->onDestroy()
,当 Service 已经被启动后,无论执行多少次startServvice()
,都不会走onCreate()
,而是会调用onStartCommand()
。
2. bindService()
- 绑定模式:在这种模式下启动 Service,当 Activity 销毁后,Service 也会跟着销毁,不再使用 Service 时,调用
unbindService()
停止。这种模式下可以进行 Activity 和 Service 的通信。 - 这这种方式下启动 Service,生命周期是
onCreate()
->onBind()
->onUnbind()
->onDestroy()
,onStartCommand()
不会有调用机会。
注意:当startService()
和bindService()
一起被调用后,若想停止服务,必须同时调用stopService()
和unbindService()
,这样服务才会停止,顺序没有严格要求,但一定要同时调用。
示例:
- 创建一个 Service
public class MyService extends Service {
private static final String TAG = "MyService";
private IBinder mBinder;
@Override
public IBinder onBind(Intent intent) {
if (mBinder == null) {
mBinder = new MyBinder();
}
Log.d(TAG, "-----onBind()-----");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "-----onUnbind()-----");
return super.onUnbind(intent);
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "-----onCreate()-----");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "-----onDestroy()-----");
}
public class MyBinder extends Binder {
// 这里可以定义想要通信的方法,在 Activity 中可以通过 Binder 实例调用
public void print(String data) {
Log.d(TAG, "print: " + data);
}
}
}
复制代码
- 在 AndroidManifest.xml 中注册
<!--android:enabled 表示是否启用,android:exported 表示是否向外界公开-->
<service
android:name=".MyService"
android:enabled="true"
android:exported="false" />
复制代码
- 在 Activity 中定义 ServiceConnectioin 并进行绑定
public class MainActivity extends AppCompatActivity {
private ServiceConnection mConnection;
private MyService.MyBinder mBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mConnection = new MyConnection();
initView();
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
private void initView() {
Button bindService = findViewById(R.id.btn3);
Button unbindService = findViewById(R.id.btn4);
bindService.setOnClickListener(view -> {
bindService(new Intent(MainActivity.this, MyService.class), mConnection, BIND_AUTO_CREATE);
});
unbindService.setOnClickListener(view -> {
unbindService(mConnection);
});
}
private class MyConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 转换为自己定义的 Binder
mBinder = (MyService.MyBinder) service;
// 调用自己定义的方法进行通信
mBinder.print("成功通信");
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 这个方法只有在出现异常的时候才会被系统调用
}
}
}
复制代码
前台服务
服务几乎都是在后台运行的,系统优先级相对比较低,当系统出现内存不足时就容易被回收,如果希望服务可以一直保持运行状态,不会因为内存不足而被回收,这时就可以使用前台服务。与普通服务不同,前台服务会有一个正在运行的图标在通知栏里显示,类似通知。例如腾讯手机管家等通知,会在通知栏显示此时手机的内存状态等。
示例:在 Service 中通过startForeground()
创建前台服务,然后在 Activity 中通过startService()
或bindService()
开启,通过stopService()
或unbindService()
关闭。
public class MyService extends Service {
private static final String TAG = "MyService";
private IBinder mBinder;
@Override
public void onCreate() {
super.onCreate();
createForegroundService();
}
private void createForegroundService() {
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
Notification notification;
// 使用了建造者模式,将需要定义到的部分提前设置好
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "Channel_1")
.setContentTitle("前台服务")
.setContentText("This is content text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentIntent(pi);
// 因为 Android 8.0 添加了 NotificationChannel(通知渠道)
// 因此需要适配,不然在 8.0 上会显示不了通知
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel("Channel_1", "前台服务", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
notification = builder.build();
} else {
notification = builder.build();
}
startForeground(1, notification);
}
......
}
复制代码
IntentService
在前面就知道了,普通服务默认是运行在主线程中的,如果在服务里执行一些耗时操作就容易出现 ANR,当然也可以自己另开线程来执行,然后在合适的时机在 Service 内部调用stopSelf()
来停止。但是这样稍显麻烦,为了可以简单地创建一个异步的、会自动停止的 Service,Android 提供了 IntentService 类,很好地解决了这个问题。
- 通过创建一个 Service 继承自 IntentService,并重写
onHandleIntent()
方法即可,在这个方法中便可以处理耗时操作,并且当执行完毕后,Service 会自动停止。
示例:
public class MyIntentService extends IntentService {
public MyIntentService() {
// 必须调用父类有参构造
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d("MyIntentService", "currentThread: " + Thread.currentThread().getName());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "-----onDestroy()-----");
}
}
复制代码
- 当执行完毕后,Service 自动停止,详情见 Logcat
远程服务
由于远程服务我并不熟悉,这里就先落下了,后面学习了再补充上去。