Android中四大组件以及如何避免anr

来源:互联网 发布:管家婆软件普普版 编辑:程序博客网 时间:2024/06/05 13:01

一个Android程序有四大基本组件,但只有activity是必须有的


1,activity:可视化的交互界面,   为一个Android程序添加一个activity的步骤是

             第一步:新建一个类继承自activity,  并且为该activity设置布局文件  

<span style="font-size:14px;">public class MyNext extends Activity {             ......         setContentView(R.layout.activity_next);      }</span>

      

            第二步,在Androidmanifest.xml清单文件中配置该activity

<span style="font-size:14px;">  <activity android:name=".activity.MyNext"/></span></span>

   至此,一个新的activity就添加成功了,一个activity的生命周期为:onCreate,onStart,onResume,onPause,onStop,onDestroy

 

2,service:服务,无界面,生命周期长,不可见,可运行在后台的组件,为一个Android程序添加服务的步骤是

             第一步:新建一个类继承自Service

 

<span style="font-size:14px;">     public class MyService extends Service {            ......       }</span>

              第二步,在Androidmanifest.xml清单文件中进行配置该service

   <span style="font-size:14px;">  <service            android:name=".MyService"/></span>

               第三步,在activity中开启服务

                开启服务的方式 有两种

                第一种:   利用startService开启的服务与 访问者相互独立,必须调用stopService 来结束服务

<span style="font-size:14px;">         //开启服务                         startService(new Intent(MyNext.this,MyService.class));           //结束服务                         stopService(new Intent(MyNext.this,MyService.class));</span>


利用 这种方式开启服务时其生命周期为:onCreate-->onStartCommand--->onDestroy,当我多次调用startService时,如果服务已经被创建则只会调用onStartCommand方法,若未创建则去调用onCreate。。。。

<span style="font-size:14px;">12-16 11:09:38.154  21909-21909/com.example.yong.myfirstdemo I/tag﹕ 调用的方法是->>onCreate---com.example.yong.myfirstdemo.MyService12-16 11:09:38.154  21909-21909/com.example.yong.myfirstdemo I/tag﹕ 调用的方法是->>onStartCommand---com.example.yong.myfirstdemo.MyService12-16 11:09:40.599  21909-21909/com.example.yong.myfirstdemo I/tag﹕ 调用的方法是->>onStartCommand---com.example.yong.myfirstdemo.MyService12-16 11:09:40.898  21909-21909/com.example.yong.myfirstdemo I/tag﹕ 调用的方法是->>onStartCommand---com.example.yong.myfirstdemo.MyService12-16 11:09:43.090  21909-21909/com.example.yong.myfirstdemo I/tag﹕ 调用的方法是->>onyDestroy---com.example.yong.myfirstdemo.MyService</span>

                      第二种:  利用bindService开启服务,该服务依赖于访问者而存在,  若访问者退出则服务结束,所以如果要求服务和访问者 同时结束,不需要调用任何方法去结束服务。如果想要在访问者未 结束时就结束服务,需要调用unbindService方法。


            <span style="font-size:14px;">  //开启服务                bindService(new Intent(MyNext.this,MyService.class), serviceConnection, BIND_AUTO_CREATE);                //关闭服务,参数与开启服务中的serviceConnection为同一个,若不相同,会出现如下错误                unbindService(serviceConnection);</span>

当bindservice方法与unbindService方法的参数serviceConnection使用的不同时会出现如下错误,如果出现如下I错去,那就要检查一下serviceConnection是不是在unbindService时重新创建了一次:

<span style="font-size:14px;">java.lang.IllegalArgumentException: Service not registered: com.example.yong.myfirstdemo.activity.MyNext$MyServiceConn@411c3870            at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:959)            at android.app.ContextImpl.unbindService(ContextImpl.java:1574)            at android.content.ContextWrapper.unbindService(ContextWrapper.java:484)            at com.example.yong.myfirstdemo.activity.MyNext.onClick(MyNext.java:191)            at android.view.View.performClick(View.java:4222)            at android.view.View$PerformClick.run(View.java:17624)            at android.os.Handler.handleCallback(Handler.java:800)            at android.os.Handler.dispatchMessage(Handler.java:100)            at android.os.Looper.loop(Looper.java:194)            at android.app.ActivityThread.main(ActivityThread.java:5398)            at java.lang.reflect.Method.invokeNative(Native Method)            at java.lang.reflect.Method.invoke(Method.java:525)            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:836)            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:603)            at dalvik.system.NativeStart.main(Native Method)</span>
                        用这种方式开启服务时服务的生命周期为:onCreate-->onBind-->onUnbind-->onDestroy,在服务创建后,我调用多次bindService方法,不会再去调用onCreate  和onBind方法。。在服务创建后不论是退出activity还是调用unbindService方法都会去调用onUnbind和onDestroy方法
<span style="font-size:14px;">12-16 11:12:57.410  22870-22870/com.example.yong.myfirstdemo I/tag﹕ 调用的方法是->>onCreate---com.example.yong.myfirstdemo.MyService12-16 11:12:57.411  22870-22870/com.example.yong.myfirstdemo I/tag﹕ 调用的方法是->>onBind---com.example.yong.myfirstdemo.MyService12-16 11:13:06.918  22870-22870/com.example.yong.myfirstdemo I/tag﹕ 调用的方法是->>onUnbind---com.example.yong.myfirstdemo.MyService12-16 11:13:06.922  22870-22870/com.example.yong.myfirstdemo I/tag﹕ 调用的方法是->>onyDestroy---com.example.yong.myfirstdemo.MyService</span>

                   但是如果未调用bindService方法,就 调用unbindService方法,则会出现以下异常:

