android核心技术与最佳实践笔记(一)

本文详细介绍了Android的核心组件Activity,包括ListActivity、PreferenceActivity和TabActivity的使用,强调了自定义适配器和加载模式的重要性,并探讨了配置变化、屏幕旋转和主题属性的处理。同时,提到了Service组件中的IntentService、MediaScannerService和RecognitionService。
摘要由CSDN通过智能技术生成
第一章  android核心组件和应用框架
1.1 核心组件
        android的四大核心组件:提供界面显示的activity,提供后台计算的service,提供进程间通信的intent和提供广播接收的broadcastReceiver。
1.1.1 activity组件
     activity是实际与用户交互的组件。有几个子类需要注意: ListActivity, PreferenceActivity 和 TabActivity
     activity的类图如下:
                  
       分别介绍类的用途和实现原理:
        1.  ListActivity
          可以用来实现列表功能。ListActivity提供了对基本的单行,双行列表的封装,同时还支持用户自定义列表。自定义列表是基于ListView来实现的。实现一个列表包括3步:选择或自定义列表项布局文件,是吸纳适配器并加载数据,为ListActivity设置适配器。
             列表布局文件决定列表的布局风格,最基本的布局控件只有RelativeLayout和LinearLayout两个。
             适配器的选择,android支持两种基本的适配器:基本适配器(BaseAdapter)和游标适配器(CursorAdapter)。基本适配器是最通用的适配器,游标适配器用来适配数据库的数据流的,其他的系统级适配器都是继承这两个适配器。
             (1) 系统列表项布局文件
                   android目前实现的基本列表项布局文件,分别为:基于单行布局的simple_list_item_1布局文件, 基于简单双行布局的simple_list_item_2布局文件,基于单行单选布局的simple_list_item_single_choice布局文件,基于单行多选布局的simple_lsit_item_multiple_choice布局文件,类似树状图的simple_expandable_list_item_1和 simple_expandable_list_item_2布局文件等。
               例如: 基于simple_list_item_1布局文件的一个实现: 
                        setListAdapter(new ArrayAdapter<String>(this,  android.R.layout.simple_list_item_1,  mStrings));//mStrings为数组类型的数组,simple_list_item_1为列表布局风格的文件
                        下面介绍ArrayAdapter为例介绍适配器加载布局文件的方法:
                                
                             上述ArrayAdapter加载布局文件的过程,可以看出,默认情况下,ArrayAdapter假定整个布局文件是一个TextView,只有指定了mFieldId,及通过如下方法初始化ArrayAdapter时,ArrayAdapter才认为加载了一个自定义布局。
                            
                             ArrayAdapter的实现由很强的局限性,仅能显示单行的列表。下面介绍实现双行的列表的方法。
                             SimpleCursorAdapter的初始化过程如下:
                                  SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,  android.R.layout.simple_item_2, c,
                                                new String[]{ Phone.TYPE,  Phone.NUMBER },  new int[]{ android.R.id.text1,  android.R.id.text2 });
                              SimpleCursorAdapter的ViewBinder的实现如下:
                                              
         在ViewBinder的实现过程中,指定了布局文件,游标,数据项,控件ID等,但没有处理布局加载和数据绑定。下面是SimpleCursorAdapter的bindView()的实现,该方法揭示了布局加载和数据绑定的过程。
                                      
                                         
                                     从bindView()的实现中可以看出,SimpleCursorAdapter的ViewBinder实际上是用户的一个自定义实现接口,当用户没有进行自定义实现时,SimpleCursorAdapter会通过传递的控件数量进行默认数据绑定。SimpleCursorAdapter还支持图片加载,不过此时游标获取的不再是文本数据,而是图片的URI.
               (2)系统适配器
                  android中,提供的适配器:BaseAdapter, CursorAdapter, ResourceCursorAdapter,  SimpleCursorAdapter, ArrayAdapter 和 SimpleAdapter等。基本适配器类图如下:
                      
                  BaseAdapter适配器是最基本的适配器,是其他适配器的基类。BaseAdapter适配器可以适配ListView和Spinner等控件,通常会调用BaseAdapter的子类或通过BaseAdapter自定义适配器来实现视图与数据的适配功能。
                  在BaseAdapter适配器中,应用了观察者模式,当数据源发生变化时,可以通过显示控件自行刷新。
                (3)自定义适配器
                 a .  基于BaseAdapter的自定义适配器
                      对于 基于BaseAdapter的自定义适配器,需要注意的是getView()方法的实现,
                          
                                   getView()主要工作是列表项布局文件的加载和数据的绑定。
                            b.  基于CursorAdapter的自定义适配器
                                        基于CursorAdapter的自定义适配器的实现重点在与bindView()方法和newView()方法。 其中bingView()方法用于绑定数据,newView()方法用于加载布局文件。实例如下:
                                      
                                     考虑到加载列表项时多次操作findViewById()方法,对性能有所影响,因此在android中设计了ViewHolder,以其来进行优化。通过View的setTag()方法和getTag()方法可大幅度提高显示速率。
                           (4)复杂场景处理
                                  在ListView中一些特殊的场景需要注意,如快速滚动时的显示问题,列表项中可单击空间的处理等。
     2.  PreferenceActivity
             最要用于偏好设置,在布局上PreferenceActivity以PreferenceScreen为根布局,支持CheckBoxPreference等多种形式的偏好设置。这些偏好值默认存储于应用的SharedPreferences中,通过getSharedPreferences()可以获取SharedPreferences对象,通过Preference.OnPreferenceChangeListener监听器可以监听到偏好值的变化。
            下面介绍几种偏好值的实现。
          (1)CheckBoxPreference 
                   不但提供二选一偏好的方法,还支持偏好的说明。下面是CheckBoxPreference布局文件的一个示例:
                             <CheckBoxPreference
                                     android:key="bt_discoverable"
                                     android:title="@string/bluetooth_visibility"
                                     android:dependency="bt_checkbox"
                                     android:summaryOn="@string/bluetooth_is_discoverable"//偏好说明
                                     android:summaryOff="@string/bluetooth_not_discoverable"
                                     android:persistent="false" />
            (2)DialogPreference
                        目前仅仅是一个接口,
            (3)EditTextPreference
                        提供了支持输入框的偏好设置功能。通过getEditText()方法获得输入框的内容,通过getText()可获得SharedPreferences中存储的偏好值,通过setText()方法可以将偏好值保存在SharedPreferences中,具体如下:
                               
            (4)ListPreference
                         当某个偏好有多个偏好值可选时,ListPreference就派上了用场,在使用ListPreference时需要注意entries和entryValues属性,其中entries表示界面的内容,而entryValues对应的是实际偏好值。
                        
                         在ListPreference中,用户只能做单选操作,如果期望能够执行多选操作,则需要用到MultiSelectListPreference 。 MultiSelectListPreference的资源文件配置和ListPreference类似。
                (4)RingtonePreference
                         是一个用于设置铃声的特殊偏好控件,目前Android提供的铃声类型包括ringtone, notification, alarm 和all等。其中all表示所有可用的铃声。下面是Ring头呢Preference的配置示例:
                         
                (5)PreferenceCategory
                         其提供了偏好组的功能。下面是一个偏好配置示例:
                          
       3.  TabActivity
               TabActivity的根布局控件为TabHost,它由TabWidget和通常基于FrameLayout的内容显示区域组成。示例如下:
                       
           (1)自定义Tab
                     
    4.  activity的加载模式
               在android中,有4中加载模式:standard,  singleTop ,  singleTask 和 singleInstance
               standard加载模式为android默认加载模式,在加载是会创建一个新的activity的实例,类似调用startActivity()方法时设置Intent的标志位为intent.FLAG_ACTIVITY_NEW_TASK。  发起standard加载模式的实例如下:
                            Intent  i =  new Intent();
                            i.setFlags(I ntent.FLAG_ACTIVITY_NEW_TASK);
                             startActivity();
              singleTop 加载模式表示当前Activity的实例处于前台并可视时,该实例会收到发送过来的Intent消息,器接收方法如下:
                            protected void onNewIntent(Intent  intent){
                                   super.onNewIntent(intent);
                                    ........
                             }
              singleTask加载模式表示当前Acitivity栈(Task)中当前Activity实例运行时,该实例会收到相应的Intent消息,接收方法类似于singleTop加载模式。发起singleTask加载模式的示例如下:
                             Intent  i  = new  Intent(); 
                             i.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                             startActivity(i);
              singleInstance加载模式表示该Acitivity以单子模式加载时,在当前Activity栈中唯一,接收方法类似于singleTop加载模式。
               为保证Activity在系统运行时能正常加载,必须在AndroidManifest.xml中声明所有需要加载的Activity,方法如下:    
                             <activity   android:name="TestActivity"
                                              android:label="@string/app_name"
                                              android:launchMode="singleInstance"
                                               //忽略重力传感器和键盘隐藏等变化
                                              android:configChanges="orientation|keyboardHidden" >
                              </activity>
               注意:通常情况下,当单个应用中包含的文件较多时,通常需创建子文件夹进行区分,如将实现Activity的文件放在ui文件夹下,将实现Service, Provider的文件放在service文件夹下,将实现的一些自定义视图放在view文件夹下,将实现一些工具文件放置在util文件夹下。这样声明的方法略有不同,具体如下:
               <activity  android:name=".ui.TestActivity"  >   ........   </activity>//注意ui前面的”.“表示当前目录
     5.  activity的属性配置
        (1)配置变化属性
                 在android中存在一些基本的配置,如android:mcc,  android:mnc,  android:locale,   android:touchscreen,  android:keyboard,  android:keyboardHidden,  android:navigation,   android:orientatiion,  android:screenLayout,  android:fontScale和android:uiMode等,用户可对这些属性进行配置,若实现与配置相关,则需监听这些属性的变化。 
               android:mcc  属性表示MCC(Mobile Country  Code),即 SIM 卡中存储的 IMSI号中的国家代码布恩,当发生国际漫游时,该属性配置会发生变化。
               android:mnc  属性表示MNC (Mobile  Network Code), 即 SIM 卡中存储的 IMSI 号中的网络代码部分,当发生不同运营商网络间漫游时,该配置会发生变化,如在中国移动和中国联通的GSM网络间漫游。当然,运营商可以限制此类漫游。
               android:locale 属性表示当前显示语言发生变化
               android:touchscreen 属性表示触摸屏发生了变化,考虑到当前的实际情况,只有在支持多屏显示时,才需使用该属性。
               android:keyboard 属性表示键盘类型发生了变化,如外接了蓝牙键盘等。
               android:keyboardHidden 属性表示显示或隐藏键盘,对翻盖或滑盖终端有效。
               android:navigation 属性表示导航键发生了变化,如从轨迹球变化为五向键,考虑到当前的实际情况,该配置显然不会发生变化。
               android:orientation 属性表示屏幕方向
               android:screenLayout 属性表示屏幕布局发生变化。在不支持多屏显示的情况下,该配置不会发生变化。
               android:fontScale 属性表示字体发生了变化
               android:uiMode 属性表示UI模式发生了变化,如变为车载模式,夜间模式等
           默认情况下,当配置发生变化时,当前的Activity会在被销毁后重新生成,通过在AndroidManifest.xml 中为相应的Acitivity针对特定配置声明该属性,则可阻止特定配置变化时Activity被销毁后重新生成。当然,在某种情况下,开发者仍然需要监听到配置的变化,则可在Activity中实现如下方法:                          public  void  onConfigurationChanged(Configuration newConfig)
                android:configChanges 属性的设置方法:  android:configChanges="orientation|keyboardHidden"
         (2)屏幕旋转属性
                   android:screenOrientatiion属性,在有重力传感器的情况下,必须考虑屏幕的适配情况,其属性值包括:unspecified,  landscape,  portrait,   user,  behind , sensor, nosensor等,其中 unspecified为默认值,旋转策略由系统决定; landscape表示横屏; portrait表示竖屏; user表示当前用户倾向的屏幕方向;behind表示屏幕方向和Activity栈中当前activity下面的activity相同; sensor 表示根据重力传感器确定屏幕方向;
          (3)主题属性
                  android:theme 属性表示当前activity的主题,通常用于设置标题栏,状态栏等,设置方法: 
                         android:theme="@android:style/Theme.NoTitleBar"
         (4)启动约束属性
                  android:exported属性表示启动约束,即是否允许被其他进程调用,如果值为false,则该Activity仅可被同一应用中的组件或拥有相应用户ID的应用的组件调用;若为true, 则可被其他进程调用。
                    android:exported属性的默认值与携带的Intent过滤器有关,如果没有携带任何Intent 过滤器,其值为false

