Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

(详细)Service、IntentService、BindService

$
0
0

/**
* Service 服务
* Service是一个不提供用户界面在后台执行耗时操作的应用程序组件。
* 没界面 运行在后台 耗时操作
*
* 注意:service服务运行在主进程的主线程中
* service默认不会开启工作线程
* 如果执行耗时操作时 需要程序员手动开启工作线程
* Service不是一个进程也不是一个线程
*
* 什么情况下使用service什么情况使用worker Thread ? 耗时操作
* 如果执行耗时操作时用户不需要与app交互(耗时操作的结果可能不展示到用户界面)时采用service 例如:下载文件存储
* 如果执行耗时操作用户需要与app交互(耗时操作的结果需要展示到ui)时采用开启worker Thread 例如:ui界面网络加载
*
* 按照服务的启动方式 将服务划分为两类
* 启动服务 startService()
* 绑定服务 bindService()
*
* 启动式服务:应用程序组件(Activity)调用startService()方法启动服务时称为启动时服务
* 特点:
* 1.调用startService()方法一旦启动服务就会一直运行在后台 直到服务被杀死(自杀、他杀、系统回收)
* 2.启动服务的组件(Activity)被销毁后 启动的服务会一直运行 不受影响
* 3.启动式服务在后台执行单一的操作 不会将服务的操作结果*返回*给启动它的组件
*/

/**
     * 点击按钮启动服务
     * @param view
     */
    public void start(View view){
        Intent intent=new Intent(MainActivity.this,MyService.class);
        intent.putExtra("str","传递数据到service");
        startService(intent);//启动服务
    }

    /**
     * 点击按钮停止服务
     * @param view
     */
    public void stop(View view){
        Intent intent=new Intent(MainActivity.this,MyService.class);
        stopService(intent);//根据intent中指定的对象停止服务
    }

/**
* 启动式服务的生命周期
* 当应用程序组件(Activity)调用startService()启动服务先回调onCreate()方法创建和初始化service—
* 接着回调onStartCommand()方法接收Intent意图请求并且开启工作线程执行耗时操作—-
* 当service中的操作执行完毕后调用StopSelf()或者时其它组件调用 stopService()就会回调onDestory()释放资源
*/
启动时服务生命周期
onCreate()—>onStartCommand()—>StopService()

public class MyService extends Service{

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 表示当service第一次创建时回调的函数  初始化  注意:service只能被创建一次
     */
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("tag","--------onCreate-----");
    }

    /**
     * 表示当应用程序组件调用startService()方法启动服务时 服务就会启动并且回调该方法
     * @param intent  应用程序组件调用startService()启动服务时传递的Intent对象
     * @param flags   表示开启服务是够需要传递额外的数据
     * @param startId 用来唯一标示start请求
     * @return 表示当系统回调完onStartCommand()方法后 service被系统意外杀死时  是否能够重新启动服务以及
     * 是否可以继续执行请求操作
     *  根据返回值将service划分为粘性service和非粘性service
     *
     * START_STICKY(常量1) STICKY粘性  当应用程序执行完onStartCommand()方法后 service被异常kill
     * 系统会自动重启服务  但是在重启服务时传入的intent为null  车祸苏醒失忆
     *
     * START_NOT_STICKY(常量2) 非粘性  当应用程序执行完onStartCommand()方法后 service被异常kill
     * 系统不会自动重启服务       车祸死亡
     *
     * START_REDELIVER_INTENT(常量3) 当应用程序执行完onStartCommand()方法后 service被异常kill
     * 系统会自动的重启服务并且将Intent重新传入   车祸苏醒正常
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("tag","--------onStartCommand-----"+intent.getStringExtra("str"));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        stopSelf();//自杀
        return START_REDELIVER_INTENT;
    }

    /**
     * 标示当service被销毁时回调的函数   资源释放
     * stopService();
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("tag","--------onDestroy-----");
    }
}

示例:
/**
* 需求:点击按钮时启动服务下载图片 下载完成后存储到本地并且发送一个通知
* 点击通知打开下载的图片
*/

