Android之 Activity间通信总结

来源:互联网 发布:东莞人工智能公司 编辑:程序博客网 时间:2024/06/06 03:20

在Android中,Activity作为界面显示。google并不推荐在Activity中做耗时操作,如果Activity操作耗时超过5s时,会提示是否等待对话框。
一般耗时操作会在Service中处理,Service主要负责长期在后台运行。
自从google推出Fragment以来,中文翻译为碎片,使用的越来越广泛。在同一个Activity界面会插入几个Fragment,用来显示不同的功能界面。
在我们的实际项目中,总是会用到Activity、Service及Fragment。Activity与它们之间是怎么进行通信,完成UI更新。接下来,我们一一道来。
一、Activity与Activity之间的通信
当A Activity打开B Activity时,大家都知道通过调用startActivity(intent),由A启动B。如果希望A传递信息给B,只需如果在intent携带即可。如果携带的信息中包含自定义类,需要将类序列化,实现接口Parcelable或者Serializable。
A启动B:

<span style="font-size:14px;">        Intent intent = new Intent(this, AtySecond_.class);        // 设置启动Activity时携带的参数信息 的Intent        Bundle bundle = new Bundle();        bundle.putString("AtySecond", "AtyCommActivity传递的消息,不需要返回值");        intent.putExtras(bundle);        startActivity(intent);</span>
B中获取A传递的信息:

<span style="font-size:14px;">// 获取出入的Budle        Intent intent = getIntent();        Bundle bundle = intent.getExtras();        msg = bundle.getString("AtySecond", "");</span>
这种方法,大家都很熟悉,如果在关闭B Activity时,A希望从B中获取操作结果,该如何做呢?在A启动B时只能使用另外一种启动方法——startActivityForResult。startActivityForResult(Intent intent,int requestCode,)的主要作用就是它可以回传数据,其中参数intent,就是启动Activity的意图,参数requestCode是启动Activity,获取返回值的请求码,在onActivityResult作返回值处理时使用,以便分别是哪一个返回值请求。
1.A在启动B时,再使用startActivity()而是使用startActivityForResult