1.1.2  Service组件
        Service的类图如下:
            
           将Service纳入编译系统,需要在AndroidManifest.xml中对Service进行显式声明,方法如下:
                       <service android:name=".service.TestService" ></service>
           1.   InputMethodService
                       InputMethodService提供了一个输入法的标准实现,普通开发者不需要关心。一种输入法在界面上有3部分构成,及软输入视图(soft input view), 候选视图,和全屏模式。
           2.   IntentService
                      IntentService 作为Service的子类,主要用于处理异步请求,防止服务阻塞。所有的请求将在一个工作进程中处理,工作结束后,线程也结束。在gallery3d应用中,CacheService即是IntentService的一个示例。
           3.   MediaScannerService
                      MediaScannerService 主要在设备启动和SD卡挂载时执行多媒体文件的扫描工作。处于性能方面的考虑, android区分SD卡和手机内存空间。对于SD卡,MediaScannerService会收到 Action为ACTION_MEDIA_MOUNTED的Intent时进行扫描;  对于手机存储空间,MedaiScannerReceiver会在收到Action为ACTION_BOOT_COMPLETED的Intent(设备启动完毕)时进行扫描。另外,在下载文件时,也可能启动媒体扫描服务。
                     媒体扫描服务相关的类如下如:
                                 
                      目前MediaScannerService扫描的多媒体格式定义在MediaFile.java 文件中。当系统开始扫描时,媒体扫描服务会广播一个Action为ACTION_MEDIA_SCANNER_STARTED的Intent, 然后创建一个MediaScanner执行扫描;当扫描结束后,广播一个Action为ACTION_MEDIA_SCANNER_FINISHED的Intent。
                     在一个特殊的场合,如录音应用和下载场景中,如果希望产生的多媒体文件接口被加入到数据库中,可以直接调用媒体扫描服务进行单个文件的扫描,但对于删除的文件,无法通过如下方式进行同步:
                                   sendBroadcase(new  Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,  Uri.fromFile(file)));
          4.  RecognitionService
                     RecognitionService是一个抽象服务,仅在开发者希望实现一个新的语音识别器时,才可能用到。为了实现一个新的语音识别器,必须实现如下抽象方法:
                             protected  abstract  void  onStartListening( Intent  recognizerIntent,  Callback  listener )
                             protected  abstract  void  onCancel( Callback  listener )
                             protected  abstract  void  onStopListening( Callback listener )
           5.   绑定服务和启动服务
                    服务的运行有两种发起方式,即绑定服务和启动服务。当通过绑定服务的方式运行服务时,一旦绑定解除,服务即被销毁,当进行多次绑定时,只有所有绑定均解除,服务才会销毁; 当以启动服务的方式运行服务时,服务并不会随着绑定组件的销毁而销毁,而是服务自我销毁,这种方式适用于文件下载,文件上传等请求后自行运行的场景。
             (1)绑定服务
                          为了绑定一个服务,需要设置 ServiceConnection 和标志位 ,方法如下:
                                  public  abstract  boolean  bindService(Intent  service,  ServiceConnection  conn,  int  flags)
                          ServiceConnection可以监控服务的状态,在进行服务绑定时,其标志位可以为BIND_AUTO_CREATE,  BING_DEBUG_UNBIND和 BING_NOT_FOREGROUND等。其中BIND_AUTO_CREATE表示当收到绑定请求时,如果服务尚未创建,则即可创建,在系统内存不足,需要先销毁优先级组件来释放内存,且只有驻留该服务的进程成为被销毁对象时,服务才可被销毁;BING_DEBUG_UNBIND通常用于调试场景中判断绑定的服务是否正确,但其会引起内存泄露,因此非调试目的不建议使用;  BING_NOT_FOREGROUND表示系统将阻止驻留该服务的进程具有前台优先级,仅在后台运行,该标志位在Froyo中引入。
                          绑定服务的示例:
                                         Intent  intent  = new  Intent();
                                         intent.setClassName("com.android.providers.media",  "com.android.providers.media.MediaScannerService");
                                         bindService(intent,  mMediaScannerConnection,  BIND_AUTO_CREATE);
                          注意绑定服务是以异步的方式运行的。绑定服务必须在当前的上下文环境中进行,在某些场景中,如果无法绑定成功,则可能需要在应用级的上下文环境进行,方法如下:     getApplicationContext().bingService(......);
                          如果解除绑定,方法如下: 
                                         public  abstract  void  unbindService( ServiceConnection  conn )
              (2)启动服务
                            启动服务: public  abstract  ComponentName  startService(Intent  service)
                            自我停止服务:    public  final  void  stopself()
                            被动停止服务:    public  abstract  boolean stopService (Intent  service)
       6.  服务的声明周期
                两种运行方式下的服务的声明周期:
                                 
               当外部组件调用其上下文的startService()方法时,即可启动相应的服务。在服务的 onStartCommand()方法中,会返回一个唯一的整数标示符启动请求。启动服务的实例如下:
                     Intent  intent = new Intent( this , ExperimentService.class );
                     intent.putExtra(EXTRA_EXP_ID,  which);
                     intent.putExtra(EXTRA_RUN_ALL,  all);
                     startService(intent) ;
                 Intent 传递过来的参数可以在onStartCommand()方法中进行处理,示例如下:
                                public int  onStartCommand(Intent  intent,  ing flags ,  int  startId) {
                                          if(intent != null){
                                                   Message  msg = mServiceHandler.obtainMessage(); 
                                                   msg.arg1 = startId;
                                                   msg.obj = intent.getExtras();
                                                   mServideHandler.sendMessage(msg);
                                          }
                                          return  START_REDELIVER_INTENT;
                                }
                 停止服务如下:                          stopService(intent) ;
                  当外部组件调用其上下文的bingService()方法时,也可绑定相应的服务。如果服务未启动,则调用onCreate()方法启动服务, 当不会调用onStartCommand()方法,只有在所有绑定均解除后,服务才自动停止运行。通过服务的onBind()方法,可以获得一个客户端与服务进行同行的IBinder接口。注意,绑定服务的android组件在销毁前应解除绑定,否则会造成内存泄露。绑定和解除绑定的实例如下: 
                             mContext.bindService( new  Intent( IBluetoothHeadset.class.getName()), mConnection,  0  );
                             mContext.unbindService( mConnection );
                             
 1.1.3   Intent 组件
           intent用于进程内或进程间通信的机制,其底层的通信以Binder机制实现,在物理层上则通过共享内存的方式来实现。
           主要用于广播和发起意图两中场景,属性有ComponentName,  action , data,  category, extras,  flags等。通常情况下,在进行Intent 的匹配时,需要匹配Action,  Data,  Category 等3个属性。
           从ComponentName 属性的明确性可以划分为,显式的intent和隐式的intent,所谓的显式的intent,即明确了目的地,不需要系统进行intent匹配的Intent。在应用内部进行组件调用时,应首选显示Intent., 举例如下;
                     intent  i = new  Intent( context,  AccountFolderList.class ) ;
                     i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);                   context.startActivity(i);
          所谓的隐式Intent, 即没有明确指明目的地,需要系统根据自己的信息进行匹配的Intent. 这类Intent同样用于应用间的相互小勇,有助于降低应用间的耦合性。举例如下:
                 Intent  intent = new  Intent(Intent.ACTION_PICK);
                 intent.setDadaAndType(Uri.EMPTY,  "vnd.andorid.cursor.dir/track");
                 intent.putExtra("album",  Long.valueOf(id).toString());
                 intent.putExtra("artist",  mArtistId);
                 startActivity(intent);
       1  。 属性说明:
          (1)ComponentName    为处理Intent消息的android组件,可以是activity,服务等。通常使用方法:
                           public  Intent  serClassName( Context  packageContext,  String   className )
                    其中,className可以为空,系统会更具intent携带的其他信息来定位相应的组件。
          (2)action  表示Intent的类型,可以是查看,删除,发布或其他,最常用的是android.intent.action.MAIN。     android.intent.action.MAIN表示一个应用的入口,通常和  android.intent.category.LAUNCHER联合使用。二者同时使用表示应用程序的启动界面。
          (3)data   表示Intent携带的数据,通常和MIME类型联合使用,表示应用可以打开的数据类型,用法如下:
                        <intent-filter>
                                    <action  android:name="android.intent.action.SEND_MULTIPLE" />
                                    <category  android:android:name="android.intent.category.DEFAULT" />
                                    <data  android:mineType="image/*" /> 
                                    <data  android:mineType="video/*" />
                           </intent-filter> 
           (4)category   表示intent的策略,目前最常用的如下:
                          android.intent.category.DEFAULT      ...LAUNCHER       ...MONKEY      ...OPENABLE   ...BROWSABLE
                          对于隐式的intent, 如果创建是没有指定category属性,则系统会默认设置器属性为android.intent.category.DEFAULT, 这是如果在intent过滤器中没有指定category属性为 android.intent.category.DEFAULT,则会造成匹配失败。
           (5)Extras  表示intent的附加信息,它在组件间传递信息时非常有用。目前Extras可以支持多种数据类型,如布尔,整型,字符串等,实例如下:
                   Intent  i  = new  Intent(this , AlarmAlertFullScreen.class); 
                   i.putExtra(Alarms.ALARM_INTENT_EXTRA,  mAlarm);
                   i.putExtra(SCREEN_OFF,  true);         
                  startActivity(i);
             (6)Flags  表示Intent的标志位。Flags和Activity 的启动模式有密切的关系。
     2  。 特殊场景
             下面介绍一些Intent应用的特殊的场景,如开机自启动,网络监听,获取内容,SD卡挂载等。
            (1) 开机自启动
                  接收开机自启动事件的Intent过滤器的设置方法如下: 
                       <receiver  android:name=“.receiver.ImServiceAutoStarter”
                                        android:process="android.process.im" >
                               <intent-filter>
                                        <action  android:name="android.intent.action.BOOT_COMPLETED" />
                                 </intent-filter>
                        </receiver>
              (2)网络监听
                   对网络进行监听的设置如下: 
                       <intent-filter>
                              <action  android:name="android.net.conn.CONNECTIVITY_CHANGE" />
                       </intent-filter>
                   在接收到相关的信息后,可以从中获取网络的状态,方法如下;
                              if(action.equals(ConnectivityManager.CONNECTIVITY_ACTION)){
                                       NetworkInfo  info = (NetworkInfo);
                                       intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
                                       if(info != null &&  info.isConnected){ ...  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值