(一)核心组件详解

Android有4个核心组件,分别是:提供界面显示的Activity、提供后台计算的Service、提供进程间通信的Intent和提供广播接收的BroadcastReceiver。本篇将详细介绍这几个核心组件的使用方法和技巧,以及背后的一些逻辑和原理。

(一)Activity组件
Activity是Android最重要的组成部分之一,是实际与用户交互的组件。其重要的几个子类有:ListActivity、PreferenceActivity和TabActivity。Activity类图如下:

1.1、ListActivity
ListActivity可以用来实现列表功能,在Android中提供了对基本的单行、双行列表的封装,同时还支持用户自定义列表,自定义列表主要是基于ListView实现的(ListView也在此一并介绍)。对于ListActivity实现而言,充分利用了适配器模式,无论数据怎么复杂,总可以做到不变应万变,极大的减少实现的复杂度。
实现一个列表包括3步:1)选择或者自定义列表项布局文件;2)实现适配器并加载数据;3)为ListActivity设置适配器
1.1.1、系统列表项布局文件
列表布局文件决定了列表的布局风格,Android已经实现了基本的列表项布局文件,如单行布局的simple_list_item_1、基于简单双行布局的simple_list_item_2、单行单选simple_list_item_single_choice等布局文件。实现如下:
 setListAdapter(new ArrayAdapter<String>(this, android.R.layout. simple_list_item_1, mStrings)) ;
1.1.2、系统适配器
Android提供的多个适配器,主要有BaseAdapter、CursorAdapter、ResourceCursorAdapter、SimpleCursorAdapter、ArrayAdapter和SimpleAdapter等。
BaseAdapter是最基本的适配器,是其他适配器的基类,在其中用了观察者模式,当数据源发生变化时,可以通知显示控件自行刷新,通知方法notifyDataSetChanged()。虽然在在此调用setAdapter()也可以实现视图的刷新,但其性能上的损耗比调用的notifyDataSetChanged()方法要高。
1.1.3、自定义适配器
主要介绍两种自定义适配器的实现
    1)基于BaseAdapter的自定义适配器,需要重点关注的是getView(int position, View convertView, ViewGroup parent)方法的实现,getView()方法完成的主要工作是列表项布局文件的加载和数据的绑定,需要主要,只有当convertView为空时才加载布局文件,这样可以避免无谓的性能损耗。
    2)基于CursorAdapter的自定义适配器,需要重点关注的是bindView(View view, Context context, Cursor cursor)方法和newView(Context context, Cursor cursor, ViewGroup parent)方法的实现,bindView()方法用于绑定数据,newView()方法用于加载布局文件,同样在加载布局文件时,考虑多次操作findViewById()方法对性能有影响,可以通过View的setTag()h和getTag()方法大幅提高显示速率,同样是优化显示的一种方法。
1.1.4、复杂场景处理
除了正常的布局加载和数据适配,还有一些特殊场景需要主要,如快速滚动的显示问题,列表项可单击控件的处理等。
    1)快速滚动显示问题:在快速滚动时,对于性能稍弱的设备或计算大的渲染,可能无法及时处理,影响体验效果。开发者可以通过ListView的setOnScrollListener()方法监听列表的状态变化设置滚动处理情况。
    2)列表项可单击控件的处理:如果复杂列表项布局包含可单击控件,且默认子空间自动获取焦点,会导致单击列表项时无法处理单击事件,只需在适配器的getView()方法设置子控件的setFocusable()方法使之无法获得焦点即可。
    3)无列表项时ListView显示:通常在应用中,无任何列表项可以显示默认场景来保证用户体验,给用户提示,需要关注适配器的isEmpty()方法,返回true时处于无列表项状态。在HoneyComb中处理无列表项状态,只需要通过ListFragment方法的setEmptyText()方法。
    4)设置头视图和尾视图:需要调用addHeaderView()或者addFooterView()方法,必须在添加完后才可以设置适配器,而且对于头尾视图,刷新后无任何列表项,也会消失。
1.2、PreferenceActivity
PreferenceActivity主要用于实现偏好设置,布局上以PreferenceScreen为根布局,支持CheckBox Preference等多种形式的偏好设置。偏好值默认存储于SharedPreferences中,通过getSharesPreferences()获得SharedPreferences对象,通过Preferene.onPreferenceChangeListener监听器监听偏好值变化。
常用偏好设置实现:
    1)CheckBoxPreference不但提供了二选一偏好方法,还支持偏好说明。
    2)DialogPreference目前仅作为借口存在,要通过继承DialogPreference才可以实现。
    3)EditTextPreference提供支持输入框偏好设置功能。
    4)ListPreference,当某个偏好有多个偏好值可选时派上用场。其中entries表示界面内容,entryValue对应的是实际偏好值。
    5)RingtonePreference用于设置铃声的特殊偏好控件。
    6)PreferenceCategory提供偏好组的功能。
