进程的优先级
每一个App被运行都会产生一个进程,而进程的存在是消耗资源的,如果不对进程进行操作随着进程越来越多,系统的资源总会被消耗干净。Android系统通过一定的策略,选择性杀死部分进程。这个策略就是对进程标记优先级,当需要杀死进程时,首先杀死优先级低的进程。
进程的优先级如下
前台进程(Foreground process)。它表明用户正在与该进程进行交互操作,android系统依据下面的条件来将一个进程标记为前台进程:
- 该进程持有一个用户正在与其交互的Activity(也就是这个activity的生命周期方法走到了onResume()方法)。
- 该进程持有一个Service,并且这个Service与一个用户正在交互中的Activity进行绑定。
- 该进程持有一个前台运行模式的Service(也就是这个Service调用了startForegroud()方法)。
- 该进程持有一个正在执行生命周期方法(onCreate()、onStart()、onDestroy()等)的Service。
- 该进程持有一个正在执行onReceive()方法的BroadcastReceiver。
一般情况下,不会有太多的前台进程。杀死前台进程是操作系统最后无可奈何的做法。当内存严重不足的时候,前台进程一样会被杀死。
可见进程(Visible process)。它表明虽然该进程没有持有任何前台组件,但是它还是能够影响到用户看得到的界面。android系统依据下面的条件将一个进程标记为可见进程:
- 该进程持有一个非前台Activity,但这个Activity依然能被用户看到(也就是这个Activity调用了onPause()方法)。例如,当一个activity启动了一个对话框,这个activity就被对话框挡在后面。
- 该进程持有一个与可见(或者前台)Activity绑定的Service。
服务进程(Service process)。除了符合前台进程和可见进程条件的Service,其它的Service都会被归类为服务进程。
后台进程(Background process)。持有不可见Activity(调用了onStop()方法)的进程即为后台进程。通常情况下都会有很多后台进程,当内存不足的时候,在所有的后台进程里面,会按照LRU(最近使用)规则,优先回收最长时间没有使用过的进程。
空进程(Empty process)。不持有任何活动组件的进程。保持这种进程只有一个目的,就是为了缓存,以便下一次启动该进程中的组件时能够更快响应。当资源紧张的时候,系统会平衡进程缓存和底层的内核缓存情况进行回收。
相对应的,如果我们不想一个进程被杀死,那么可以采用一些手段来提升进程优先级。
由上面的总结可以知道,当一个进程持有一个Service,并且这个Service与用户正在交互的Activity进行绑定或者拥有一个正在执行生命周期方法的Service时进程的优先级是最高的,那么下面来介绍Service。
Service
1.Service的作用
我们为什么要引入Service?在众多的app中,有些app是需要长期在后台运行处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。例如一个音乐播放器,大多数时候是在后台运行播放音乐的。这个时候用到Service我们可以让他在后台执行某些任务,甚至当程序退出的时候我们也可以用Service来完成一些操作。
2.Service的特点
Service是无用户界面的
Service在后台运行
Service生命周期长
3.Service的类别
4.Service的两种启动方式
startService
通过startService启动后,service会一直无限期运行下去,只有外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁。
要创建一个这样的Service,你需要让该类继承Service类,然后重写以下方法:
onCreate()
1.如果service没被创建过,调用startService()后会执行onCreate()回调;
2.如果service已处于运行中,调用startService()不会执行onCreate()方法。
也就是说,onCreate()只会在第一次创建service时候调用,多次执行startService()不会重复调用onCreate(),此方法适合完成一些初始化工作。onStartCommand()
如果多次执行了Context的startService()方法,那么Service的onStartCommand()方法也会相应的多次调用。onStartCommand()方法很重要,我们在该方法中根据传入的Intent参数进行实际的操作,比如会在此处创建一个线程用于下载数据或播放音乐等。onBind()
Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。onDestory()
在销毁的时候会执行Service该方法。
这几个方法都是回调方法,且在主线程中执行,由android操作系统在合适的时机调用。
示例代码:
创建一个类继承自Service
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
System.out.println("onCreat方法被执行了");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("onStartCommand方法被执行了");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("onDestroy方法被执行了");
}
}
在xml中设置两个按钮
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务"
android:onClick="Onclick1"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止服务"
android:onClick="Onclick2"
/>
在AndroidManifest.xml中注册
<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">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".MyBroadcastReceiver"
>
<intent-filter
>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
<service android:name=".MyService">
</service>
</application>
MainActivity
public class MainActivity extends AppCompatActivity {
private Button button1;
private Button button2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = findViewById(R.id.button1);
button2 = findViewById(R.id.button2);
}
public void Onclick1(View v)
{
Intent intent = new Intent(this,MyService.class);
startService(intent);
}
public void Onclick2(View v)
{
Intent intent = new Intent(this,MyService.class);
stopService(intent);
}
}
运行结果
点击按钮停止后
bindService
为什么要引入bindService开启服务的方法
如果想调用服务里的方法 直接创建类调用是不行的
因为Service中缺少上下文对象 我们可以通过bindService解决这个问题
由该方法启动的服务可以进行通信
bindService启动服务特点:
1.第一次点击按钮 执行服务的onCreat和onBind方法
2.当onBind方法返回为null时onServiceConnected方法是不执行的
3.调用者(Activity)销毁时Service也会被销毁
示例代码:
在新建子类继承Service类,并新建一个内部类继承自Binder类。
在Service中暴露出需要被调用的方法
public class MyService extends Service {
public class MyBinder extends Binder{
public void BinderMethod()
{
ServiceMethod();
}
}
private MyBinder myBinder = new MyBinder();
@Nullable
@Override
public IBinder onBind(Intent intent)
{
System.out.println("onBind方法被执行了");
return myBinder;
}
@Override
public void onCreate() {
System.out.println("onCreat方法被执行了");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("onStartCommand方法被执行了");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("onDestroy方法被执行了");
}
@Override
public boolean onUnbind(Intent intent) {
System.out.println("onUnbind方法被执行了");
return super.onUnbind(intent);
}
public int ServiceMethod()
{
Toast.makeText(this,"这是Service中的ServiceMethod方法",Toast.LENGTH_LONG).show();
return 0;
}
}
在AndroidManifest.xml配置Service
<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">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".MyBroadcastReceiver"
>
<intent-filter
>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
<service android:name=".MyService">
</service>
</application>
为MainActivity设置三个按钮 分别为BindService UNBindService和调用Service中的方法
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="bindService"
android:onClick="Onclick1"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="UnbindService"
android:onClick="Onclick2"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="调用Service中的方法"
android:onClick="Onclick3"
/>
在MainActvity中用实现各个按钮的点击事件
public class MainActivity extends AppCompatActivity {
private Myconn myconn;
private MyService.MyBinder myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void Onclick1(View v)
{
Intent intent = new Intent(this,MyService.class);
myconn = new Myconn();
bindService(intent,myconn,BIND_AUTO_CREATE);
}
public void Onclick2(View v)
{
unbindService(myconn);
}
public void Onclick3(View v)
{
myBinder.BinderMethod();
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(myconn);
}
private class Myconn implements ServiceConnection
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder= (MyService.MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
测试结果