public class MainActivity extends AppCompatActivity {
    private String imageUrl="http://f.hiphotos.baidu.com/image/h%3D200/sign=236c94ef2c381f3081198aa999004c67/242dd42a2834349bbe78c852cdea15ce37d3beef.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    //点击按钮启动服务下载图片
    public void downLoad(View view){
        Intent intent=new Intent(MainActivity.this,DownLoadService.class);
        intent.putExtra("imagePath",imageUrl);
        startService(intent);
    }
}
public class DownLoadService extends Service{
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    //获取下载图片的地址--启动工作线程--下载图片--存储到本地--发送通知
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
         //1.获取下载图片的地址
        final String imagePath=intent.getStringExtra("imagePath");
        //2.启动工作线程 service本身是在主线程的主进程中且本身不会开启线程,因而需要自己手动开启线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                //3.下载图片
                if(HttpUtils.isNetWorkConn(DownLoadService.this)){
                    byte[] buff=HttpUtils.getHttpResult(imagePath);
                    if(buff!=null && buff.length!=0){
                        String fileName=imagePath.substring(imagePath.lastIndexOf("/")+1);
                        //4.存储到本地
                        boolean bl=ExternalStorgaUtils.
                                writeExternalStoragePublic(Environment.DIRECTORY_DOWNLOADS,
                                        fileName,buff);
                        if(bl){
                            Log.i("tag","存储成功");
                            //5.发送通知
                            sendNotification(fileName);
                        }else{
                            Log.i("tag","存储失败");
                        }
                    }else{
                        Log.i("tag","下载失败");
                    }
                }else{
                    Log.i("tag","网络异常");
                }
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }
 //发送通知的饿方法
    public void sendNotification(String fileName){
        NotificationCompat.Builder builder=new NotificationCompat.Builder(DownLoadService.this);
        builder.setContentTitle("提示信息");
        builder.setContentText("下载完成");
        builder.setSmallIcon(R.mipmap.ic_launcher);

        Intent intent=new Intent(DownLoadService.this,ResultActivity.class);
        intent.putExtra("fileName",fileName);
        PendingIntent pi=PendingIntent.getActivity(DownLoadService.this,1,
                intent,PendingIntent.FLAG_ONE_SHOT);
        builder.setContentIntent(pi);

        NotificationManager manager= (NotificationManager)
                getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(1,builder.build());
    }
    public class ResultActivity extends AppCompatActivity{
    private ImageView iv;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_result);
        iv= (ImageView) findViewById(R.id.iv);
        //获取通知中传递的文件名称
         String fileName=getIntent().getStringExtra("fileName");
        //获取图片文件的路径  storage/sdcard/downloads/filename
        String pathName= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                        .getAbsolutePath()+ File.separator+fileName;
        //decodeFile(String path) 根据参数中指定图片的路径转换成bitmap对象
        Bitmap bm= BitmapFactory.decodeFile(pathName);
        iv.setImageBitmap(bm);

        //关闭通知
        NotificationManager manager= (NotificationManager)
                getSystemService(Context.NOTIFICATION_SERVICE);
        manager.cancel(1);
    }
}

IntentService
/**
* IntentService和Service的区别?
* IntentService是Service的具体子类
* 当服务中只需要开启一个工作线程就可以完成耗时操作时 这时建议采用IntentService
* 当服务中仅开启一个工作线程并不能满足需求时 建议开启多个工作线程 使用service
*
* IntentService的特点:
* 1.IntentService底层采用队列的形式管理发送的 Intent对象 其它组件发送的请求都会
* 存储到该队列中 IntentService中回调onHandleIntent()方法依次处理队列中的请求
* onHandleIntent()底层已经开启工作线程
*
* 2. 当应用程序组件(Activity)调用startService()启动 IntentService时会执行
* onCreate()-onStartCommand()-onHandleIntent()-onDestory()
* 注意:onHandleIntent()执行完成请求后将服务自动销毁
*/

/**
 * 需求:根据网络地址下载apk文件 并且下载完成后在线安装
 */
public class MainActivity extends AppCompatActivity {
    private String apkPath="http://apk.99danji.com/99apk/FlappyBird_20150730.apk";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    //点击按钮启动服务
    public void start(View view){
        Intent intent=new Intent(MainActivity.this,MyIntentService.class);
        intent.putExtra("path",apkPath);//启动服务时传递apk的下载地址
        startService(intent);
    }
}

