简单了解Android的Service

时间:2022-01-16 17:02:39
来自小白的突突突。。。(看完大神的博客写的,原文在文末)


平时感觉对service已经很熟悉的了,但是用起来的时候感觉,诶,不熟

该博文是我为了加深自己对service的加深理解而写的,不喜欢的大大,可以忽略。。。


首先简单了解一下Service是如何启动的
Service作为android的四大组件之一,在每一个应用中都扮演着非常重要的角色,他主要用于在后台处理一些耗时的操作。或者去执行某些需要长期运行的任务,必要的时候,可以在程序退出的情况下,让Service在后台继续保持运行状态




定义一个MyService类继承Service类

/**
 * Created by Administrator on 2017/7/17.
 */


public class MyService extends Service {
    private static final String TAG = "MyService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: " );
        return null;
    }




    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "service oncreate" );
    }




    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: " );
    }
}




服务要在清单应用中配置Service




 <service android:name=".MyService"></service>








布局中有两个按钮


在Activity中实列化两个按钮,然后设置点击事件
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button startService,DestoryService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        startService = (Button) findViewById(R.id.startService);
        DestoryService = (Button) findViewById(R.id.DestoryService);


        startService.setOnClickListener(this);
        DestoryService.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.startService:
                Intent intent = new Intent(MainActivity.this,MyService.class);
                startService(intent);//启动服务
                break;
            case R.id.DestoryService:
                Intent intent2 = new Intent(MainActivity.this,MyService.class);
                stopService(intent2);
                break;
        }
    }
}
不断点击启动服务,然后点击destory服务
简单了解Android的Service





可以看到,在Start Service按钮的点击事件里,我们构建了一个Intent对象,并调用StartService()方法来启动服务。。。。。
、我们同样构建出了一个Intent对象,并调用StopService()方法来停止我们的服务,




启动服务,就可以在oncrete或onStartCommand()方法里面去执行一些具体的逻辑,不过这样的Service和Activity的关系并不大,只是Activity通知了Service,“你可以启动了”,然后Service就去忙自己的了,






那么有没有什么办法能让他们两的关系更多一点呢,比如在Activity中可以指定Service去执行什么任务,当然可以,只是需要Activity和Service建立关联。。。










新建一个Service类,里面一个内部类,这个类继承Binder,在onBinder方法中返回给类的对象


在Activity新建ServiceConnect对象,把Binder向下转型,获得该返回的对象,然后就可以在Activity中操作服务中的任务了


Service


/**
 * Created by Administrator on 2017/7/17.
 */


public class MyService extends Service {
    private static final String TAG = "MyService";
    private MyBinder mybinder = new MyBinder();


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: " );
        return mybinder;
    }


    @Override
    public void onCreate() {
        Log.e(TAG, "onCreate: ");
        super.onCreate();
    }




    @Override
    public int onStartCommand(Intent intent,  int flags, int startId) {
        Log.e(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy: " );
        super.onDestroy();
    }




    //怎么让Activity可以控制Service的任务呢
    //定义一个类,然后在ONBind中和Activity建立关系
    class MyBinder extends Binder{
        //假如Activity让Service去下载,当然也可以暂停啊,取消下载等等啦
        void loading(){
            Log.e(TAG, "开始下载 " );
            //下载的逻辑
        }
    }
}




在清单文件中配置






Activity代码


public class MainActivity extends AppCompatActivity implements View.OnClickListener {
     private Button bindServiceButton,unBindServiceButton;
    ServiceConnection serviceConnect;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //通过ServiceConnect找到服务返回的类
        serviceConnect = new ServiceConnection() {
            //Activity和服务创建关系的时候
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
              MyService.MyBinder binder =   (MyService.MyBinder)service;
                //启动服务的时候,并且启动下载
                binder.loading();
            }


