现在的位置: 首页 > 综合 > 正文

结合开发知识点积累

2018年06月09日 ⁄ 综合 ⁄ 共 7792字 ⁄ 字号 评论关闭

一、Intent 和PendingIntent区别

1、Intent:及时启动的意图,Intent一般是用作Activity、Sercvice、BroadcastReceiver之间传递数据

      例如:启动activity:startActivity(intent); 启动服务:startService(intent)\bindService(intent); 发送广播:sendBroadcast(intent)。相应的activity 、service、广播接收器只要设置响应的过滤器里的action就可以接收到。

2、PendingIntent:延时的意图,可以理解为延迟执行的intent,PendingIntent是对Intent一个包装。主要使用在:通知Notificatio的发送,短消息SmsManager的发送和警报器AlarmManager的执行 。

要得到一个pendingIntent对象,使用方法类的静态方法getActivity(intent)、getBroadcast(intent)、getService(intent)分别对应着打开一个activity、发送一个广播、启动一个服务。

、NotificationManager 通知管理器

实现流程:

1、创建通知:Notification notification = new Notification(icon,title,when);参数为通知的图标、标题(当通知发出时在状态栏显示的内容)和什么时候发出,立刻发出的话为System.currentTimeMillis()

2、为通知对象notification添加一个意图intent,当点击这个通知时,会根据这个意图打开一个activity

 Intent intent = new Intent(action);//创建一个意图

 //因为是要延时显示,所以要把这个意图包裹成延时意图。意图要发送给activity就用PendingIntent.getActivity来包装,要是发送给广播接收器则用getBroadcast来包装。

 PendingIntent mPI= PendingIntent.getBroadcast(this,0,intent,0);

 3、绑定延时意图PendingIntent以及设置在通知栏列表的显示信息。

 notification.setLastestEnventInfo(this,title,content,mPI);

4、通过系统的通知管理器发送通知:

  NotificationManager mNF = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

 mNF.notify(id,notification);

总结:获取系统通知管理器-》创建通知-》设置通知将要调用的activity-》发送通知

三、activity生命周期

onCreat():创建,初始化成员变量等:不可见、不可操作。

onStart():启动,可见但不可操作。

onResume():复活、活动,可见可操作。在系统的activity栈的最上层

onPause():暂停,可见但不可操作,有别的activity挡住,只部分可见。

onStop():停止,不可见不可操作,被别的activity全部遮挡。当前面的activity关闭后,进入onRestart()状态,并进入onStart()->onResume()恢复活动状态。

onDestroy():销毁。

注意:状态成对出现。

onCreat()和onDestroy():经过了摧毁的activity,在激活需要重新创建。

onStart()和onStop():经过停止的activity,在激活需要重新启动。

onResume()和onPause():经过暂停的activity,在激活需要重新恢复Resume。

四、service生命周期及两种启动方式的区别

service同activity的生命周期类似,但由于service没有界面,所以就没有onResume()、onPause()、onStop()等同界面有关的状态

1、通过startService()方法启动的服务:

      若是第一次:onCreat()->onStart() ->service running服务运行状态-->onDestory();当第二次时,则不需要重新创建。

     通过startService()方法启动的服务于调用者没有关系,即使调用者关闭了,服务仍然运行,想要关闭服务要调用stopService(),此时系统会调用onDestory(),使用此方法启动时,服务首次启动系统先调用服务的onCreate()-->onStart(),如果服务已经启动再次调用只会触发onStart()方法。

2、使用bindService()启动的服务:

    onCreat()->onBind() ->service被绑定运行状态->onUnbind()-->onDestory();

使用bindService()启动的服务与调用者绑定,只要调用者全部关闭服务就终止,使用此方法启动时,服务首次启动系统先调用服务的onCreate()-->onBind(),如果服务已经启动再次调用不会再触发这2个方法。当所有的调用者都关闭或调用unbindService(),则服务由系统依次调用onUnbind()-->onDestory(); 服务有系统关闭。

区别:

1、应用场景不同:startService()一般在一个应用中调用,bindService()一般在进程间调用。

2、调用者同服务的关系不同:startService()服务一旦启动同调用者没有关系,即使调用者关闭,服务照常运行,bindService()只要所有的调用者都关闭,系统会把服务销毁。

3、关闭方式不同:startService():要关闭服务,只要有一个调用stopService(),就可以关闭,bindService()只有所有的调用者都关闭或都调用unbindSercice()才可关闭。

五、广播的实现

1、创建广播接收器

    public class MyBroadcastReceiver extends BroadcastReceiver

    {     public void onReceive(...) {  }   }

2、实现自己的onReceive方法:在此对接收到的广播进行处理

