Android四大组件的简介

来源:互联网 发布:尼康50mm 1.8g 知乎 编辑:程序博客网 时间:2024/06/05 14:53

Android的四大组件:Activity、Service、ContentProvider、BroadcastReceiver。

一、Activity

(一)、使用Bundle在Activity之间交换数据

在Activity之间交换数据,主要是通过Intent来完成。Intent提供了两类方法来“携带”额外的数据:

1、“携带”Bundle数据

putExtras(Bundle data)和Bundle getExtras();

2、“携带”基本数据类型、String、Serializable

putExtras(String name,Xxx value):向Intent中以key-value对形式存入数据;

getXxxExtras(String name):从Intent中按key取出指定类型数据;

其中Bundle中可以“携带”通过以下方法取出数据:

getXxx(String key)和getSerializable(String key,Serializable data);

(二)、启动其他Activity并返回结果

为了获取被启动的Activity返回的结果,需要从两方面入手:

当前Activity需要重写onActivityResult,当被启动Activity返回结果时,该方法被触发;

被启动的Activity需要调用setResult方法设置处理结果;

示例:

当前Activity方法:

    //点击jump按钮跳转到被调用的Activity    public void jump(View view){    Intent intent=new Intent(TestActivity.this,SecondActivity.class);    startActivityForResult(intent, 0);//0表示requestCode    }    //回调方法,获取指定Activity返回的结果    public void onActivityResult(int requestCode,int resultCode,Intent intent){    //当请求码和返回码都是0时,处理特定的结果    //通过请求码和返回码,可以处理不同的请求和返回结果    if(requestCode==0 && resultCode==0){    String str=intent.getStringExtra("result");    show.setText(str);    }    }
被调用Activity方法:

String str="第二个Activity的返回值";//获取启动该Activity的IntentIntent intent=getIntent();intent.putExtra("result", str);//设置结果码,并设置退回的ActivitySecondActivity.this.setResult(0, intent);SecondActivity.this.finish();
(疑问:这个和直接使用Intent启动Activity貌似没有什么差别啊。。。)
(三)、Activity的生命周期和加载模式

Activity在Android应用中是以Activity栈的形式管理的,当前活动的Activity位于栈顶。

Activity的生命周期完全可以用一张图解释:


比较常见的场景:

1、覆写onCreate()方法,该方法用于初始化;

2、覆写onPause()方法,当用于使用该应用时,电话打进来了,可以在该方法中保存当前应用的数据信息;

3、覆写onResume()方法,当用户挂掉电话后,再次回到应用状态,onResume()方法被回调,可以通过重写该方法恢复数据信息;

(四)、Activity的4种加载模式

配置Activity时可以通过android:lanuchMode属性,配置该Activity的加载模式:

1、standard:标准模式,默认的加载模式;

2、singleTop:Task顶单例模式,如果被启动Activity已位于Task栈顶,系统不会重新创建目标Activity实例,而是复用已有的Activity实例;

3、singleTask:Task内单例模式,在同一个Task内只有一个实例;

4、singleInstance:全局单例模式,系统无论从哪个Task启动目标Activity,都只会创建一个目标Activity实例,并使用一个新的Task栈来装载该Activity实例。采用singleInstance模式加载Activity所在的Task只包含该Activity;

Android以Task来管理多个Activity,先启动的Activity放在Task栈底,后启动的Activity放在Task栈顶。

Activity的加载模式,就负责管理实例化、加载Activity的方法,并可以控制Activity与Task之间的加载关系。

二、Fragment详解

(一)、Fragment概述及其设计哲学

Fragment的特征:

1、Fragment必须被“嵌入”Activity中使用。

2、在Activity运行过程中,可调用FragmentManager的add()、remove()、replace()方法动态的添加、删除和替换Fragment。

3、一个Activity可以同时组合多个Fragment;一个Fragment也可以被多个Activity复用。

4、Fragment可以响应自己的输入事件,并拥有自己的生命周期,但是Fragment的生命周期会受它所在的Activity的生命周期控制。

(二)、创建Fragment

创建Fragment通常需要实现如下三个方法:

onCreate():创建Fragment对象回调方法,初始化操作;

onCreateView():Fragment绘制界面组件回调方法,返回该Fragment所显示的View;