/**
* 绑定服务
* 应用程序组件(Activity)调用bindService()方法启动服务时 称为绑定服务
* bindService()将服务玉启动服务绑定到一起
*
* 特点:
* 1.绑定式服务类似与客户端-服务端的接口形式 允许应用程序组件(Activity)与服务进行交互
* (activity可以访问service的方法)
* 2.应用程序组件(Activity)调用bindService()方法将activity与service绑定到一起并且启动运行service
* 3.应用程序组件与service运行时间一致
* 多个应用程序组件可以同时绑定到同一个服务 服务销毁 绑定解除
* 当绑定多个应用程序的组件都被销毁时 服务也跟着被销毁
* 一方销毁另一方跟着销毁
*/
/**
* 绑定式服务的生命周期:
* 应用程序组件(Activity)调用bindService()绑定服务时回调用onCreate()创建服务--
* 回调onbind()方法将应用组件与service绑定到一起建立链接–当应用程序组件退出或者调用
* unBindService()方法时解除绑定回调onUnBind()方法-- 最后当所有绑定服务的应用程序
* 都退出时回调onDestory()销毁服务
*/

public class MainActivity extends AppCompatActivity {
    private MyServiceConnection connection;
    private MyService myService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        connection=new MyServiceConnection();
    }

    /**
     * 以内部类的形式构建ServiceConnection接口子类
     */
    public class MyServiceConnection implements ServiceConnection{
        /**
         * 表示当应用程序组件与service绑定成功后回调的函数
         * @param name
         * @param service
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
                Log.i("tag","-------onServiceConnected------");
            MyService.MyBinder myBinder= (MyService.MyBinder) service;//向下转型 Ibinder---MyBinder
            myService=myBinder.getService();//获取service的对象
            int num=myService.getRandom();
            Log.i("tag","获取的随机数是:"+num);
        }

        /**
         * 表示绑定服务意外中断时回调的函数
         * @param name
         */
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }

    /**
     * 点击按钮绑定服务
     */
    public void bind(View view){
        /*
        bindService(Intent service, @NonNull ServiceConnection conn,int flags)
        Intent service,   表示绑定服务的意图对象(允许采用隐式意图和显式意图)
        @NonNull ServiceConnection conn, 表示监听当前组件绑定的服务变化的接口
        int flags 表示对绑定服务操作的标记
        返回值为boolean类型  表示是否成功绑定服务
        BIND_AUTO_CREATE 常量 表示绑定服务时若服务没有创建 则先创建再绑定
         */
        Intent intent=new Intent(MainActivity.this,MyService.class);
        boolean bl=bindService(intent,connection, Context.BIND_AUTO_CREATE);
        Log.i("tag","服务绑定成功了吗?"+bl);
    }

    /**
     * 点击按钮解除绑定服务
     */
    public void unBind(View view){
        unbindService(connection);//解除绑定
    }
}
public class MyService extends Service{
    /**
     * 表示服务第一次创建时回调的函数
     */
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("tag","---------onCreate------");
    }




    /*
     * 需求:绑定服务的activity组件访问service中的getRandom()方法该如何操作?
     *  如果想要调用类中的函数 需要创建类的对象 然后对象.函数() 但是service是一个应用程序组件
     *  所以在使用时不能直接通过new service()de形式构建对象 如何获取service类的对象?
     *  发现应用程序组件调用bindService()方法绑定服务成功可以获取onBind()方法的返回值IBinder对象
     *  IBinder是一个接口 所以在service中定义一个IBinder类的子类 发现如果直接实现IBinder接口 需要
     *  重写的函数比较多 所以选择继承IBinder这个接口的子类Binder类  在继承Binder类的内部类中
     *  定义一个函数返回当前servive的对象 那么activity与service链接成功后就可以获取Ibinder对象
     *  进而就获取服务对象
     */
    public int getRandom(){
        return (int) (Math.random()*10+1);
    }
    /**
     * 表示应用程序组件(activity)调用bindService()方法绑定服务时
     *  注意:应用程序与service只能绑定一次
     * @param intent
     * @return
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("tag","---------onBind------");
        return new MyBinder();
    }
    /*
    构建Ibinde若接口的具体子类对象
     */
    public class MyBinder extends Binder{
        //定义函数 返回当前service服务类的对象
        public MyService getService(){
            return MyService.this;
        }
    }




    /**
     * 表示应用程序组件(activity)与service解除绑定时回调的函数
     * @param intent
     * @return
     */
    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("tag","---------onUnbind------");
        return super.onUnbind(intent);
    }

    /**
     * 表示当其它的应用程序组件绑定服务时回调的函数
     * @param intent
     */
    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        Log.i("tag","---------onRebind------");
    }

    /**
     * 表示当service销毁时回调的函数
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("tag","---------onDestroy------");
    }
}

示例:bindService实现后台播放音乐

public class MainActivity extends AppCompatActivity {
    private ServiceConnection conn;
    private PlayMusicService playMusicService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        conn=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                PlayMusicService.MyBinder myBinder= (PlayMusicService.MyBinder) service;
                playMusicService=myBinder.getService();
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
        Intent intent=new Intent(this,PlayMusicService.class);
        boolean bl=bindService(intent,conn, Context.BIND_AUTO_CREATE);
        Log.i("tag","服务绑定成功了吗?"+bl);
    }



    /**
     * 点击按钮执行操作
     * @param view
     */
    public void clickView(View view){
        switch (view.getId()){
            case R.id.btn_play:
                playMusicService.playMusic();
                break;
            case R.id.btn_pause:
                playMusicService.pauseMusic();
                break;
            case R.id.btn_stop:
                playMusicService.stopMusic();
                break;
        }
    }
}
public class PlayMusicService extends Service{
    private MediaPlayer mediaPlayer;
    private boolean isStop=false;//标示是否停止
    @Override
    public void onCreate() {
        super.onCreate();
        initMediaPlayer();//初始化操作
    }
    /*
    初始化MediaPlayer
     */
    public void initMediaPlayer(){
        if(mediaPlayer==null){
            mediaPlayer=new MediaPlayer();
        }
        mediaPlayer.reset();
        try {
            //设置assets资产中的文件作为MediaPlayer播放音频源
            AssetFileDescriptor sdf=getAssets().openFd("thatway.mp3");
            mediaPlayer.setDataSource(sdf.getFileDescriptor(),
                    sdf.getStartOffset(),sdf.getLength());
            mediaPlayer.prepare();//准备方法  播放之前MediaPlayer必须处于准备状态
            if(sdf!=null){
                sdf.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //表示播放异常时触发的监听器
        mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                mp.reset();
                Toast.makeText(PlayMusicService.this,"播放异常!",Toast.LENGTH_LONG).show();
                return false;
            }
        });
        //表示播放完毕后触发的监听器
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                Toast.makeText(PlayMusicService.this,"音乐播放完毕!",Toast.LENGTH_LONG).show();
            }
        });

    }
    /*
    播放音乐
     */
     public void playMusic(){
         if(isStop){
             initMediaPlayer();
             isStop=false;
         }
         if(mediaPlayer!=null && !mediaPlayer.isPlaying()){//isPlaying() true表示正在播放
             mediaPlayer.start();//播放音乐
         }
     }

    /*
    暂停音乐
     */
    public void pauseMusic(){
        if(mediaPlayer!=null && mediaPlayer.isPlaying()){
            mediaPlayer.pause();
        }
    }
    /*
    停止播放
     */
    public void stopMusic(){
        if(mediaPlayer!=null){
            mediaPlayer.stop();
            isStop=true;
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    public class MyBinder extends Binder{
        public PlayMusicService getService(){
            return PlayMusicService.this;
        }
    }

    @Override
    public boolean onUnbind(Intent intent) {
        if(mediaPlayer!=null){
            mediaPlayer.release();//重置
            mediaPlayer=null;
        }
        return super.onUnbind(intent);
    }
}
作者:u010296640 发表于2016/10/15 10:27:04 原文链接
阅读:53 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>