3、在应用中动态注册广播接收器:

      先new出一个广播接收器对象:MyBroadcastReceiver myReceiver = new MyBroadcastReceiver();

     然后设置这个广播接收器对象要过滤的action: IntentFilter intentfilter = new IntentFilter(); intentfilter.addAction(broadcastaction);

    注册这个广播接收器:this.registerReceiver(myReceiver,intentfilter);

   也可以在manifest.xml文件中静态注册:<receiver><intent-filter><action>,据说动态注册的优先级更高。

4、发送广播

     既然是通信必须先创建一个意图:Intent intent = new Intent(roadcastaction);

     发送广播:sendBroadcast(intent);

5、注销广播接收器:

   在程序不用或退出的时候要注销:this.unregisterReceiver(myReceiver)

   说明:如果通过<receiver>标签来注册的BroadcastReceiver,那么该对象的实例在onReceive被调用之后就会在任意时间内被销毁。也就是说,我们并需要担心静态注册的BroadcastReceiver的销毁问题。

六、横竖屏切换时候Activity的生命周期

几种情况:

1、禁止横竖屏切换:portrait人物、竖屏;landscape风景、横屏

   <activity android:screenOrientation = "portrait">

2、不设置configChanges参数(手机状态改变参数):切屏时会重新调用各个生命周期,横切竖时执行一次,竖切横时执行两次

3、在manifest文件中设置了<activity android:configChanges="orientation">

      横竖屏切换都执行一次

      开始生命周期:onCreat->onStart->onResume

      切换生命周期:onSaveInstanceState->onPause->onStop->onDestory->onCreat->onStart->onRestoreInstanceState->onResume

     结束生命周期:onPause->onStop->onDestory

4、在manifest文件中设置了<activity android:configChanges="orientation|keyboardHidden">

    切屏时不会重新调用各个生命周期,只会调用onConfigurationChanged方法

   另外,要注意版本问题,据说在4.0版本要加个screenSize参数才能不重新调用各个生命周期。

总结一下整个Activity的生命周期 :

补充一点,当前Activity产生事件弹出Toast和AlertDialog的时候Activity的生命周期不会有改变

Activity运行时按下HOME键(跟被完全覆盖是一样的):onSaveInstanceState --> onPause --> onStop       onRestart -->onStart--->onResume

Activity未被完全覆盖只是失去焦点:onPause--->onResume

 七、android 中MVC的理解

V(view):视图是负责生成应用程序用户界面的部分,接收用户输入,显示处理结果。

M(model):模型业务逻辑层,数据库访问、计算等业务逻辑在该层实现。

C(control):控制层,根据用户的输入和业务处理结果控制界面显示,同时把用户的输入传递给模型层处理。

1、视图层(view):一般采用XML布局文件进行界面描述。通过控制层的activity加载显示界面。

2、控制层(control):activity是控制层,不要在acitivity中写业务逻辑代码,要通过activity交割model业务逻辑层处理,这样做的另外一个原因是android中的acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。还记不记得ANR,就是基于这个原因

3、模型层(model):数据库操作、网络连接、业务逻辑等都在此处理。一般通过子线程或服务(service)实现.

八、application类的作用

android系统会为每个启动的应用创建一个application类对象用来存放信息,如PID等,通常不需要我们自己创建,由系统自动帮我们创建。在manifest文件中会看到application,其他的组件如activity、service、BroadcastReceiver都在其内。如果我们想自己创建,需要如下几个步骤:

  1、继承Application类

  2、实现其onCreate()、onTerminate()方法进行初始化和销毁工作。

 3、由于是单例模式,一定要定义个静态类变量:static MyApplication mApp;同时在onCreate()初始化中把类对象赋值:mApp=this;

 4、要在manifest文件中注册:只要在application标签中添加android:name = MyApplication这个属性就可以

定义自己的application类的目的:

 1、数据共享:application是全局对象,数据成员可以全局共享。例如百度地图应用,在application中定义一个百度地图管理器,在应用中所有的应用activity都可以调用。
 2、数据传输:进程内组件之间传递数据,如activity同activity,通过intent.putExtra(),但这个只能传递基本数据类型如int string,要传递复杂的对象类型就麻烦了。可以通过在Application中创建一个HashMap<String,Object> ,以字符串为索引,Object为value这样我们的HashMap就可以存储任何类型的对象了。在Activity A中把需要传递的对象放入这个HashMap,然后通过Intent或者其它途经再把这个索引的字符串传递给Activity