<span style="font-size:14px;">// 设置启动Activity时携带的参数信息 的Intent        Intent intent = new Intent(this, AtySecond_.class);        Bundle bundle = new Bundle();        bundle.putString("AtySecond", "AtyCommActivity传递的消息,需要返回值");        intent.putExtras(bundle);        // 参数 REQUEST_ONE :请求依据,作为在onActivityResult做处理时识别码        startActivityForResult(intent, REQUEST_ONE);</span>
2.重写onActivityResult,来获取从BActivity返回的数据
<span style="font-size:14px;">    protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);Log.i("123", "requestCode: " + requestCode);if (requestCode == REQUEST_ONE) {if (null != data) { // data为AtySecond返回的Intent// msg即为回传的值String msg = data.getStringExtra("AtySecond");tv_msg.setText("返回的信息:" + msg);}}}</span>
3.在B Activity finish()之前,将传回数据时,使用setResult方法

<span style="font-size:14px;">    // 携带返回值得Intent        Intent intent = new Intent();        intent.putExtra("AtySecond", "AtySecond返回值");        setResult(RESULT_OK, intent);        //此处一定要调用finish()方法        this.finish();</span>
setResult方法什么时候调用。刚开始使用setResult,Result并 没有返回回去,获取的Intent是null.查阅了半天资料,才发现只有当前Activity被finish,结果才会被发送给parent的onActivityResult去处理。也就是说,setResult方法要在finish()之前调用,才能将数据返回。
按BACK键从一个Activity退出来的,一按BACK,android就会自动调用Activity的finish()方法,然后设置resultCode为RESULT_CANCELED,同时设置intent为NULL并没有调用setResult()也就不会返回任何数据了.解决方法就是在Activity里面捕获按BACK的事件,捕获到之后先setResult,然后自己来调用finish().

<span style="font-size:14px;">    public void onBackPressed() {        // 携带返回值得Intent        Intent intent = new Intent();        intent.putExtra("AtySecond", "AtySecond返回值");        setResult(RESULT_OK, intent);        //此处一定要调用finish()方法        super.onBackPressed();    }</span>
二、Activity与Fragment之间的通信
使用Fragment可以完成在同一Activity完成不同界面的转换。在界面转换时,Activity与Fragment之间的通信成了重中之重。Activity与Frament之间有以下通信方式:
1、如果Activity中有Fragment实例,可以通过直接调用Fragment中的public方法
在Activity中

<span style="font-size:14px;">FrmFirst mFrmFirst = new FrmFirst();tv_frmShow.setText("Frm的信息:" + mFrmFirst.getInfo());</span>
在Fragment中
<span style="font-size:14px;">public class FrmFirst extends Fragment {TextView tv_xl;public FrmFirst() {// Required empty public constructor}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.frm_first, container, false);tv_xl = (TextView) view.findViewById(R.id.tv_xl);return view;}// 权限修饰为public,以供外部调用public String getInfo() {return tv_xl.getText().toString();}}</span>
2、如果Activity中没有Fragment实例,每个Fragment都有唯一的TAG或者ID,可以通过getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实例,然后进行1中的操作;
// 获取Fragment ,调用Fragment中的Public方法,与Fragment通信Fragment mFrm = mFManager.findFragmentByTag("fragmentTag");if (mFrm instanceof FrmFirst) {FrmFirst f = (FrmFirst) mFrm;tv_frmShow.setText("Frm的信息:" + f.getInfo());} else {tv_frmShow.setText("Frm的信息:");}
3.在Fragment中获取Actvity实例,然后进行操作
在Fragment中
AtyFrms mAtyFrms;
在onAttach中获取Activity实例

<span style="font-size:14px;">// 绑定当前Activity    // 可以调用当前Activity中的public 方法    public void onAttach(Activity activity) {        super.onAttach(activity);        mAtyFrms = (AtyFrms) activity;    }// 通过getActivity获取Activity实例    public void onResume() {        super.onResume();        // 通过getActivity方法获取当前Activity        // 调用Activity中的public方法        AtyFrms atyFrms = (AtyFrms) getActivity();// setInfo为Activity的public方法        atyFrms.setInfo("当前界面为QQ");    }</span>
4.如果Activity向Fragment传递参数,在Activity通过setArguments传递,在Fragment通过getArguments获取
官方文档推荐,在每个Frament里必须有一个空的构造函数,以便其可以实例化,但是不推荐含有带参的构造方法,用来传递参数,因为这些构造函数,并不能在调用Fragment时,将Fragment重新实例化,如果需要传递参数,可以通过setArguments传递,在Fragment通过getArguments。
在Activity中
<span style="font-size:14px;">Bundle bundle = new Bundle();bundle.putString("FrmFoure", "AtyFrms打开FrmFoure");if (null == mFrmFoure) {mFrmFoure = new FrmFoure_();}mFrmFoure.setArguments(bundle);mFTransaction.replace(R.id.fl_content, mFrmFoure, "fragmentTag");mFTransaction.commit();在Fragment中// 获取传递的参数 BundleBundle bundle = getArguments();String info = bundle.getString("FrmFoure", "未传递参数信息");</span>
info即为Activity传递的参数
5.通过回调听信。在Activity中实现接口,在Fragment中回调接口
在Activity中

<span style="font-size:14px;">public class AtyFrms extends AppCompatActivity implements FrmThree.FrmChanedListener{***... public void setCururent(String str) {tv_frmShow.setText("Frm的信息:" + str);}***...}</span>
在Fragment中,定义接口
<span style="font-size:14px;">    // 定义接口    //  持有它的Activity必须实现这个回调方法    public interface FrmChanedListener {        void setCururent(String str);    }    //获取接口实例    FrmChanedListener mListener;    public void onAttach(Activity activity) {        super.onAttach(activity);        // 如果Activity没有实现这个接口,那么Fragment会抛出ClassCastException异常        // 如果成功,那么mListener成员就会拥有Activity实现的FrmChanedListener对象的引用,        // 以便Fragment FrmThree能够通过FrmChanedListener接口定义的回调方法和Activity共享事件        try {            mListener = (FrmChanedListener) activity;        } catch (ClassCastException e) {            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");        }    }    //回调接口    public void onResume() {        super.onResume();        // Fragment FrmThree能够通过FrmChanedListener接口定义的回调方法和Activity共享事件        mListener.setCururent("微信页面使用回调通信");    }</span>
6.通过广播通信。在Activity中注册广播并在onReive中对相应广播处理,在Fragment中发送广播。
广播实例见Service通信。
三、Activity与Service之间通信
Activity启动服务Service时,通过Intent启动。若Activity向Service传递参数可以通过Intent传递。而当Service某些操作更新UI时,我们该如何操作呢?启动Service又有startService和bindService两种方式,不同的启动方式又该如何通信?以下有几种通信方式:
1.在Activity中,通过bindService方式启动Service,获取Service实例,然后进行操作
在Activity中
<span style="font-size:14px;">ServiceConnection conn = new ServiceConnection() {            @Override            public void onServiceConnected(ComponentName name, IBinder service) {                MyService.MyBinder mMyBinder = (MyService.MyBinder) service;// 获取Service对象                mMyService =  mMyBinder.getService();            }}// 通过bindService绑定ServiceIntent intentBind = new Intent(this, MyService_.class);        bindService(intentBind, conn, BIND_AUTO_CREATE);</span>
在Service中
<span style="font-size:14px;">public IBinder onBind(Intent intent) {        return new MyBinder();    }// 创建内部类MyBinder继承于Binder,以便获取Service实例    public class MyBinder extends Binder {        public MyService getService() {            return MyService.this;        }    }</span>
2.通过回调的方式。如方法1,已经获取Service实例。在Actvity中实现接口,在Service中,设置接口实例
并调用。
在Activity中
<span style="font-size:14px;">ServiceConnection conn = new ServiceConnection() {            @Override            public void onServiceConnected(ComponentName name, IBinder service) {                MyService.MyBinder mMyBinder = (MyService.MyBinder) service;                mMyService =  mMyBinder.getService();// 通过匿名内部类实例化接口                mMyService.setListener(new MyService.onProgressChangedListener() {                    @Override                    public void setProgress(int progress) {                                            }                });            }</span>
在Service中
<span style="font-size:14px;">public class MyService extends Service {***...onProgressChangedListener mListener;// 定义接口public interface onProgressChangedListener {void setProgress(int progress);}***...// 获取接口实例public void setListener(onProgressChangedListener listener) {this.mListener = listener;}***...}</span>
3.通过广播BroadcastReiceive通信。
通过starService启动Service时,并不能够获取Service,意味着方式1和2,都不可再实现。我们可以这样做,在Service需要更新UI时,发送一条广播。在Activity中注册广播并接受广播处理。此种方式,只需要发送广播,并不需要获取Service实例,那么问题迎刃而解。
在Activity中
<span style="font-size:14px;">public class AtyService extends AppCompatActivity {***...MyBroadcastReceive mReiver;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_aty_service);// 动态注册广播mReiver = new MyBroadcastReceive();IntentFilter filter = new IntentFilter("***");registerReceiver(mReiver, filter);}protected void onDestroy() {super.onDestroy();// 在Activity销毁时,将广播注销unregisterReceiver(mReiver);}***...public class MyBroadcastReceive extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {***}}***...}</span>
在Service中
<span style="font-size:14px;"><span style="white-space:pre"></span>// 需要更新UI时,发送一条广播Intent intentBroad = new Intent("***");intentBroad.putExtra("PROGRESS", pro);sendBroadcast(intentBroad);</span>
在stopService或unBindService时,需要调用unregisterReceiver,将广播注销掉。

一点心得,大家分享!
集思广益、坚持不懈的总结,总会进步!

参考资料:
1.Android Developers
2.Android 中文API
3.http://www.cnblogs.com/lijunamneg/archive/2013/02/05/2892616.html
4.http://blog.csdn.net/lmj623565791/article/details/37970961
5.http://segmentfault.com/a/1190000002400391

6.http://blog.csdn.net/sdlgxxy/article/details/6226127


源码下载地址:点击打开链接


0 0
原创粉丝点击