            //Activiity和Service断开关系的时候
            @Override
            public void onServiceDisconnected(ComponentName name) {


            }
        };




        bindServiceButton = (Button) findViewById(R.id.bindService);
        unBindServiceButton = (Button) findViewById(R.id.unbindService);


        bindServiceButton.setOnClickListener(this);
        unBindServiceButton.setOnClickListener(this);
    }




    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bindService:
                Intent bindIntent = new Intent(MainActivity.this,MyService.class);
                bindService(bindIntent,serviceConnect,BIND_AUTO_CREATE);//第三个参数标记,Activity和service建立关联的时候,自动创建Service
               /* public boolean bindService(android.content.Intent service,
                    android.content.ServiceConnection conn,
                int flags)*/
                break;
            case R.id.unbindService:
                //解除关联
                unbindService(serviceConnect);
                break;
        }
    }
}






随意点击绑定服务按钮和解绑服务按钮,其实绑定一次后,就可以再绑定,然后解绑一次后,也不可以再次解绑。

简单了解Android的Service


Service可以在程序的任何一个Activity中获的
bindServic当Activity销毁的时候,Service也会销毁,
startSevice当Activity销毁的时候,Service不会销毁












上面的Activity和Service加强联系已经学完




那么Service和Thread的关系是怎样的呢?
请各位看客往下面看;
什么时候用Service什么时候用线程呢?
其实Service和Thread和线程没有任何关系。。。
之所以有不少人会把它们联系起来,主要就是因为Service的后台概念。Thread我们大家都知道,是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行。而Service我们最初理解的时候,总会觉得它是用来处理一些后台任务的,一些比较耗时的操作也可以放在这里运行,这就会让人产生混淆了。但是,如果我告诉你Service其实是运行在主线程里的,你还会觉得它和Thread有什么关系吗?让我们看一下这个残酷的事实吧。




在MainActivity的onCreate()方法里加入一行打印当前线程id的语句:
[java] view plain copy
Log.d("MyService", "MainActivity thread id is " + Thread.currentThread().getId());  
然后在MyService的onCreate()方法里也加入一行打印当前线程id的语句:
[java] view plain copy
Log.d("MyService", "MyService thread id is " + Thread.currentThread().getId());  
现在重新运行一下程序,并点击Start Service按钮,会看到如下打印日志:






可以看到,它们的线程id完全是一样的,由此证实了Service确实是运行在主线程里的,也就是说如果你在Service里编写了非常耗时的代码,程序必定会出现ANR的。


你可能会惊呼,这不是坑爹么!?那我要Service又有何用呢?其实大家不要把后台和子线程联系在一起就行了,这是两个完全不同的概念。Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。你可能又会问,前面不是刚刚验证过Service是运行在主线程里的么?在这里一直执行着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。


额,既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。


一个比较标准的Service就可以写成:
[java] view plain copy
@Override  
public int onStartCommand(Intent intent, int flags, int startId) {  
    new Thread(new Runnable() {  
        @Override  
        public void run() {  
            // 开始执行后台任务  
        }  
    }).start();  
    return super.onStartCommand(intent, flags, startId);  
}  
  
class MyBinder extends Binder {  
  
    public void startDownload() {  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                // 执行具体的下载任务  
            }  
        }).start();  
    }  
  
}  






创建前台Service
public class MyService extends Service {  
  
    public static final String TAG = "MyService";  
  
    private MyBinder mBinder = new MyBinder();  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        Notification notification = new Notification(R.drawable.ic_launcher,  
                "有通知到来", System.currentTimeMillis());  
        Intent notificationIntent = new Intent(this, MainActivity.class);  
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,  
                notificationIntent, 0);  
        notification.setLatestEventInfo(this, "这是通知的标题", "这是通知的内容",  
                pendingIntent);  
        startForeground(1, notification);  
        Log.d(TAG, "onCreate() executed");  
    }  
  
    .........  
  
}  
这里只是修改了MyService中onCreate()方法的代码。可以看到,我们首先创建了一个Notification对象,然后调用了它的setLatestEventInfo()方法来为通知初始化布局和数据,并在这里设置了点击通知后就打开MainActivity。然后调用startForeground()方法就可以让MyService变成一个前台Service,并会将通知的图片显示出来。










我的博文是看郭霖大神的文章写的(接近于相同,目的只是为了加深自己的理解),
大家也可以去阅读,传送门:::
http://blog.csdn.net/guolin_blog/article/details/11952435/
http://blog.csdn.net/guolin_blog/article/details/9797169