Android四大组件Servier(上)
来源:互联网 发布:vue.js a标签跳转 编辑:程序博客网 时间:2024/05/29 18:41
此文赠与龙哥,希望对他有帮助
准备自己复习下,哈哈
1.定义一个服务
首先创建一个服务
public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); }}
可以看到,MyService是继承自Serview的,说明这是一个服务,目前MyService中可以算是空空如也,但是有一个onBind()方法特别醒目。这个方法是Service中唯一一个抽象方法,所以必须在子类中实现,我们后边会使用到onBind(),目前可以先忽略掉
既然是定义一个服务,自然应该在服务中心去处理一些事情,那处理事情的逻辑应该写在哪里,我们重写Service中的另外一些方法,方法如下
@Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); }
可以看到,我们重写了onCreate(),onStartCommand()和onDestory()这个三个方法,他们是每个服务中最长用到3个方法 ,其中
onCreate()在服务创建的时候调用
onStartCommand()方法,在服务每次启用的时候调用,
onDestory()方法在,服务销毁的时候调用
通常情况下,如果我们希望服务一旦启动就立刻去执行摸个动作,就可以吧逻辑写在onStartCommand之中,,当服务销毁时,我们又应该在onDestory方法中取回收那些不再使用的资源
另外需要注意,每一个服务都需要在配置文件中注册才能生效
<service android:name=".MyService" android:enabled="true" android:exported="true"> </service>
2.启动和停止服务
定义好了服务之后,接下来就应该考虑如何去启动和停止这个服务,启动和停止的方法当然你也不会陌生,主要是借助Intent来实现的,下面我们,就尝试在项目中启动和停止MyServicer这个服务
首先我们在布局中,生成两个按钮,一个是开启服务,一个是停止服务
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private Button startService,stopService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService=(Button)findViewById(R.id.start_service); stopService=(Button)findViewById(R.id.stop_serevice); startService.setOnClickListener(this); stopService.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.start_service: Intent startIntent=new Intent(this,MyService.class); startService(startIntent); break; case R.id. stop_serevice: Intent stopIntent=new Intent(this,MyService.class); stopService(stopIntent); break; default: break; } }}
可以看到,我们定义了2个按钮,和他们的点击事件,我们构造出一个Intent对象,并调用startService方法来启动MyService这个服务,另外一个按钮同理
startService()和stopService()的方法都定义在context类中,所以,我们可以直接调用这两个方法。注意,这里完全是由活动来决定服务合适停止的,如果没有点击停止按钮,服务就一直处于运行状态,
那么接下来,我们给MyService的几个方法中加入打印日志
public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { super.onCreate(); Log.i("MyService","onCreate"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("MyService","onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Log.i("MyService","onDestroy"); }}
来进行测试
可以看到,打印日志和我们预计的结果是一样的
其中onCreate()方法是在服务第一次创建的时候调用的,而onSteatCommand()方法这是在每次启动服务中都会调用,
3.活动和服务进行通信
上一小节中我们学习了如何开启和停止服务的放大,虽然服务实在活动中启动的,但是启动服务之后,活动和服务肌肤就没什么关系了,确实如此,我们在活动中调用startService()方法来启动MyService这个服务,然后MyService的onCreat()和onStartCommand()方法机会执行,之后服务会,一直处于运行状态,但具体运行的是什么逻辑,活动是控制不了的。这就类似于活动通知服务一下:‘你可以启动了’,然后服务就去忙自己的事情了,但是活动并不知道服务到底去做什么事情,以及完成的如何。
那么有没有什么办法,能让获得和服务的关系变得更紧密一点,例如活动中指挥服务去做什么,服务就去做什么。当然可以,这就需要借助刚才忽略掉onBind();
比如说,我们希望在MyService里提供一个下载功能,然后在活动中可以决定何时开始下载,以及可以查看下载进度。实现这个功能的思路是创建一个专门的binder对象对下载功能进行管理,修改MyService中的代码,
public class MyService extends Service { private DownloadBinder mBinder=new DownloadBinder(); class DownloadBinder extends Binder{ public void startDownload(){ Log.d("MyService","startDownload executed"); } public int getPregress(){ Log.d("MyService","getPregress executed"); return 0; } } public MyService() { } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() { super.onCreate(); Log.i("MyService","onCreate"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("MyService","onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Log.i("MyService","onDestroy"); }}
可以看到,这里我们新建一个DownloadBinder类,并让他继承自Binder,然后给他的内部提供了,开始下载以及查看下载进度的方法,方然,只是模拟方法,并没有真正实现功能,我们在两个方法中分别打印了日志
接着,在MyService中创建了DownloadBinder的实例,然后onBind()方法中返回了这个实例,这样MyService中的功能结束了,
在布局中我们添加两个按钮
<Button android:id="@+id/bind_service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="bind_service" /> <Button android:id="@+id/unbind_service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="unbind_service" />
两个按钮的作用分别是绑定服务和取消绑定服务,
当一个活动和服务绑定后,就可以调用该服务的binder提供的方法了,修改MainAcitivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private Button startService,stopService,bindService,unbindService; private MyService.DownloadBinder downloadBinder; private ServiceConnection connection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { downloadBinder=(MyService.DownloadBinder)iBinder; downloadBinder.getPregress(); downloadBinder.startDownload(); } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService=(Button)findViewById(R.id.start_service); stopService=(Button)findViewById(R.id.stop_serevice); bindService=(Button)findViewById(R.id.bind_service); unbindService=(Button)findViewById(R.id.unbind_service); startService.setOnClickListener(this); stopService.setOnClickListener(this); bindService.setOnClickListener(this); unbindService.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.start_service: Intent startIntent=new Intent(this,MyService.class); startService(startIntent); break; case R.id. stop_serevice: Intent stopIntent=new Intent(this,MyService.class); stopService(stopIntent); break; case R.id. bind_service: Intent bindIntent=new Intent(this,MyService.class); bindService(bindIntent,connection,BIND_AUTO_CREATE); //绑定服务 stopService(bindIntent); break; case R.id. unbind_service: unbindService(connection);//解绑服务 break; default: break; } }}
可以看到,这里我们首先创建了一个ServiceConnection的匿名类,在里边重写了onServiceConnected()和onServicerDisconnected()方法,这两个方法,分别会在服务和活动绑定成功以及接触绑定的时候调用,在onServiceConnected()方法中,我们向下转型得到了DownloadBinder的实例,有了这个实例,我们就可以调用public方法了,在onServiceConnected()方法中,调用DownloadBinder 的startDownload()和getProgress()方法
,我们运行一下,看下打印
可以看到,。首先,我们的MyService 的onCreate方法得到执行,,然后startDownload和getProgress方法得到执行,说明我们确实成调用了服务中的方法了,
任何一个服务在整个应用程序范围内都是通用的,即MyService不仅可以和MainActivity绑定,还可以和任何一个其他的活动进行绑定,而且在绑定完成后,他们都可以获取到想通的DownloadBinder实例
4.服务的生命周期
一旦在项目中的任何位置,调用了Context的startService()方法,相应的服务就会启动起来,并且回调onStartCommand()方法,如果这个服务没有创建过,onCreate()方法会先于onStartCommand()方法执行。服务启动以后会一直保持运行状态知道stopService()或者stopself()方法被调用。注意,虽然每次调用startService()方法,onStartCommand就会执行一次,但实际上每个服务都会只存在一个实例。所以不管你调用了多少次startService()方法,只需要调用一次stopService()或者stopSelf()fangfa ,服务就会停下来。
另外,还可以调用context的bindService来获取一个服务的持久链接,这是就会回调服务中的onBind方法。如果这个服务之前还没有被创建过,onCreate()方法会先于onBind方法执行。之后,调用方法可以获取到onBind方法里返回的IBinder对象的实例,这样就能自由的和服务进行通信了,只要调用方和服务之间的链接没有断开,服务就会一直保持运行状态
当调用了startService()方法以后,又去调stopService()方法,这时服务中的onDestory()方法就会执行,表示服务已经摧毁。类似的,当调用bindService()方法后,又去调用unbindService方法,onDestory()方法也会执行,这两种都很好理解,但是,
如果一个服务既调用了startService()有调用了,bindService(),这种情况下如何销毁呢
这种情况下,要同事调用stopService()和unbinderService()方法,onDestory()方法才会执行
5.服务的更多技巧
5.1使用前台服务
服务几乎都是在后台运行的,一直以来他都是默默的工作,但是服务的系统优先级还是比较低的。当系统内存不足的情况是,就有可能回收桥正在后台运行的服务。如果你希望服务可以一直保持运行状况,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台服务。前台服务和普通服务的最大的区别就在于,他会一直有一个正在运行的图标在系统的状态栏显示,下拉状态后可以看到更加详细的信息,非常类似于通知的效果。当然有时候,你也可能不仅仅是为了防止服务被回收掉才使用前台服务,有些项目由于特殊的需求会要求必须使用前台服务,比如天气预报,他的服务就是在后台更细腻天气数据的同时,还会在系统状态栏一直显示当前的天气信息
那么我们来写一个前台服务吧,其实并不复杂,修改MyService中的代码,如下所示
@Override public void onCreate() { super.onCreate(); Log.i("MyService","onCreate"); Intent intent=new Intent(this,MainActivity.class); PendingIntent pi=PendingIntent.getActivity(this,0,intent,0); Notification notification=new NotificationCompat.Builder(this) .setContentTitle("This is content title") .setContentText("This is content text") .setWhen(System.currentTimeMillis()) .setSmallIcon(R.mipmap.ic_launcher) .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher)) .setContentIntent(pi) .build(); startForeground(1,notification); }
可以看到,这里只是修改了onCreate()方法中的代码
构建Notification之后,调用startForeground()方法。这里接受2个参数,第一个是通知的id,第二个参数书构建出来的notification对象,调用startForeground方法后就会让MyService变成一个前台服务,并在系统状态栏显示出来。
现在重新运行下程序,启动服务,MyService就会启动一个前台服务,如图
5.2使用IntentService
话说回来,在本章一开始,我们就知道,服务的代码试运行在主线程中的,如果直接在服务中去处理一些耗时操作,就很容易出现ANR
所以这个时候,就需要使用android 的多线程的技术了,我们应该在服务的每个具体的方法中开启一个子线程,然后在这里去处理耐心额耗时的逻辑。因此,一个比较标准的服务就可以写成
@Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("MyService","onStartCommand"); new Thread(new Runnable() { @Override public void run() { //处理具体逻辑 stopSelf(); } }).start(); return super.onStartCommand(intent, flags, startId); }
虽然这样写并不复杂,但是总会有一些程序员忘记开启线程,或者忘记结束服务,为了可以简单的创建一个一步的会自动停止的服务,android专门提供了一个IntentService类,这个类就可以很好的解决前面提到的2中尴尬,
新建一个MyIntentService继承自IntentService,代码如下所示:
public class MyIntentService extends IntentService { public MyIntentService(String name) { super(name);//调用父类的有璨构造函数 } @Override protected void onHandleIntent(@Nullable Intent intent) {//打印当前线程ID Log.d(" MyIntentService","Thread id is "+Thread.currentThread().getId()); } @Override public void onDestroy() { super.onDestroy(); Log.d("MyIntentService","onDestory executed"); }}
首先提供一个无参构造函数,并且必须在其内部调用父类的有参构造函数。然后要在子类中实现onHandleIntent()这个抽象方法,在这个方法中可以去处理一些具体逻辑,而且完全不用担心anr的问题
因为这个方法已经在子线程中运行了,这里为了证实一下,我们在onHandleIntent方法中打印当前线程id
另外更具IntentService的特性,这个服务在运行结束后会自动停止,我们写了打印日志,来验证下
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private Button startService,stopService,bindService,unbindService,startIntentService; private MyService.DownloadBinder downloadBinder; private ServiceConnection connection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { downloadBinder=(MyService.DownloadBinder)iBinder; downloadBinder.getPregress(); downloadBinder.startDownload(); } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService=(Button)findViewById(R.id.start_service); stopService=(Button)findViewById(R.id.stop_serevice); bindService=(Button)findViewById(R.id.bind_service); unbindService=(Button)findViewById(R.id.unbind_service); startIntentService=(Button)findViewById(R.id.start_intent_service); startService.setOnClickListener(this); stopService.setOnClickListener(this); bindService.setOnClickListener(this); unbindService.setOnClickListener(this); startIntentService.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.start_service: Intent startIntent=new Intent(this,MyService.class); startService(startIntent); break; case R.id. stop_serevice: Intent stopIntent=new Intent(this,MyService.class); stopService(stopIntent); break; case R.id. bind_service: Intent bindIntent=new Intent(this,MyService.class); bindService(bindIntent,connection,BIND_AUTO_CREATE); //绑定服务 stopService(bindIntent); break; case R.id. unbind_service: unbindService(connection);//解绑服务 break; case R.id.start_intent_service: Log.i("MainActivity","Thread id is "+Thread.currentThread().getId()); Intent intent=new Intent(this,MyIntentService2.class); startService(intent); break; default: break; } }}
可以看到,我们在StartIntentService 按钮的点击时间里面去启动,MyIntentService这个服务,并在这里打印一线主线程,
记得在配置文件中注册下这个服务
打一下日志
可以看到,不仅MyIntentService和MainActivity所在的线程id不一样,并且onDestory()方法也得到执行,索命,MyIntentServicezai 运行完毕后会自动停止。集成了开启线程和自动停止于一身,IntentService还是博得了不少程序员的喜爱。
Servier(上)到此结束
- Android四大组件Servier(上)
- Android四大组件Servier(下)
- 四大组件之一Servier
- Android四大组件之 Activity(上)
- Android四大组件之BroadcastReceiver(上)
- Android四大组件之ContentProvider(上)
- Android 四大组件之 Service (上)
- Android四大组件之一:Activity总结(上)
- Android四大组件之Activity<上>
- Android四大组件(摘要)
- Android四大基本组件(3)之四大组件总结
- (Android入门)Android四大组件
- Android四大组件之ContentProvider(二)读取设备上的图片、音频和视频
- [Android知识体系]之四大组件:service(完全解析上)
- Android开发艺术探索——第九章:四大组件的工作过程(上)
- [Android学习笔记4]四大应用组件之一:Service 上
- Android Studio 四大组件之 Service的生命周期上
- Android四大组件之一Service(服务)
- C++中的yield和fork
- [简单逻辑学]逻辑学的基本原理——否定命题
- 基于分布式环境下限流系统的设计
- Java初学者的感悟
- volatile变量在多线程同步时运用的优点: 1、锁一次只允许一个线程访问值,volatile 允许多个线程执行读操作,因此当使用 volatile 保证读代码路径时,要比使用锁执行全部代码路径获得
- Android四大组件Servier(上)
- 数据字典
- PAT (Basic Level) Practise (中文)1001. 害死人不偿命的(3n+1)猜想 (15)
- D13
- 机器学习笔记(XIII)决策树(III)连续与缺失值
- 一键解决您scrapy安装不上的问题,包括lxml的难题,非常好使
- 面试过阿里等互联网大公司,我知道了这些套路
- consistent hashing(一致性hash)
- 将数据库中数据下载到csv格式文件中