问题场景:
一个Activity,一个IntentService。从Activity中获得一个数据,将这个数据通过Intent发送到IntentService中,在IntentService中进行一个长时间的运算,将计算结果返回到Activity中,并在Activity的一个TextView中进行显示。
例如,在Activity中输入一个数字10,在IntentService中计算第十个质数是什么,然后将结果返回给Activity并在Activity的一个TextView中显示。
分析:
利用PendingIntent作为Activity和IntentService之间数据传递的载体。在Activity启动IntentService的Intent对象中,放入一个PendingIntent(PendingIntent实现了Parcelable接口,所以可以将PendingIntent作为Intent的Extra放入)。然后IntentService在计算完毕后,将计算结果放入一个Intent中,并将这个Intent放入前面那个PendingIntent中,调用PendingIntent的send方法。此时Activity的onActivityResult方法会被回调,通过获得方法参数中的Intent类型参数data,将里面的计算结果取出放入TextView显示即可。
代码实现:
Activity源文件(使用了xUtils的注入机制):
未来,把IntentService的运行结果封装为自定义事件对象的myMesssage属性即可。
可以看到,这里完全不需要PendingIntent,因此也不需要onActivityResult方法了。此时数据的传递完全依靠事件机制来完成
可以看到,MyIntentService的代码更加的简洁,获得Activity传递过来的用户输入内容,将计算结果封装到事件对象中,并且发布事件即可。
一个Activity,一个IntentService。从Activity中获得一个数据,将这个数据通过Intent发送到IntentService中,在IntentService中进行一个长时间的运算,将计算结果返回到Activity中,并在Activity的一个TextView中进行显示。
例如,在Activity中输入一个数字10,在IntentService中计算第十个质数是什么,然后将结果返回给Activity并在Activity的一个TextView中显示。
分析:
利用PendingIntent作为Activity和IntentService之间数据传递的载体。在Activity启动IntentService的Intent对象中,放入一个PendingIntent(PendingIntent实现了Parcelable接口,所以可以将PendingIntent作为Intent的Extra放入)。然后IntentService在计算完毕后,将计算结果放入一个Intent中,并将这个Intent放入前面那个PendingIntent中,调用PendingIntent的send方法。此时Activity的onActivityResult方法会被回调,通过获得方法参数中的Intent类型参数data,将里面的计算结果取出放入TextView显示即可。
代码实现:
Activity的布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="请输入一个数字" />
<EditText
android:id="@+id/et_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_alignParentRight="true"
android:layout_below="@+id/textView1"
android:layout_marginTop="27dp"
android:hint="输入一个整数..."
android:ems="10" >
<requestFocus />
</EditText>
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/btn_calculate"
android:layout_alignParentBottom="true"
android:layout_alignRight="@+id/et_number"
android:layout_marginBottom="146dp"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="@+id/btn_calculate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/et_number"
android:layout_alignRight="@+id/et_number"
android:layout_below="@+id/et_number"
android:layout_marginTop="63dp"
android:text="Button" />
</RelativeLayout>
Activity源文件(使用了xUtils的注入机制):
public class MainActivity extends Activity {
/**
* 利用xUtils的注入机制为属性赋值
*/
@ViewInject(R.id.et_number)
private EditText etNumber;
@ViewInject(R.id.btn_calculate)
private Button btnCalculate;
@ViewInject(R.id.tv_result)
private TextView tvResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//使用xUtils的ViewUtils实现注入
ViewUtils.inject(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@OnClick({R.id.btn_calculate})
public void doClick(View v){
//获得用户输入的数字,用来计算第n个质数是什么
String value=etNumber.getText().toString();
//创建一个Intent对象,来启动IntentServic,在后台完成计算
Intent intent=new Intent(this,MyIntentService.class);
//将用户输入的数字传入Intent对象
intent.putExtra(MyIntentService.PARAM, Integer.parseInt(value));
//创建一个PendingIntent对象,未来在IntentService完成计算后,要利用该PendingIntent将结果送回
PendingIntent pi=createPendingResult(MyIntentService.RESULT_CODE, new Intent(), 0);
//PendingIntent实现了Parcelable接口
intent.putExtra(MyIntentService.PENDING_RESULT, pi);
//启动IntentService
startService(intent);
}
/**
* 当IntentService利用PendingIntent返回结果的时候,该方法会被调用
* 返回的PendingIntent中会包含一个添加了运算结果的intent对象
* 因此从PendingIntent中的Intent中去获取计算结果
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//Intent类型的参数data是包裹在PendingIntent中的
if(resultCode==MyIntentService.RESULT_CODE){
String result=data.getStringExtra(MyIntentService.RESULT);
tvResult.setText(result);
}
super.onActivityResult(requestCode, resultCode, data);
}
}
MyIntentService的源代码:
public class MyIntentService extends IntentService {
public static final String PARAM="prime_to_find";
public static final String PENDING_RESULT="pending_result";
public static final String RESULT="result";
public static final int RESULT_CODE="nth_prime".hashCode();
public static final int INVALID="invalid".hashCode();
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
try{
//从来自Activity的Intent中获得用户输入的数值
int num=intent.getIntExtra(PARAM, -1);
//从来自Activity的Intent中获得PendingIntent,计算完毕后要使用它返回结果到Activity
PendingIntent reply=intent.getParcelableExtra(PENDING_RESULT);
if(num<2) reply.send(INVALID);
BigInteger prime=getPrime(num);
//这个Intent用来保存结果,并将该Intent放入PendingIntent中返回到Activity中
//未来Activity的onActivityResult方法的第三个参数就是该Intent对象
Intent resultIntent = new Intent();
resultIntent.putExtra(RESULT, prime.toString());
reply.send(this, RESULT_CODE, resultIntent);
}catch(Exception e){
e.printStackTrace();
}
}
private BigInteger getPrime(int num) {
BigInteger b=new BigInteger("2");
for(int n=0;n<num;n++){
b=b.nextProbablePrime();
}
return b;
}
}
现在使用EventBus进行改写。使用EventBus的时候需要有这样几个元素:自定义的事件对象,事件的发布者,事件的接收者(订阅者)。这样,当有事件发生时,接收者(订阅者)就可以接收到事件对象。接下来接收者利用事件对象提供的方法来操作事件对象即可。对于接收者来说,需要写两个内容:注册和接收事件对象。对于发布者来说,直接发布事件对象即可。
首先写一个自定义的事件类-MyEvent
public class MyEvent {
private String myMesssage;
public MyEvent(String myMesssage) {
super();
this.myMesssage = myMesssage;
}
public String getMyMesssage() {
return myMesssage;
}
public void setMyMesssage(String myMesssage) {
this.myMesssage = myMesssage;
}
}
未来,把IntentService的运行结果封装为自定义事件对象的myMesssage属性即可。
使用了EventBus的Activity源代码:
public class MainActivity extends Activity {
/**
* 利用xUtils的注入机制为属性赋值
*/
@ViewInject(R.id.et_number)
private EditText etNumber;
@ViewInject(R.id.btn_calculate)
private Button btnCalculate;
@ViewInject(R.id.tv_result)
private TextView tvResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//使用xUtils的ViewUtils实现注入
ViewUtils.inject(this);
//将该Activity注册为事件的接收者
EventBus.getDefault().register(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@OnClick({R.id.btn_calculate})
public void doClick(View v){
//获得用户输入的数字,用来计算第n个质数是什么
String value=etNumber.getText().toString();
//创建一个Intent对象,来启动IntentServic,在后台完成计算
Intent intent=new Intent(this,MyIntentService.class);
//将用户输入的数字传入Intent对象
intent.putExtra(MyIntentService.PARAM, Integer.parseInt(value));
//启动IntentService
startService(intent);
}
/**
* 必须写这个方法作为接收者的一部分。这样当有发布者发布事件对象的时候,该方法会被回调
* @param event 接收发布者发布的事件对象
*/
public void onEventMainThread(MyEvent event){
String msg=event.getMyMesssage();
tvResult.setText(msg);
}
/**
* 在销毁Activity的时候,必须从EventBus中注销掉该接收者
*/
@Override
protected void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
}
可以看到,这里完全不需要PendingIntent,因此也不需要onActivityResult方法了。此时数据的传递完全依靠事件机制来完成
MyIntentService的源代码:
public class MyIntentService extends IntentService {
public static final String PARAM="prime_to_find";
public static final String PENDING_RESULT="pending_result";
public static final String RESULT="result";
public static final int RESULT_CODE="nth_prime".hashCode();
public static final int INVALID="invalid".hashCode();
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
try{
//从来自Activity的Intent中获得用户输入的数值
int num=intent.getIntExtra(PARAM, -1);
BigInteger prime=getPrime(num);
//IntentService是事件对象的发布者,将计算结果封装到事件对象中
EventBus.getDefault().post(new MyEvent(prime.toString()));
}catch(Exception e){
e.printStackTrace();
}
}
private BigInteger getPrime(int num) {
BigInteger b=new BigInteger("2");
for(int n=0;n<num;n++){
b=b.nextProbablePrime();
}
return b;
}
}
可以看到,MyIntentService的代码更加的简洁,获得Activity传递过来的用户输入内容,将计算结果封装到事件对象中,并且发布事件即可。