一、Service与Activity之间通过IBinder对象进行通信
(1):在Service中必须要实现一个onBind(Intent intent)方法;
(2):在Service中需要自定义一个继承Bindler的类;在这个这个类中的一切 将会被传递到Activity中
也就是说 其实 Activity与Service之间 通信靠的是onBind(0方法返回的那个IBinder对象,也就是上面那个对象
(3)在Activity中需要实现一个ServiceConnection对象,该对象必须实现两个方法:onServiceConnected,onServiceDisconnected.
(4)在onServiceConnected()方法中获取在Service中创建的Binder对象,因为在Service中的OnBind()方法返回的是
IBinder对象,所有也就要得到该对象,并通过该对象,来对Service中的Binder对象中的数据进行操作,从而达到了通信的目的。
(5)注意使用将Service和Activityvban绑定的方法来进行通信那么需要再Acticity中使用
当然上述只是使用了Intent和Activity通过广播进行数据的传输,当然也可以使用Service和
bindService()启动的时候里面的参数就是:
第一个是一个从Activity跳转到Serviced的Intent (Intent intent=new Intent(this,myService.class)),
第二个是:一个serviceConnection对象,这个对象必须实现两个方法
第三个参数一般设置为:Service.BIND_AUTO_CREATE就可以了
在Service中的代码:
public class
BindService extends Service
{
private int count;
private boolean quit;
// 定义onBinder方法所返回的对象
private
MyBinder binder = new MyBinder();
// 通过继承Binder来实现IBinder类
public class MyBinder extends Binder // ①
{
public int getCount()
{
// 获取Service的运行状态:count
return count;
}
}
// 必须实现的方法,绑定该Service时回调该方法
@Override
public IBinder onBind(Intent intent)
{
System.out.println("Service is Binded");
// 返回IBinder对象
return binder;
}
// Service被创建时回调该方法
@Override
public void onCreate()
{
super.onCreate();
System.out.println("Service is Created");
// 启动一条线程,动态地修改count状态值
new Thread()
{
@Override
public void run()
{
while (!quit)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
count++;
}
}
}.start();
}
// Service被断开连接时回调该方法
@Override
public boolean onUnbind(Intent intent)
{
System.out.println("Service is Unbinded");
return true;
}
// Service被关闭之前回调该方法
@Override
public void onDestroy()
{
super.onDestroy();
this.quit = true;
System.out.println("Service is Destroyed");
}
}
|
在Activity中的代码:
public class MainActivity extends Activity
{
Button bind, unbind, getServiceStatus;
// 保持所启动的Service的IBinder对象
BindService.MyBinder binder;
// 定义一个ServiceConnection对象
private ServiceConnection conn = new ServiceConnection()
{
// 当该Activity与Service连接成功时回调该方法
@Override
public void onServiceConnected(ComponentName name
, IBinder service)
{
System.out.println("--Service Connected--");
// 获取Service的onBind方法所返回的MyBinder对象
binder = (BindService.MyBinder) service; // ①
}
// 当该Activity与Service断开连接时回调该方法
@Override
public void onServiceDisconnected(ComponentName name)
{
System.out.println("--Service Disconnected--");
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取程序界面中的start、stop、getServiceStatus按钮
bind = (Button) findViewById(R.id.bind);
unbind = (Button) findViewById(R.id.unbind);
getServiceStatus = (Button) findViewById(R.id.getServiceStatus);
// 创建启动Service的Intent
final
Intent intent = new Intent(this, BindService.class);
bind.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View source)
{
// 绑定指定Service
bindService(intent, conn, Service.BIND_AUTO_CREATE);
}
});
unbind.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View source)
{
// 解除绑定Service
unbindService(conn);
}
});
getServiceStatus.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View source)
{
// 获取、并显示Service的count值
Toast.makeText(MainActivity.this,
"Service的count值为:" +
binder.getCount(),
Toast.LENGTH_SHORT).show(); // ②
}
});
}
}
|
其实一般当Acticity和Service进行通信的时候,每当activity通过intent启动一个Service的时候,
在Service中的onStartCommand()方法中最好是开启一个线程进行操作。也就是说Service子类的标准格式应该是:
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 开始执行后台任务
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
public IBinder onBind(Intent intent) {
MyBinder mBinder = new MyBinder();
return mBinder;
}
class MyBinder extends Binder {
public void startDownload() {
new Thread(new Runnable() {
@Override
public void run() {
// 执行具体的任务
}
}).start();
}
}
|
二、使用广播通信的方式将Service或者IntentService与Activity进行联系
(在这里我只是编写了在Activity中写一个广播类,来实现从IntentService传递数据到Activity当然也可以在IntentService中写一个广播子类并实现onReceive()方法,来接受Activity传递过来的数据)
(1):使用广播通信的时候,要在Activity中,创建一个 BroadcastReceiver 子类处理收到的广播内容
(2):当然要也肯定要再Activity中注册Action
(3):因为在activity中接受内容的话,那么就必须要在IntentService中通过Intent中来发送广播
(4):加入发送的数据比较简单,可以直接通过Intent的Bundle来传递数据,也就是putExtral(),但是要是发送的数据比较
多的话,或者说是可序列话的话,那么就必须使用Parcelable 接口或者使用Serializable接口来实现。传递数据的功能
关于如何传递数据的话,看自己写的两者的差别和如何使用Bundle传递数据。(Parcelable 较为复杂但是建议使用 )
在此处使用Parcelable
传递数据
实现Parcelable接口 假设我们下载任务完成后得到的是如下Item类的一组对象,那么我们将要怎么样将其传递给广播接收器呢?
首先,必须要实现Item的序列化,序列化是通过实现Parcelable接口而实现的,这里我们将上面的类改造为ItemParcelable类,并实现Parcelable接口:
首先重写
writeToParcel
方法,将你的对象(
ItemParcelable
)序列化为一个
Parcel
对象,即:将类的数据写入外部提供的
Parcel
中,打包需要传递的数据到
Parcel
容器保存,以便从
Parcel
容器获取数据。
接下来,重写
describeContents
方法,内容接口描述,默认返回0就可以。
最后实例化静态内部对象
CREATOR
实现
Parcelable.Creator publicstatic final Parcelable.Creator CREATOR
接口。注意,其中
public static final
一个都不能少,内部对象
CREATOR
的名称也不能改变,必须全部大写。
需重写本接口中的两个方法:
createFromParcel(Parcelin)
实现从
Parcel
容器中读取传递数据值,封装成
Parcelable
对象返回逻辑层,
newArray(int size)
创建一个类型为
T
,长度为
size
的数组,仅一句话即可(
return new T[size]
),供外部类反序列化本类数组使用,这里的T就是
ItemParcelable
。还需要注意的是
writeToParcel
和
createFromParcel
方法中序列化的顺序必须相同。
最后通过ItemParcelable传递数据
接受数据:
|
Activity通过广播进行数据的传输