例子:
 <PreferenceCategory
        android:key="account_servers"
        android:title="@string/account_title">
        <CheckBoxPreference
            android:key="account_login"
            android:default="true"
            android:title="自动登录"
            android:summary="login"/>
        ......
    </PreferenceCategory >
1.3、TabActivity
TabActivity能让用户在单一界面实现更多功能,简化用户的操作。根布局控件为TabHost,它由TabWidget和通常基于FrameLayout的内容显示区域组成。
1.3.1、自定义Tab
对于标准的Tab而言,由图标和标签两部分组成,图标的存在减少了有效显示的区域面积,可以去除图标。如果希望自定义Tab的高度信息,实现如下:
 getTabWidget().getChildAt(i).getLayouParams().height = 48 ;
1.3.2、创建Tab页
创建Tab页有两种方式:一种是加载视图的方式,一种是加载Activity的方式。
    1)加载视图:对于布局简单的Tab也,通常采用加载视图的方式实现,通过不同的Tab显示不同的视图。
    2)对于复杂布局的Tab页,为了减低复杂性,通常采用加载Activity的方式实现,需要用到tabHost的setContent()方法。
例子:
 Intent intent = new Intent(this, OtherActivtiy.class) ;
    TabHost tabHost = getTabHost() ;
    tabHost.addTab(tabHost.newTabSpec("title")
        .setIndicator("标题", getResources().getDrawable(R.id.xxx)        //如果不出入图片即仅显示标题
        .setContent(intent))) ;
1.4、Activity的加载模式
Activity共有4中加载模式:standard、singleTop、singleTask和singleInstance。
standard加载模式是默认加载模式,加载时会创建一个新的Activity,类似Intent标志位为Intent.FLAG_ACTIVITY_NEW_TASK。
singleTop加载模式表示当前Activity的实例处于前天并可视时,该实例会收到发送过来的Intent消息。
singleTask加载模式表示当前Activity栈中有该Activity实例运行时,该实例接收Intent信息。
singleInstance加载模式表示该Activity以单子模式加载,在一个栈中仅仅有该实例,如果当前Activity栈中唯一,则类似于singleTop模式。

(二)Service
如果计算量大而又非UI层工作,可以考虑将这部分工作放置在Service中。Android中Service应用非常广泛,尤其在框架层,应用更多的是对应系统服务的调用。在此将介绍几个常用的系统服务以及服务的启动和绑定。Service类图如下:

2.1、InputMethodService
该服务提供了一个输入法的标准实现,一个输入法在界面上由3部分构成,即软输入视图(Soft Input View)、候选视图(Candidates View)和全屏视图(Fullscreen View),实现自定义的输入法,需要注意一下几个回调方法:
    public void onInitializeInterface() ;
    public void onBindInput() ;
    public void onStartInput(EditorInfo info, boolean restarting) ;
    public View onCreateCandidatesView() ;
    public View onCreateInputView() ;
    public View onCreateExtractTextView() ;
    public void onStartInputView(EditorInfo info, boolean restarting) ;
2.2、IntentService
主要用于处理异步请求,防止服务阻塞,所有请求将在一个工作线程(HandlerThread)中处理,工作结束后,线程也结束。
2.3、MediaScannerService
主要在设备启动和SD卡挂载时执行多媒体文件的扫描功能,出于性能方面考虑,Android区分SD卡和手机存储空间。对于SD卡,MediaScannerService会收到Action为ACTION_MEDIA_MOUNTED的Intent(SD卡挂载)时进行扫描,对手机存储空间,会收到ACTION_BOOT_COMPLETED的Intent(即设备启动完毕)时进行扫描,另外在下载文件时也可能启动媒体扫描服务。
当系统开始扫描,会广播一个ACTION_MEDIA_SCANNER_START的Intent,然后创建MediaScannerService执行扫描,扫描结束,广播一个ACTION_MEDIA_SCANNER_FINISH的Intent。
2.4、RecognitionService
RecognitionService是一个抽象服务,开发者希望实现一个新的语音识别器时才可以用到。
2.5、绑定服务和启动服务
服务的运行有两种发起方式,即绑定服务和启动服务。通过绑定服务运行,一旦绑定解除,服务就被销毁,可以多次绑定;通过启动服务运行,服务不会随组件的销毁而销毁,而是服务会自我销毁,适用于文件下载、上传等自动运行服务。
2.5.1、绑定服务
需要设置ServiceConnection和标志位,是以异步的方式运行的,必须在当前的上下文环境中进行。  
    public abstract boolean bindService(Intent service, ServiceConnection conn, int flag) ;
    public abstract void unbindService(ServiceConnection conn) ;
