zoukankan      html  css  js  c++  java
  • Android—Service与Activity的交互

       service—Android的四大组件之一。人称“后台服务”指其本身的运行并不依赖于用户可视的UI界面

       实际开发中我们经常需要service和activity之间可以相互传递数据维持程序的运行。

       先了解Service的生命周期吧。

    新建一个类继Service:

    package com.example.myservicedemo.service;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    
    /**
     * 服务类(需要在项目清单文件中注册服务)
     * 
     * @author lenovo
     *
     */
    public class MyService extends Service {
    	@Override
    	public IBinder onBind(Intent intent) {
    		// TODO Auto-generated method stub
    		return null;
    	}
        /**
         * 服务创建的时候调用
         */
    	@Override
    	public void onCreate() {
    		// TODO Auto-generated method stub
    		super.onCreate();
    		System.out.println("=========onCreate======");
    	}
        /**
         * 服务启动的时候调用
         */
    	@Override
    	public int onStartCommand(Intent intent, int flags, int startId) {
    		// TODO Auto-generated method stub
    		System.out.println("=========onStartCommand======");
    		return super.onStartCommand(intent, flags, startId);
    	}
        /**
         * 服务销毁的时候调用
         */
    	@Override
    	public void onDestroy() {
    		// TODO Auto-generated method stub
    		System.out.println("=========onDestroy======");
    		super.onDestroy();
    	}
    }
    

     新建以上类并继承Service后只会重写onBind()方法,其他方法是我手动手写,为了弄清楚Service的生命周期

     MainActivity中(设置两个按钮用来开始和停止服务):

    package com.example.myservicedemo.ui;
    
    import com.example.myservicedemo.R;
    import com.example.myservicedemo.service.MyService;
    import com.example.myservicedemo.service.MyService.DownLoadBinder;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    public class MainActivity extends Activity implements OnClickListener {
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		Button btn_start = (Button) findViewById(R.id.btn_start);
    		Button btn_stop = (Button) findViewById(R.id.btn_stop);
    		btn_start.setOnClickListener(this);
    		btn_stop.setOnClickListener(this);
    	}
    
    	@Override
    	public void onClick(View v) {
    		// TODO Auto-generated method stub
    		int id = v.getId();
    		switch (id) {
    		/*
    		 * 开启服务点击事件
    		 */
    		case R.id.btn_start:
    			Intent startIntent = new Intent(this, MyService.class);
    			startService(startIntent);
    			break;
    		/*
    		 * 停止服务点击事件
    		 */
    		case R.id.btn_stop:
    			Intent stopIntent = new Intent(this, MyService.class);
    			stopService(stopIntent);
    			break;
    
    		default:
    			break;
    		}
    	}
    
    }
    

      切记android中的服务是需要在项目清单文件中注册的(AndroidStudio可以自动,eclipse需要手动添加):

          <service android:name="服务类坐所在的包名.MyService"></service>

          此时运行程序,点击开启服务时候输出是下图:(我输出多次onStartCommand()是因为我连续点击了多次开启服务按钮)

       

      上图可以看出服务第一次开启时先是调用了onCreate()方法和onStartCommand()方法,多次点击开始服务时只调用了onStartCommand()方法

       so:

       onCreate()方法是服务创建的时候调用的~

       onStartCommand()方法在每次启动服务的时候都会调用~

       onDestory()方法在停止服务时候会调用~

       点击停止服务后,输出如图:

     

     启动服务还有一种方式是bindService();

     此时的MyService类要做改变:

    package com.example.myservicedemo.service;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    
    /**
     * 服务类(需要在项目清单文件中注册服务)
     * 
     * @author lenovo
     *
     */
    public class MyService extends Service {
        private DownLoadBinder downLoadBinder=new DownLoadBinder();
    	@Override
    	public IBinder onBind(Intent intent) {
    		// TODO Auto-generated method stub
    		System.out.println("=====onBind=====");
    		return downLoadBinder;
    	}
    	/**
    	 * 内部类继承Binder
    	 * @author lenovo
    	 *
    	 */
    	public class DownLoadBinder extends Binder{
    		public void startDownLoad(){
    			System.out.println("=====startDownLoad()=====");
    		}
    		public void getProgress(){
    			System.out.println("=====getProgress()=====");
    		}
    	}
        /**
         * 服务创建的时候调用
         */
    	@Override
    	public void onCreate() {
    		// TODO Auto-generated method stub
    		super.onCreate();
    		System.out.println("=========onCreate======");
    	}
        /**
         * 服务启动的时候调用
         */
    	@Override
    	public int onStartCommand(Intent intent, int flags, int startId) {
    		// TODO Auto-generated method stub
    		System.out.println("=========onStartCommand======");
    		return super.onStartCommand(intent, flags, startId);
    	}
        /**
         * 服务销毁的时候调用
         */
    	@Override
    	public void onDestroy() {
    		// TODO Auto-generated method stub
    		System.out.println("=========onDestroy======");
    		super.onDestroy();
    	}
    }
    

      以上的代码和第一次相比,一是多了一个内部类DownLoadBinder继承IBinder并且声明了两个方法,二是将onBind方法的返回值改为了DownLoadBinder类型的变量

         activity bindService方法启动服务时候一般是需要传递数据的,核心就在onBind()方法中,往下看

     MainActivity中加两个按钮:绑定服务和取消绑定服务

      

    package com.example.myservicedemo.ui;
    
    import com.example.myservicedemo.R;
    import com.example.myservicedemo.service.MyService;
    import com.example.myservicedemo.service.MyService.DownLoadBinder;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    public class MainActivity extends Activity implements OnClickListener {
        private MyService.DownLoadBinder downLoadBinder;
        private MyService myService;  //我们自己的service  
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		Button btn_start = (Button) findViewById(R.id.btn_start);
    		Button btn_stop = (Button) findViewById(R.id.btn_stop);
    		Button btn_bind = (Button) findViewById(R.id.btn_bind);
    		Button btn_unbind = (Button) findViewById(R.id.btn_unbind);
    		btn_start.setOnClickListener(this);
    		btn_stop.setOnClickListener(this);
    		btn_bind.setOnClickListener(this);
    		btn_unbind.setOnClickListener(this);
    	}
    
    	@Override
    	public void onClick(View v) {
    		// TODO Auto-generated method stub
    		int id = v.getId();
    		switch (id) {
    		/*
    		 * 开启服务点击事件
    		 */
    		case R.id.btn_start:
    			Intent startIntent = new Intent(this, MyService.class);
    			startService(startIntent);
    			break;
    		/*
    		 * 停止服务点击事件
    		 */
    		case R.id.btn_stop:
    			Intent stopIntent = new Intent(this, MyService.class);
    			stopService(stopIntent);
    			break;
    		/*
    		 * 绑定服务点击事件
    		 */
    		case R.id.btn_bind:
    			Intent bindIntent = new Intent(this, MyService.class);
    			bindService(bindIntent, connection, BIND_AUTO_CREATE);
    			break;
    		/*
    		 * 解除绑定服务点击事件
    		 */
    		case R.id.btn_unbind:
                unbindService(connection);
    			break;
    
    		default:
    			break;
    		}
    	}
    	private ServiceConnection connection=new ServiceConnection() {
    		/**
    		 * 服务解除绑定时候调用
    		 */
    		@Override
    		public void onServiceDisconnected(ComponentName name) {
    			// TODO Auto-generated method stub
    			
    		}
    		/**
    		 * 绑定服务的时候调用
    		 */
    		@Override
    		public void onServiceConnected(ComponentName name, IBinder service) {
    			// TODO Auto-generated method stub
    			//myService=((DownLoadBinder) service).
    			downLoadBinder=(DownLoadBinder) service;
    			/*
    			 * 调用DownLoadBinder的方法实现参数的传递
    			 */
    			downLoadBinder.startDownLoad();
    			downLoadBinder.getProgress();
    		}
    	};
    
    }
    

      运行后点击绑定服务后输出如下:

         

         说明成功绑定了服务且传递了数据,点击解除绑定服务时候ondestory()方法输出

        不过这种方法好像只能传递一次数据,,,,不爽,,,,比如后台在实时更新东西,activity需要实时获取呢???

        查找资料大多是以下几种方式:

       1.使用接口回调方式,activity实现相应的接口,service通过接口进行回调,比较灵活

       2.使用广播

        这篇博客主要介绍第一种方法,为什么不介绍第二种???——不愿意介绍,不喜欢。

        使用接口回调方式的MyService和MainActivity代码我是备注详细之后才粘贴的,大家可以看注释

        MyService代码:

        

    package com.example.myservicedemo.service;
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    
    /**
     * 服务类(需要在项目清单文件中注册服务)
     * 
     * @author lenovo
     *
     */
    public class MyService extends Service {
        private DownLoadBinder downLoadBinder=new DownLoadBinder();
        /**
    	 * 回调
    	 */
    	private Callback callback;
    	/**
    	 * Timer实时更新数据的
    	 */
    	private Timer mTimer=new Timer();
    	/**
    	 * 
    	 */
    	private int num;
    	
    	@Override
    	public IBinder onBind(Intent intent) {
    		// TODO Auto-generated method stub
    		System.out.println("=====onBind=====");
    		return downLoadBinder;
    	}
    
    	/**
    	 * 内部类继承Binder
    	 * @author lenovo
    	 *
    	 */
    	public class DownLoadBinder extends Binder{
    		/**
    		 * 声明方法返回值是MyService本身
    		 * @return
    		 */
    		public MyService getService() {
    			return MyService.this;
    		}
    	}
        /**
         * 服务创建的时候调用
         */
    	@Override
    	public void onCreate() {
    		// TODO Auto-generated method stub
    		super.onCreate();
    		/*
    		 * 执行Timer 2000毫秒后执行,5000毫秒执行一次
    		 */
    		mTimer.schedule(task, 0, 1000);
    	}
    	
    	/**
    	 * 提供接口回调方法
    	 * @param callback
    	 */
    	public void setCallback(Callback callback) {
    		this.callback = callback;
    	}
    	
    	/**
    	 * 
    	 */
    	TimerTask task = new TimerTask(){
    
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			num++;
    			if(callback!=null){
    				/*
    				 * 得到最新数据
    				 */
    				callback.getNum(num);
    			}
    			
    		}
    		
    	};
    	
    	
    	/**
    	 * 回调接口
    	 * 
    	 * @author lenovo
    	 *
    	 */
    	public static interface Callback {
    		/**
    		 * 得到实时更新的数据
    		 * 
    		 * @return
    		 */
    		void getNum(int num);
    	}
        /**
         * 服务销毁的时候调用
         */
    	@Override
    	public void onDestroy() {
    		// TODO Auto-generated method stub
    		System.out.println("=========onDestroy======");
    		/**
    		 * 停止Timer
    		 */
    		mTimer.cancel();
    		super.onDestroy();
    	}
    }
    

      MainActivity代码:

    package com.example.myservicedemo.ui;
    
    import com.example.myservicedemo.R;
    import com.example.myservicedemo.service.MyService;
    import com.example.myservicedemo.service.MyService.Callback;
    import com.example.myservicedemo.service.MyService.DownLoadBinder;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    public class MainActivity extends Activity implements OnClickListener {
        private MyService.DownLoadBinder downLoadBinder;
       // private MyService myService;  //我们自己的service  
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		Button btn_start = (Button) findViewById(R.id.btn_start);
    		Button btn_stop = (Button) findViewById(R.id.btn_stop);
    		Button btn_bind = (Button) findViewById(R.id.btn_bind);
    		Button btn_unbind = (Button) findViewById(R.id.btn_unbind);
    		btn_start.setOnClickListener(this);
    		btn_stop.setOnClickListener(this);
    		btn_bind.setOnClickListener(this);
    		btn_unbind.setOnClickListener(this);
    	}
    
    	@Override
    	public void onClick(View v) {
    		// TODO Auto-generated method stub
    		int id = v.getId();
    		switch (id) {
    		/*
    		 * 开启服务点击事件
    		 */
    		case R.id.btn_start:
    			Intent startIntent = new Intent(this, MyService.class);
    			startService(startIntent);
    			break;
    		/*
    		 * 停止服务点击事件
    		 */
    		case R.id.btn_stop:
    			Intent stopIntent = new Intent(this, MyService.class);
    			stopService(stopIntent);
    			break;
    		/*
    		 * 绑定服务点击事件
    		 */
    		case R.id.btn_bind:
    			Intent bindIntent = new Intent(this, MyService.class);
    			bindService(bindIntent, connection, BIND_AUTO_CREATE);
    			break;
    		/*
    		 * 解除绑定服务点击事件
    		 */
    		case R.id.btn_unbind:
                unbindService(connection);
    			break;
    
    		default:
    			break;
    		}
    	}
    	private ServiceConnection connection=new ServiceConnection() {
    		/**
    		 * 服务解除绑定时候调用
    		 */
    		@Override
    		public void onServiceDisconnected(ComponentName name) {
    			// TODO Auto-generated method stub
    			
    		}
    		/**
    		 * 绑定服务的时候调用
    		 */
    		@Override
    		public void onServiceConnected(ComponentName name, IBinder service) {
    			// TODO Auto-generated method stub
    			downLoadBinder = (DownLoadBinder) service;
    			MyService service2 = downLoadBinder.getService();
    			/**
    			 * 实现回调,得到实时刷新的数据
    			 */
    			service2.setCallback(new Callback() {
    				
    				@Override
    				public void getNum(int num) {
    					// TODO Auto-generated method stub
    					System.out.println("====num===="+num);
    				}
    			});
    		}
    	};
    
    }
    

      运行后的结果应该输出如图就对了(输出随service中num的数量而更新):

        

       期间遇到的问题:

       bindService后无效,MyService类中的onBind()方法没有被调用

       解决:这种情况下你的Activity应该是继承了TabBarActivity,绑定服务的时候调用写这种形式:

       this.getApplicationContext().bindService(intent, mConnection, BIND_AUTO_CREATE);

       最近几天用到,总结一下,希望可以为大家带来帮助,有错误还请大神指正。

     

     

     

  • 相关阅读:
    vue的echart基本使用
    vue和angular中moment.js格式化时间插件
    vue-element的上传图片
    vue小问题-验证规则的坑
    前端请求的接口来自不同的服务器处理
    vue报错:Invalid prop: type check failed for prop "index". Expected String with value
    vue注册页面表单元素
    项目的上传 /码云(git)
    前端工程化-模块化
    fs && path.join()
  • 原文地址:https://www.cnblogs.com/yunfang/p/6258053.html
Copyright © 2011-2022 走看看