onPause():用户离开Fragment回调方法;

(三)、Fragment与Activity通信

将Fragment添加到Activity中有两种方式:

1、在布局文件中使用<fragment../>元素添加Fragment,<fragment.../>元素的android:name属性指定Fragment的实现类。

2、在Java代码中通过FragmentTransaction对象的add()方法来添加Fragment。

Activity与Fragment交互信息:

1、Fragment获取它所在Activity:调用Fragment的getActivity()方法即可返回它所在的Activity;

2、Activity获取它所包含的Fragment:调用Activity关联的FragmentManager的fiindFragmentById(int id)或者findFragmentByTag(String tag)方法即可获得指定的Fragment;

Fragment和Activity传递数据:

1、Activity向Fragment传递数据:在Activity中创建Bundle数据包,并调用Fragment的setArguments(Bundle bundle)方法即可将Bundle数据包传递给Fragment;

2、Fragment向Activity传递数据或者Activity需要在Fragment运行中进行实时通信:在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口,这样Fragment即可调用回调接口的方法将数据传递给Activity;

(四)、Fragment管理与Fragment事务

Activity管理Fragment主要通过FragmentManager,FragmentManager主要完成以下几方面的功能:

1、使用findFragmentById()或者findFragmentByTag()方法来获取指定Fragment;

2、调用popBackStack()方法将Fragment从后台栈中弹出;

3、调用addOnBackStackChangeListener()注册一个监听器,用于监听后台栈的变化;

4、调用beginTransaction()方法得到FragmentTransaction对象,该对象用于动态添加、删除、替换Fragment;

每个FragmentTransaction可以包含多个对Fragment修改,比如可以包含多个add、replace、remove操作,最后还调用commit()方法提交事务。

在调用commit()方法之前,开发者可以调用addToBackStack()将事务添加到back栈,该栈由Activity负责管理,允许用户按BACK键返回到前一个Fragment状态。

(五)、Fragment的生命周期


Activity和Fragment生命周期对比:


三、ContentProvider

(一)、数据共享标准:ContentProvider简介

ContentProvider是不同应用程序之间进行数据交换的标准API,ContentProvider以某种Uri的形式对外提供数据,允许其他应用访问或者修改数据;其他应用程序使用ContentResolver根据Uri去访问操作指定数据。

开发一个完整的ContentProvider的步骤:

1、自定义ContentProvider类,该类实现ContentProvider基类;

2、向Android注册ContentProvider,在注册时,需要为ContentProvider绑定一个Uri。

自定义ContentProvider,需要实现onCreate、insert、delete、query、update、getType方法。

Uri的范例:

content://org.carzyit.providers.dictprovider/words

可以分为如下三部分:

content:// Android的ContentProvider规定的;

org.cratyit.providers.dictprovider 这是ContentProvider的authority部分。系统通过该部分找到要操作哪个ContentProvider。访问指定的ContentProvider,这个部分是固定的;

words 资源部分(数据部分),当访问不同资源时,这个部分是动态变动的。

将一个字符串转化为Uri,可以使用:Uri uri=Uri.parse("content://org.crazyit.providers.dictprovider/word/2");

一个应用程序得到ContentResolver:Context.getContentResolver();

调用ContentResolver对象就可以调用其insert、query、delete、update等方法来操作数据了。

一般来说ContentProvider是单例模式,当多个应用程序通过ContentResolver来操作ContentProvider提供的数据时,ContentResolver调用的数据操作将会委托给同一个ContentProvider来处理。

(二)、开发ContentProvider

ContentProvider、ContentResolver、Uri的关系:


以插入操作为例:当A应用调用ContentResolver的insert()方法时,实际上相当于调用了该Uri对应的ContentProvider(该ContentProvider属于B应用)的insert()方法。

前面讲过,开发ContentProvider需要两步:

1、自定义一个ContentProvider子类,实现基类的query、insert、update、delete等方法;

2、在AndroidManifest.xml文件中注册该ContentProvider,指定android:authorities属性。

在AndroidManifest.xml中配置ContentProvider:

<provider android:name=".FirstProvider"android:authorities="org.crazyit.providers.firstprovider"android:exported="true"/>
配置ContentProvider时,指定的属性如下:

name:指定该ContentProvider的实现类的类名;

authorities:指定该ContentProvider对应的Uri;

exported:指定该ContentProvider是否允许其他应用调用。

(三)、操作系统的ContentProvider

使用ContentResolver调用系统的ContentProvider数据的步骤:

1、调用getContentResolver()方法获取ContentResolver对象;

2、根据需要调用ContentResolver的insert、delete、update、query方法操作数据即可。

《疯狂Android讲义》上提供了操作联系人、多媒体文件的实例。

(四)、监听ContentProvider的数据改变

监听程序中ContentProvider数据的改变,需要通过ContentResolver向指定Uri注册ContentObserver监听器,继承ContentObserver基类,并重写onChange(boolean selfChange)方法。

/*为指定Uri注册监听器uri:该监听器所监听的ContentProvider的UrinotifyForDescendents:监听的范围,如果为true,假如注册监听的uri为content://abc,那么Uri为content://abc/xyz等的数据改变也会触发监听器;如果为false,则注册监听uri为content://abc,就只监听content://abc;observer:监听器实例*/getContentResolver().registerContentObserver(Uri.parse("content://sms"),true,new SmsObserver(new Handler()));

四、Service

Service一旦启动起来之后,就完全具有自己的生命周期了。

(一)、Service简介

开发Service的步骤:

1、自定义Service的子类;

2、在AndroidManifest.xml文件中配置该Service。

Service和Activity都是Context派生的,所以都可以使用getResources(),getContentResolver()方法。

Android系统运行Service有两种方式:

1、通过Context的startService()方法,通过该方法启动Service,访问者和Service之间没有关联,即使访问者退出了,Service仍然可以运行。

2、通过Context的bindService()方法,通过该方法启动Service,访问者和Service绑定在了一起,访问者一旦退出,Service也会终止。

BindServiceActivity:

public class TestActivity extends Activity {Button bind;Intent intent;BS.MyBinder myBinder;private ServiceConnection conn=new ServiceConnection(){public void onServiceConnected(ComponentName name,IBinder service){System.out.println("ServiceConnection.onServiceConnected");myBinder=(MyBinder) service;}public void onServiceDisconnected(ComponentName name) {//非人为断开连接}};public void bindService(View view){/**bindService(Intent intent,ServiceConnection conn,int flag); * intent 要启动的Service * conn ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。 * 当访问者与Service之间成功连接时将回调该ServiceConnection对象的onServiceConnected(ComponentName name,IBinder service)方法; * 当Service所在的宿主进程由于异常中止或者其他原因终止,导致该Service与访问者之间断开连接回调该ServiceConnection对象的onServiceDisconnected(ConmonentName name)方法; * 当调用者主动通过unBindService()方法断开与Service连接时,onServiceDisconnected()方法不会回调。 * flag 0:当Service还未创建时不自动创建;Service.BIND_AUTO_CREATE:自动创建 */bindService(intent, conn, Service.BIND_AUTO_CREATE);}    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        bind=(Button) findViewById(R.id.start);        intent=new Intent();        intent.setAction("com.service.ts.service_intent");    }        public void showCount(View view){    System.out.println("count="+this.myBinder.getCount());    }    }
BindService:BS类

public class BS extends Service {private int count;private MyBinder myBinder=new MyBinder();public class MyBinder extends Binder{public int getCount(){return count;}}@Overridepublic IBinder onBind(Intent intent) {System.out.println("BS.onBind");return myBinder;}@Overridepublic void onCreate() {super.onCreate();System.out.println("TS.onCreate");new Thread(){public void run() {while(true){try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}count++;}}}.start();}}
IBinder相当于Service内部的钩子,通过在Activity调用由Service传递过来的IBinder,可以调用Service内部变量。


这和一下情形类似:

一个类实现另一个类的内部接口,另一个类就可以通过该内部接口调用这个类的内部变量。

Service的生命周期


service的生命周期还有一种特殊情况:


当Activity调用bindService()方法绑定一个已经启动的Service时,系统只是把Service内部的IBinder对象传给Activity,并不会把该Service生命周期完全绑定到该Activity,因而当Activity调用unBindService()方法取消与该Service的绑定时,也只是切断该Activity与Service之间的关联,并不能停止该Service组件。

使用IntentService

Service本身存在的不足:

1、Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中;

2、Service也不是专门一条新的线程,因此不应该在Service中直接处理耗时任务。

IntentService弥补了Service的不足,IntentService的特点:

1、IntentService使用队列来管理请求Intent;

2、IntentService为onBind、onStartCommand方法提供了默认的实现,开发者只需要实现onHandleIntent()方法,在该方法中实现业务逻辑,IntentService会创建单独的worker线程来处理onHandleIntent()方法。对于异步的startService请求,IntentService会依次处理对立中的Intent,创建的worker线程保证同一时刻只处理一个Intent;

3、当所有请求都处理完成后,IntentService会自动停止,无须开发者调用stopSelf()方法来停止该Service。

使用startService,IntentService的回调函数的过程:

1、onCreate

2、onStartCommand

3、onHandleIntent

4、onDestroy

使用BindService,IntentService的回调函数的过程:

1、onCreate

2、onBind

3、onDestroy

上面两种方式启动IntentService,都没有调用IntentService的构造方法。

配置一个Service的方法:

1、在AndroidManifest.xml文件中配置Service时,指定action:

        <service android:name="com.service.BS">            <intent-filter>                <action android:name="com.service.ts.service_intent"/>            </intent-filter>        </service>
2、如果只是配置Service,没有指定action:

<service android:name=".MyService" />
可以通过一下代码启动Service:

// 创建需要启动的Service的IntentIntent intent = new Intent(this, MyService.class);// 启动ServicestartService(intent);

(二)、跨进程调用Service(AIDL Service)

为了实现跨进程通信(IPC),Android提供了AIDL Service。
远程Service的onBind()方法只是将IBinder对象的代理传给客户端的ServiceConnection的onServiceConnected方法的第二个参数。
AIDL定义两个进程之间的通信接口,和Java语法存在以下几点差异:
1、AIDL定义接口的源代码必须以.aidl结尾;
2、AIDL接口中用到的数据类型,除了基本类型、String、List、Map、CharSequence之外,其他类型全部需要导包,即使在同一个包里。
客户端绑定远程Service和绑定本地的Service的步骤类似,区别是:
1、绑定本地Service,本地Service返回的IBinder实现类的对象;绑定远程Service,远程Service返回的IBinder接口和AIDL定义的接口(假设为ICat.aidl)的实现类的对象的代理,即返回的是一个代理,所以在客户端的ServiceConnection的方法onServiceConnected方法中,根据传入的IBinder参数,设置客户端:

//获取远程Service的onBind方法返回的对象的代理catService=ICat.Stub.asInterface(service);
2、注意:远程的AIDL定义的接口所在的包全路径(比如是org.sina.aidl.service.ICat.aidl)要和客户端的AIDL定义的接口所在的包全路径相同(即也要是org.sina.aidl.service.ICat.aidl)。

绑定远程Service,并传递domain类数据:

1、在远程和本地客户端都要在相同包路径下写domain类,比如domain类时Person类:

定义domain类的aidl

parcelable Person;
定义domain类的java

public class Person implements Parcelable {private Integer id;private String name;private String pass;//无参和有参构造方法//set和get方法//自动生成的hashCode、equals//覆写实现Parcelable需要实现的方法@Overridepublic int describeCoontents(){return 0;}//把Person对象写入Parcel@Overridepublic void writeToParcel(Parcel dest,int flags){dest.writeInt(id);dest.writeString(name);dest.writeString(pass);}//必须定义一个类型为Parcelable.Creator<Person>,名为CREATOR的//静态变量,该静态变量的值负责恢复从Parcel数据包中恢复Person类public static final Parcelable.Creator<Person> CREATOR=new Parcelable.Creator<Person>() {//从Parcel中读取数据,返回Person对象public Person createFromParcel(Parcel source) {return new Person(source.readInt(),source.readString(),source.readString());}public Person[] newArray(int size) {return new Person[size];}};}
2、定义作为内部钩子的通信接口aidl:

package com.lyc.aidl.service;import com.lyc.aidl.Pet;import com.lyc.aidl.Person;interface IPet{// 定义一个Person对象作为传入参数List<Pet> getPets(in Person owner);}
3、定义远程Service:

private PetBinder petBinder;private static Map<Person , List<Pet>> pets= new HashMap<Person , List<Pet>>();// 继承Stub,也就是实现额IPet接口,并实现了IBinder接口public class PetBinder extends Stub{@Overridepublic List<Pet> getPets(Person owner) throws RemoteException{// 返回Service内部的数据return pets.get(owner);}}@Overridepublic void onCreate(){super.onCreate();petBinder = new PetBinder();}
4、在客户端的绑定和通信操作:

public class ComplexClient extends Activity{private IPet petService;private Button get;EditText personView;ListView showView;private ServiceConnection conn = new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service){// 获取远程Service的onBind方法返回的对象的代理petService = IPet.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name){petService = null;}};@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);personView = (EditText) findViewById(R.id.person);showView = (ListView) findViewById(R.id.show);get = (Button) findViewById(R.id.get);// 创建所需绑定的Service的IntentIntent intent = new Intent();intent.setAction("org.crazyit.aidl.action.COMPLEX_SERVICE");// 绑定远程ServicebindService(intent, conn, Service.BIND_AUTO_CREATE);get.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0){try{String personName = personView.getText().toString();// 调用远程Service的方法List<Pet> pets = petService.getPets(new Person(1,personName, personName)); //其他操作}catch (RemoteException e){e.printStackTrace();}}});}@Overridepublic void onDestroy(){super.onDestroy();// 解除绑定this.unbindService(conn);}}

五、BroadcastReceiver

BroadcastReceiver作为全局监听器,可以非常方便的实现不同组件之间的通信,例如客户端程序与startService方法启动的Service之间的通信。

启动BroadcastReceiver只需要两步:

1、创建需要启动的BroadcastReceiver的Intent;

2、调用Context的sendBroadcast()或者sendOrderBroadcast()方法来启动指定的BroadcastReceiver。

当程序发出一个BroadcastReceiver Intent之后,所有匹配该Intent的BroadcastReceiver都有可能被启动。

前面介绍的OnXxxListener只是程序级别的监听器,当程序退出时,OnXxxListener监听器也随之关闭;BroadcastReceiver属于系统级的监听器,拥有自己的进程,只要存在匹配的Intent,就会被激发。

实现BroadcastReceiver,只需要重写onReceive(Context context,Intent intent)方法即可。

指定BroadcastReceiver匹配的Intent,有两种方式:

1、代码指定。

IntentFilter filter=new IntentFilter("android.provider.Telephony.SMS_RECEIVED");IncomingSMSReceiver receiver=new IncomingSMSReceiver();registerReceiver(receiver,filter);
2、在AndroidManifest.xml文件中配置。

<receiver android:name=".IncomingSMSReceiver"><intent-filter><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter></receiver>
系统Broadcast事件之后,系统会创建对应的BroadcastReceiver的实例,并自动触发它的onReceive()方法,onReceive()方法执行完后,BroadcastReceiver的实例就会被销毁。和Activity不同的是,通过Intent启动Activity组件,如果找不到,就会程序异常;通过Intent启动BroadcastReceiver时,如果找不到,应用不会有任何问题。

不要在BroadcastReceiver的onReceive()方法中执行耗时操作。如果需要执行耗时操作,可以考虑使用Intent启动一个Service完成操作。

Broadcast分为两种:

1、普通广播:完全异步,逻辑上可以在同一时刻被所有接收者接收。缺点是不能将处理结果传递给下一个接收者,并且无法终止Broadcast Intent的传播。使用sendBroadcast()方法发送。

2、有序广播:接收者按照在<intent-filter.../>元素的android:priority属性中声明的优先级依次接收Broadcast。优先级别也可以调用IntentFilter的setPriority()进行设置。有序广播的接收者可以终止有序广播的传播,调用BroadcastReceiver的abortBroadcast()方法即可终止广播,后面的接收者就无法接收广播。高优先级的接收者可以通过setResultExtras(Bundle bundle)方法将处理结果数据存入广播中,传递给低优先级接收者,通过Bundle bundle=getResultExtras(true)获取上一个接收者存入数据。使用sendOrderedBroadcast()方法发送。

另外,还可以让程序中的BroadcastReceiver监听系统相关数据和状态的改变广播。

0 0
原创粉丝点击