2.5.2、启动服务
    public abstract void unbindService(ServiceConnection conn) ;    //启动服务
    public final void stopself() ;    //自我停止
    public abstract boolean stopService(Intent service) ;    //被动停止
(三)Intent
Intent是Android用于进程内或进程间通信的机制,其底层以IBinder机制实现,物理层上则通过共享内存的方式来实现。
Intent主要用于两种场景:广播和发起意图,其属性有ComponentName、action、data、category、extras、flags等,通常情况下,进行Intent匹配时,需要匹配Action、Data、Category等3种属性。
从目的地来说,Intent分为显式和隐式,所谓显式即明确指明了目的地,不需要系统进行Intent匹配,内部进行组件调用时,应该调用显式;隐式即没有明确目的地,需要系统根据自己信心进行匹配的Intent,这类Intent同样用于应用间的相互调用,有助于减低耦合性。
3.1、属性说明
    1)ComponentName:ComponentName为处理Intent消息的Android组件,可以使Activity、Service等,可以为空,会根据Intent携带的其他信心定位相应组件。
    2)action:表示Intent的类型,可以使查看、删除、发布或其他,最常用的是android.intent.action.Main,表示应用的入口。
    3)data:表示Intent携带的数据,通常与MIME类型结合使用,表示应用可以打开的数据的类型。
    4)category:表示Intent的策略,常用的有:DEFAULT、LAUNCHER、MONKEY、OPENABLE、BROWSABLE,对于没有设置的默认设置为DEFAULT。
    5)extras:表示Intent的附件信息,在组件间传递信息非常有用。
    6)flags:表示Intent的标志位,经常应用于Activity的场景,和Activity的启动模式密切相关。
3.2、特殊场景
作为整个系统的灵魂组件,Intent功能非常强大,使用范围非常广泛,可以应用于开机自启动、网络监听、获取内容、SD卡挂载等特殊场景。
例子(网络监听):
    <intent-filter>
        <action android:name="android.net.com.CONNECTIVITY_CHANGE" />
    </intent-filter>
//接收到相关信息后,从中获取网络状态
    if(action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
        NetworkInfo info = (NetworkInfo) ;
        intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO) ;
        if(info != null && info.isConnected()) { ... }
    }
3.3、PendingIntent的逻辑
PendingIntent和Intent略有不同,其可以设定执行次数,主要用于远程服务通信、闹钟、通知、短信、启动器中。
    public static PendingIntent getActivity(Context context, int requesrCode, Intent intent, int flags) ;        //类似startActivity(intent)
    public static PendingIntent getService(Context context, int requesrCode, Intent intent, int flags) ;        //类似sendBroadcast(intent)
    public static PendingIntent getBroadcast(Context context, int requesrCode, Intent intent, int flags) ;        //类似startService
3.4、返回结果
通常Intent是单向的,但特殊场景,可以返回相应的数据,调用方法如下:
    public void startActivityForResult(Intent intent, int requestCode) ;
完成后通过如下方法返回调用方的Activity:
    public final void serResult(int resultCode, Intent data) ;
计算完成,在调用方的onActivityResult()方法中收到返回结果:  
	protected void onActivityResult(int requestCode, int resultCode, Intent data) ;
(四)BroadcastReceiver
广播的发送本质是基于Intent进行的,接收实现也比较简单,具体如下:
	public class AlertReceiver extends BroadcastReceiver {
        	public void onReceiver(Context contex, Intent intent) { ... }
    	}
然后将BroadcastReceiver在AndroidManifest.xml文件进行注册过滤接收的广播:
     <receiver android:name="AlertReceiver">
        <intent-filter>
            <action android:name="android.intent.action.EVENT_REMINDER">
        </intent-filter>
    </receiver>
如果BroadcastReceiver作为组件的私有类,那么可以通过上下文环境的方法实现注册和解除:

    public abstract Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) ;
    public abstract Intent unRegisterReceiver(BroadcastReceiver receiver) ;

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值