<span style="font-size:14px;">java.lang.IllegalArgumentException: Service not registered: com.example.yong.myfirstdemo.activity.MyNext$MyServiceConn@412019c0            at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:959)            at android.app.ContextImpl.unbindService(ContextImpl.java:1574)            at android.content.ContextWrapper.unbindService(ContextWrapper.java:484)            at com.example.yong.myfirstdemo.activity.MyNext.onClick(MyNext.java:186)            at android.view.View.performClick(View.java:4222)            at android.view.View$PerformClick.run(View.java:17624)            at android.os.Handler.handleCallback(Handler.java:800)            at android.os.Handler.dispatchMessage(Handler.java:100)            at android.os.Looper.loop(Looper.java:194)            at android.app.ActivityThread.main(ActivityThread.java:5398)            at java.lang.reflect.Method.invokeNative(Native Method)            at java.lang.reflect.Method.invoke(Method.java:525)            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:836)            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:603)            at dalvik.system.NativeStart.main(Native Method)</span>

                  如果出现上述异常,仅仅是因为未绑定服务,可以用try/catch语句来提醒用户还未绑定服务

  <span style="font-size:14px;">          try {                    unbindService(serviceConnection);                } catch (IllegalArgumentException e) {                    //异常处理代码                    Log.i("tag","还未绑定服务");                }</span>

3,BroadcastReceiver,广播接收器,广播接收器只有一个方法onReceive,广播接收器组件用法如下:

      第一步:自定义一个类,继承自BroadcastReceiver,并重写onReceive方法,代码如下:

        

<span style="font-size:14px;"> class MyBroadCastReceiver extends BroadcastReceiver{        @Override        public void onReceive(Context context, Intent intent) {            //监听到广播时的代码            Log.i("tag", "调用的方法是->>onReceive" + "---" + getClass().getName());        }    }</span>

         第二步,注册广播,和服务类似,广播的注册有两种形式,

               第一种,在Androidmanifest.xml文件中注册

       <span style="font-size:14px;">  <receiver android:name=".MyBroadCastReceiver">            <intent-filter>                <action android:name="com.receiver"/>            </intent-filter>        </receiver></span>

                第二种方式,在代码中注册,

                 

<span style="font-size:14px;">     IntentFilter filter = new IntentFilter("com.receiver");    MyBroadCastReceiver mBroadCastReceiver = new MyBroadCastReceiver();</span>

                   
<span style="font-size:14px;">              //注册广播                registerReceiver(mBroadCastReceiver, filter);                //撤销广播                unregisterReceiver(mBroadCastReceiver);</span>

       广播注册成功后,我们可以发送广播
<span style="font-size:14px;">               //发送广播               sendBroadcast(new Intent("com.receiver"));</span>

正如Service中bindService与unbindService必须成对出现,广播中registerReceiver与unregisterReceiver也必须成对出现,如果出现以下错误:
<span style="font-size:14px;"> java.lang.IllegalArgumentException: Receiver not registered: com.example.yong.myfirstdemo.MyBroadCastReceiver@411d37f8            at android.app.LoadedApk.forgetReceiverDispatcher(LoadedApk.java:665)            at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:1462)            at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:445)            at com.example.yong.myfirstdemo.activity.MyNext.onClick(MyNext.java:202)            at android.view.View.performClick(View.java:4222)            at android.view.View$PerformClick.run(View.java:17624)            at android.os.Handler.handleCallback(Handler.java:800)            at android.os.Handler.dispatchMessage(Handler.java:100)            at android.os.Looper.loop(Looper.java:194)            at android.app.ActivityThread.main(ActivityThread.java:5398)            at java.lang.reflect.Method.invokeNative(Native Method)            at java.lang.reflect.Method.invoke(Method.java:525)            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:836)            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:603)            at dalvik.system.NativeStart.main(Native Method)</span>

可以从两个方向去考虑,第一,在调用unregisterReceiver之前是否没有调用registerReceiver方法,第二,两个方法中的参数是否为同一个。。。如果是第一种情况,可以向处理service出现异常时的解决方案一样,在调用unregisterReceiver方法时进行try/catch,
try {                    unregisterReceiver(mBroadCastReceiver);                }catch (IllegalArgumentException e){                    //广播未注册时的处理代码               } 

注册广播有两种方式,各有利弊

1,在xml中注册,属于常驻型广播,广播在应用开启前注册,在应用结束后,仍旧存在,不随着activity的结束而终止

2,在代码中注册,属于非常驻型,存活周期受activity影响,方便管理

总结:

     面试必备的一个问题:如何去避免anr?anr是说程序无响应,是由于耗时操作造成 的,那么如何更好的避免呢?

    首先,哪些属于耗时操作?    网络操作,大文件的拷贝,阻塞式的请求等属于耗时操作。。

     activity属于可视化的用户交互界面,在activity的UI线程中执行耗时操作,或造成卡顿现象,直接影响用户体验,可以在activity中开启线程去进行耗时操作, 用AsyncTask解决。

      广播接收器的onReceive方法执行时间特别短只有不到10s,这也就意味着无法在广播接收器中进行耗时操作,而且因为onReceive方法时间太短也无法去开启子线程来进行耗时操作,所以可以在onReceive方法中开启服务,在服务中进行耗时操作。


4,ContentProvider,内容提供者,两个程序之间共享私有数据












1 0
原创粉丝点击