B ,Activity B 就可以根据这个字符串在HashMap中取出这个对象了。只要再向下转个型 ,就实现了对象的传递。

 3、数据缓存:比如有一个Activity需要从网站获取一些数据,获取完之后我们就可以把这个数据cache到Application 当中,当页面设置到其它Activity再回来的时候,就可以直接使用缓存好的数据了。但如果需要cache一些大量的数据,最好是cache一些 (软引用)SoftReference ,并把这些数据cache到本地rom上或者sd卡上。如果在application中的缓存不存在,从本地缓存查找,如果本地缓存的数据也不存在再从网络上获取。很多新闻阅读、网页浏览软件就是采用这种策略,如百度新闻,在有网络时加载一些新闻后,没网的时候也可以看。

九、onSaveInstanceState()和onRestoreInstanceState()什么时候被调用

 1、调用时机

A、当应用遇到意外情况(如内存不足、按了home键等),需要销毁activity时才被调用,但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。

 B、另外,当屏幕的方向发生了改变, Activity会被摧毁并且被重新创建。

 C、如果你想在Activity被摧毁前缓存一些数据,并且在Activity被重新创建后恢复缓存的数据。可以重写Activity的 onSaveInstanceState() 和 onRestoreInstanceState()方法。

具体的就是在摧毁时在onPause()前调用onSaveInstanceState(),重建时在onStart后调用onRestoreInstanceState()

2、自己实现这个方法的目的

      保存应用的一些临时状态,如视频的播放进度,百度地图的当前中心点等,使activity重建后可以恢复到销毁前的状态。

3、实现方法举例

摧毁前:protected void onSaveInstanceState(Bundle saveState){saveState.putInt("state",5)}

可以在onCreate()中提取这个值:onCreate(Bundle saveInstanceState){int state = savaInstanceState.getInt("state")}

也可以在onCreate()-》onStart()后通过onRestoreInstanceState()提取:onRestoreInstanceState(Bundle saveInstanceState){int state = saveInstanceState.getInt("state")}

注意:每个activity的onCreate()函数的参数就是已经保存的键值对Bundle saveInstanceState.

十、view、SurfaceView区别及使用场景

1、view是如何显示视图的

 每个继承自View的类,都有一个onDraw()函数,该函数在UI主线程执行,View被实例初始化时,被调用一次,实现视图显示。

视图显示要通过画布(Canvas)展现出来:我们常用的布局文件方式,是把图片绘制到你的layout中的一个View ,通过系统标准的View绘制过程处理。另外一种方式是创建自己View类,通过onDraw()函数调用,用Canvas绘制出来

2、View视图的绘图过程

     初始化视图->调用onDraw(Canvas canvas){}:在这个函数里可以在画布上画图片、画文字->在主线程内直接渲染到屏幕上。

      画图像:  canvas.drawBitmap(...),需要图片对象、图片位置、画笔参数。画笔参数可为空

      画文字:canvas.drawText(...),需要文字内容、文字位置、画笔参数,文字的颜色、大小、效果等通过画笔设置。

既然在主线程中绘画就可能造成阻塞,如果在onDraw(),添加一个线程来绘画,又不被android允许,因为android只允许在UI主线程中改变UI界面,绘画完毕后渲染到屏幕的实质就是改变UI界面。

3、SurfaceView视图的绘制过程

首先确认SurfaceView绘制也是通过Canvas绘图,然后在主UI线程中渲染到屏幕上的。SurfaceView视图有一个成员变量Surface,该成员变量又有一个Canvas对象。绘图的时候是先在后台绘图缓存到Surface里,完成后一次渲染大屏幕上。

工作过程:

获取Surface控制器:SurfaceHolder mHolder = getHolder();

启动绘图线程并通过Surface控制器获取并锁定Surface中的画布Canvas: Canvas canvas = mHolder.lockCanvas();

通过canvas在绘图线程中进行绘图操作。

绘图完成后,解锁画布,并发送Post消息给Surface,让Surface把绘制的并缓存在该Surface中的东西渲染到屏幕上:mHolder.unlockCanvasAndPost(canvas);

4、通过它们的绘图原理可以看到区别

     View:在UI的主线程中更新画面,如果更新画面时间较长或过频繁,有可能不能来及接收系统按键、触屏等事件,会引起阻塞,那么就会出现ANR错误,还记不记得

     SurfaceView:在新的子线程中更新画面操作,但不渲染到屏幕,只是缓存到Surface里,完成后再渲染到屏幕,这不会阻塞主线程。但是应用复杂而且涉及到同步。

5、应用场景:由于各有优缺点,所以在不同的场景,要用不同的方式

     被动更新或更新画面时间短:用View,如通过用户操作来更新画面,可以在用户操作事件中调用视图的更新函数:view.invalidate()进而调用View的onDraw()函数实现。

    主动更新或更新画面时间长:用SurfaceView,比如游戏由代码控制的频繁刷新界面,则用此比较合适。

抱歉!评论已关闭.