FrameLayout(帧布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局) FrameLayout 从屏幕的左上角开始布局,叠加显示, 实际应用 播放器的暂停按钮. LinearLayout 线性布局,这个东西,从外框上可以理解为一个div,他首先是一个一个从上往下罗列在屏幕上。每一个LinearLayout里面又可分为垂直布局 (android:orientation="vertical")和水平布局(android:orientation="horizontal" )。当垂直布局时,每一行就只有一个元素,多个元素依次垂直往下;水平布局时,只有一行,每一个元素依次向右排列。 AbsoluteLayout 绝对布局犹如div指定了absolute属性,用X,Y坐标来指定元素的位置android:layout_x="20px" view android:layout_y="12px" fwvga 854*480apk qq斗地主 qq游戏大厅800*480 800*480.apk fwvga 854*480 指定平板机型的游戏开发中经常用到绝对布局 widget 绝对布局 指定机型的平板游戏开发. 2.3 3.0 1. 界面布局 任务管理器 gridview 2. 手机 任务管理 listview lephone lepad RelativeLayout 相对布局可以理解为某一个元素为参照物,来定位的布局方式。主要属性有: 相对于某一个元素 android:layout_below="@id/aaa" 该元素在 id为aaa的下面 android:layout_toLeftOf="@id/bbb" 改元素的左边是bbb 相对于父元素的地方 android:layout_alignParentLeft="true" 在父元素左对齐 android:layout_alignParentRight="true" 在父元素右对齐 Android oa客户端. TableLayout 表格布局类似Html里面的Table。每一个TableLayout里面有表格行TableRow,TableRow里面可以具体定义每一个元素,设定他的对齐方式android:gravity="" 。 每一个布局都有自己适合的方式,另外,这五个布局元素可以相互嵌套应用,做出美观的界面。 oa 自动化 生成报表 ,图标 表示 webview css div webview
17.谈谈UI中,Padding和Margin有什么区别?
Padding 文字对边框, margin是控件对父窗体. Padding 盒子里面的内容距离盒子的距离 , margin 盒子与盒子之间的距离
18.请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。
简单的说,Handler 获取当前线程中的looper对象,looper用来从存放Message的MessageQueue中取出Message,再有Handler进行Message的分发和处理. Message Queue(消息队列) :用来存放通过Handler发布的消息,通常附属于某一个创建它的线程,可以通过Looper.myQueue()得到当前线程的消息队列. Handler: 可以发布或者处理一个消息或者操作一个Runnable,通过Handler发布消息,消息将只会发送到与它关联的消息队列,然也只能处理该消息队列中的消息. Looper: 是Handler和消息队列之间通讯桥梁,程序组件首先通过Handler把消息传递给Looper,Looper把消息放入队列。Looper也把消息队列里的消息广播给所有的Handler:Handler接受到消息后调用handleMessage进行处理. Message: 消息的类型,在Handler类中的handleMessage方法中得到单个的消息进行处理,在单线程模型下,为了线程通信问题,Android设计了一个Message Queue(消息队列),线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。下面将对它们进行分别介绍: 1. Message Message消息,理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。 2. Handler Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的 Handler对象引用来sendMessage(Message)。而使用Handler,需要implement 该类的 handleMessage(Message)方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。 3. Message Queue Message Queue消息队列,用来存放通过Handler发布的消息,按照先进先出执行。 每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被 Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。 4. Looper Looper是每条线程里的Message Queue的管家。Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper() 得到当前线程的Looper就有可能为NULL。对于子线程使用Looper,API Doc提供了正确的使用方法:这个Message机制的大概流程: 1. 在Looper.loop()方法运行开始后,循环地按照接收顺序取出Message Queue里面的非NULL的Message。 2. 一开始Message Queue里面的Message都是NULL的。当Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个Message对象的target属性是当前的Handler对象。随后Looper取出了那个Message,则调用该Message的target指向的Hander的dispatchMessage函数对Message进行处理。在dispatchMessage方法里,如何处理Message则由用户指定,三个判断,优先级从高到低: 1) Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作; 2) Handler里面的mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理; 3) 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。 由此可见,我们实现的handleMessage方法是优先级最低的! 3. Handler处理完该Message (update UI) 后,Looper则设置该Message为NULL,以便回收! 在网上有很多文章讲述主线程和其他子线程如何交互,传送信息,最终谁来执行处理信息之类的,个人理解是最简单的方法——判断Handler对象里面的Looper对象是属于哪条线程的,则由该线程来执行! 1. 当Handler对象的构造函数的参数为空,则为当前所在线程的Looper; 2. Looper.getMainLooper()得到的是主线程的Looper对象,Looper.myLooper()得到的是当前线程的Looper对象。
19.AIDL的全称是什么?如何工作?
AIDL的英文全称是Android Interface Define Language当A进程要去调用B进程中的service时,并实现通信,我们通常都是通过AIDL来操作的A工程:首先我们在net.blogjava.mobile.aidlservice包中创建一个RemoteService.aidl文件,在里面我们自定义一个接口,含有方法get。ADT插件会在gen目录下自动生成一个RemoteService.java文件,该类中含有一个名为RemoteService.stub的内部类,该内部类中含有aidl文件接口的get方法。说明一:aidl文件的位置不固定,可以任意然后定义自己的MyService类,在MyService类中自定义一个内部类去继承RemoteService.stub这个内部类,实现get方法。在onBind方法中返回这个内部类的对象,系统会自动将这个对象封装成IBinder对象,传递给他的调用者。其次需要在AndroidManifest.xml文件中配置MyService类,代码如下: 为什么要指定调用AIDL服务的ID,就是要告诉外界MyService这个类能够被别的进程访问,只要别的进程知道这个ID,正是有了这个ID,B工程才能找到A工程实现通信。说明:AIDL并不需要权限B工程: 首先我们要将A工程中生成的RemoteService.java文件拷贝到B工程中,在bindService方法中绑定aidl服务 绑定AIDL服务就是将RemoteService的ID作为intent的action参数。 说明:如果我们单独将RemoteService.aidl文件放在一个包里,那个在我们将gen目录下的该包拷贝到B工程中。如果我们将RemoteService.aidl文件和我们的其他类存放在一起,那么我们在B工程中就要建立相应的包,以保证RmoteService.java文件的报名正确,我们不能修改RemoteService.java文件 bindService(new Inten("net.blogjava.mobile.aidlservice.RemoteService"), serviceConnection, Context.BIND_AUTO_CREATE); ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法中的service参数就是A工程中MyService类中继承了RemoteService.stub类的内部类的对象。
20.请解释下Android程序运行时权限与文件系统权限的区别。
Android程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求, 打电话,访问网络,获取坐标,读写sd卡,读写联系人等..安装的时候会提示用户… 文件系统的权限是linux权限. 比如说sharedpreference里面的Context.Mode.private Context.Mode.world_read_able Context.Mode_world_writeable 777自己 同组 其他
21.系统上安装了多种浏览器,能否指定某浏览器访问指定页面
Intent intent =newIntent(); intent.setAction("android.intent.action.VIEW"); Uri content_url =Uri.parse(" http://www.163.com "); intent.setData(content_url); intent.setClassName("com.android.browser","com.android.browser.BrowserActivity"); startActivity(intent); 只要修改以intent.setClassName("com.android.browser","com.android.browser.BrowserActivity"); 中相应的应用程序packagename 和要启动的activity即可启动其他浏览器来 uc浏览器":"com.uc.browser", "com.uc.browser.ActivityUpdate“ opera浏览器:"com.opera.mini.android", "com.opera.mini.android.Browser" qq浏览器:"com.tencent.mtt", "com.tencent.mtt.MainActivity"
22.对android主线程的运用和理解。
23.对android虚拟机的理解,包括内存管理机制垃圾回收机制。
dalvik和art区别
虚拟机很小,空间很小,谈谈移动设备的虚拟机的大小限制 16M , 谈谈加载图片的时候怎么处理大图片的, outmemoryException BitmapFactory.option 垃圾回收,没有引用的对象,在某个时刻会被系统gc掉 . Dalvik和标准Java 虚拟机 (JVM)首要差别 Dalvik 基于 寄存器 ,而 JVM 基于栈。 基于 寄存器 的 虚拟机 对于编译后变大的程序来说,在它们执行的时候,花费的时间更短。 Dalvik和Java运行环境的区别 1:Dalvik主要是完成对象生命周期管理, 堆栈 管理,线程管理,安全和异常管理,以及 垃圾回收 等等重要功能。 2:Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik 虚拟机 实例,其代码在虚拟机的解释下得以执行。 3:不同于Java 虚拟机 运行java 字节码 ,Dalvik虚拟机运行的是其专有的 文件格式 Dex 4:dex 文件格式 可以减少整体文件尺寸,提高I/o操作的类查找速度。 5:odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化。 6:所有的Android应用的线程都对应一个Linux线程, 虚拟机 因而可以更多的依赖 操作系统 的 线程调度 和管理机制 7:有一个特殊的 虚拟机 进程Zygote,他是虚拟机实例的孵化器。它在系统启动的时候就会产生,它会完成 虚拟机 的初始化,库的加载,预制类库和初始化的操作。如果系统需要一个新的 虚拟机 实例,它会迅速复制自身,以最快的数据提供给系统。对于一些只读的系统库,所有 虚拟机 实例都和Zygote共享一块内存区域。 8:Dalvik是由Dan Bornstein编写的,名字来源于他的祖先曾经居住过名叫Dalvík的小渔村,村子位于冰岛Eyjafjörður 许多GC实现都是在对象开头的地方留一小块空间给GC标记用。Dalvik VM则不同,在进行GC的时候会单独申请一块空间,以位图的形式来保存整个堆上的对象的标记,在GC结束后就释放该空间。 dalvik是执行的时候编译+运行,安装比较快,开启应用比较慢,应用占用空间小ART是安装的时候就编译好了,执行的时候直接就可以运行的,安装慢,开启应用快,占用空间大用个比喻来说就是,骑自行车dalvik 是已经折叠起来的自行车,每次骑都要先组装自行车才能骑ART 是已经组装好的自行车,每次骑直接上车就能走人效率高在开启的时候,运行中的速度是差不多的
24.Framework工作方式及原理,Activity是如何生成一个view的,机制是什么。
主要用到反射和代理的知识。主要用pull解析xml,然后通过反射得到属性,在onDrew画出来 反射 , 配置文件 可以讲下activity的源码,比如说 每个activity里面都有window.callback和keyevent.callback,一些回调的接口或者函数吧. 框架把activity创建出来就会调用里面的这些回调方法,会调用activity生命周期相关的方法. Activity创建一个view是通过ondraw 画出来的, 画这个view之前呢,还会调用onmeasure方法来计算显示的大小.
25.android本身的一些限制,比如apk包大小限制,读取大文件时的时间限
这个问题问的有问题, apk包大小限制不好说, 极品飞车有100M 还是能装到手机上, 世面google market 上大程序 主程序 很小 5~10M 下载sdcard 200~300M 15分钟之内 申请退款 apk包,精简包, 素材存放在服务器. 游戏程序. 读大文件的时间限制应该是main线程里面的时间限制吧.5秒.
26.Android程序与Java程序的区别?
Android程序用android sdk开发,java程序用javasdk开发. Android SDK引用了大部分的Java SDK,少数部分被Android SDK抛弃,比如说界面部分,java.awt swing package除了java.awt.font被引用外,其他都被抛弃,在Android平台开发中不能使用。 android sdk 添加工具jar httpclient , pull opengl 将Java 游戏或者j2me程序移植到Android平台的过程中, Android SDK 与Java SDK的区别是很需要注意的地方。 sampleDataAdpter("YY-MM-DD")
27.Android中Task任务栈的分配
首先我们来看下Task的定义,Google是这样定义Task的:a task is what the user experiences as an "application." It's a group of related activities, arranged in a stack. A task is a stack of activities, not a class or an element in the manifest file. 这意思就是说Task实际上是一个Activity栈,通常用户感受的一个Application就是一个Task。从这个定义来看,Task跟Service或者其他Components是没有任何联系的,它只是针对Activity而言的。 Activity有不同的启动模式, 可以影响到task的分配 Task,简单的说,就是一组以栈的模式聚集在一起的Activity组件集合。它们有潜在的前后驱关联,新加入的Activity组件,位于栈顶,并仅有在栈顶的Activity,才会有机会与用户进行交互。而当栈顶的Activity完成使命退出的时候,Task会将其退栈,并让下一个将跑到栈顶的Activity来于用户面对面,直至栈中再无更多Activity,Task结束。
事件
Task栈(粗体为栈顶组件)
点开Email应用,进入收件箱(Activity A)
A
选中一封邮件,点击查看详情(Activity B)
AB
点击回复,开始写新邮件(Activity C)
ABC
写了几行字,点击选择联系人,进入选择联系人界面(Activity D)
ABCD
选择好了联系人,继续写邮件
ABC
写好邮件,发送完成,回到原始邮件
AB
点击返回,回到收件箱
A
退出Email程序
null
如上表所示,是一个实例。从用户从进入邮箱开始,到回复完成,退出应用整个过程的Task栈变化。这是一个标准的栈模式,对于大部分的状况,这样的Task模型,足以应付,但是,涉及到实际的性能、开销等问题,就会变得残酷许多。 比如,启动一个浏览器,在Android中是一个比较沉重的过程,它需要做很多初始化的工作,并且会有不小的内存开销。但与此同时,用浏览器打开一些内容,又是一般应用都会有的一个需求。设想一下,如果同时有十个运行着的应用(就会对应着是多个Task),都需要启动浏览器,这将是一个多么残酷的场面,十个Task栈都堆积着很雷同的浏览器Activity, 是多么华丽的一种浪费啊。 于是你会有这样一种设想,浏览器Activity,可不可以作为一个单独的Task而存在,不管是来自那个Task的请求,浏览器的Task,都不会归并过去。这样,虽然浏览器Activity本身需要维系的状态更多了,但整体的开销将大大的减少,这种舍小家为大家的行为,还是很值得歌颂的 standard", "singleTop", "singleTask", "singleInstance"。 standard模式, 是默认的也是标准的Task模式,在没有其他因素的影响下,使用此模式的Activity,会构造一个Activity的实例,加入到调用者的Task栈中去,对于使用频度一般开销一般什么都一般的Activity而言,standard模式无疑是最合适的,因为它逻辑简单条理清晰,所以是默认的选择。 而singleTop模式,基本上于standard一致,仅在请求的Activity正好位于栈顶时,有所区别。此时,配置成singleTop的Activity,不再会构造新的实例加入到Task栈中,而是将新来的Intent发送到栈顶Activity中,栈顶的Activity可以通过重载onNewIntent来处理新的Intent(当然,也可以无视...)。这个模式,降低了位于栈顶时的一些重复开销,更避免了一些奇异的行为(想象一下,如果在栈顶连续几个都是同样的Activity,再一级级退出的时候,这是怎么样的用户体验...),很适合一些会有更新的列表Activity展示。一个活生生的实例是,在Android默认提供的应用中,浏览器(Browser)的书签Activity(BrowserBookmarkPage),就用的是singleTop。 singleTask,和singleInstance,则都采取的另辟Task的蹊径。 标志为singleTask的Activity,最多仅有一个实例存在,并且,位于以它为根的Task中。所有对该Activity的请求,都会跳到该Activity的Task中展开进行。singleTask,很象概念中的单件模式,所有的修改都是基于一个实例,这通常用在构造成本很大,但切换成本较小的Activity中。最典型的例子,还是浏览器应用的主Activity(名为Browser...),它是展示当前tab,当前页面内容的窗口。它的构造成本大,但页面的切换还是较快的,于singleTask相配,还是挺天作之合的。 singleInstance显得更为极端一些。在大部分时候singleInstance与singleTask完全一致,唯一的不同在于,singleInstance的Activity,是它所在栈中仅有的一个Activity,如果涉及到的其他Activity,都移交到其他Task中进行。这使得singleInstance的Activity,像一座孤岛,彻底的黑盒,它不关注请求来自何方,也不计较后续由谁执行。在Android默认的各个应用中,很少有这样的Activity,在我个人的工程实践中,曾尝试在有道词典的快速取词Activity中采用过, 是因为我觉得快速取词入口足够方便(从notification中点选进入),并且会在各个场合使用,应该做得完全独立。 大的apk 拆成 很多小的apk ●Activity的android:affinity属性 1.配置后 当启动这个activity时就先去找有没有activity的亲和力属性相同 有就加入这个 activity所在的任务中没有就新开任务 2.affinity起作用需要的条件而者具备一个: 1.intent包含FLAG_ACTIVITY_NEW_TASK标记 2.activity元素启用了allowTaskReparenting属性.
28.在Android中,怎么节省内存的使用,怎么主动回收内存?
回收已经使用的资源, 合理的使用缓存 合理设置变量的作用范围… application 对象 //未来的某一段时间执行 System.gc();
29.不同工程中的方法是否可以相互调用?
30.dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念 是同一概念
Dvm的进程是dalivk虚拟机进程,每个android程序都运行在自己的进程里面, 每个android程序系统都会给他分配一个单独的liunx uid(user id), 每个dvm都是linux里面的一个进程.所以说这两个进程是一个进程 .
31.在Android中是如何实现判断区分电话的状态,去电,来电、未接来电?
Day8 showAddressService.java TelephoneyManger.listen();
32.谈谈Android的优点和不足之处。
1、开放性,开源ophone 阿里云( 完全兼容android) 2、挣脱运营商束缚 3、丰富的硬件选择 mtk android 4、不受任何限制的开发商 5、无缝结合的Google应用 缺点也有5处: 1、安全问题、隐私问题 2、卖手机的不是最大运营商 3、运营商对Android手机仍然有影响 4、山寨化严重 5、过分依赖开发商,缺乏标准配置
33.Android系统中GC什么情况下会出现内存泄露呢?
视频编解码/内存泄露 检测内存泄露 工具 导致内存泄漏主要的原因是,先前申请了内存空间而忘记了释放。如果程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器GC验证这些对象是否不再需要。如果存在对象的引用,这个对象就被定义为"有效的活动",同时不会被释放。要确定对象所占内存将被回收,我们就要务必确认该对象不再会被使用。典型的做法就是把对象数据成员设为null或者从集合中移除该对象。但当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理。 Java带垃圾回收的机制,为什么还会内存泄露呢? Vector v = new Vector(10); for (int i = 1; i < 100; i++) { Object o = new Object(); v.add(o); o = null; }//此时,所有的Object对象都没有被释放,因为变量v引用这些对象。 Java 内存泄露的根本原因就是 保存了不可能再被访问的变量类型的引用
34.Android UI中的View如何刷新。
在主线程中 拿到view调用Invalide()方法,查看画画板里面更新imageview的方法 在子线程里面可以通过postInvalide()方法;
35. 简单描述下Android 数字签名。
Android 数字签名 在Android系统中,所有安装到系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程序之间建立信任关系 Android系统要求每一个安装进系统的应用程序都是经过数字证书签名的,数字证书的私钥则保存在程序开发者的手中。Android将数字证书用来标识应用程序的作者和在应用程序之间建立信任关系,不是用来决定最终用户可以安装哪些应用程序。 这个数字证书并不需要权威的数字证书签名机构认证(CA),它只是用来让应用程序包自我认证的。 同一个开发者的多个程序尽可能使用同一个数字证书,这可以带来以下好处。 (1)有利于程序升级,当新版程序和旧版程序的数字证书相同时,Android系统才会认为这两个程序是同一个程序的不同版本。如果新版程序和旧版程序的数字证书不相同,则Android系统认为他们是不同的程序,并产生冲突,会要求新程序更改包名。 (2)有利于程序的模块化设计和开发。Android系统允许拥有同一个数字签名的程序运行在一个进程中,Android程序会将他们视为同一个程序。所以开发者可以将自己的程序分模块开发,而用户只需要在需要的时候下载适当的模块。 在签名时,需要考虑数字证书的有效期: (1)数字证书的有效期要包含程序的预计生命周期,一旦数字证书失效,持有改数字证书的程序将不能正常升级。 (2)如果多个程序使用同一个数字证书,则该数字证书的有效期要包含所有程序的预计生命周期。 (3)Android Market强制要求所有应用程序数字证书的有效期要持续到2033年10月22日以后。 Android数字证书包含以下几个要点: (1)所有的应用程序都必须有数字证书,Android系统不会安装一个没有数字证书的应用程序 (2)Android程序包使用的数字证书可以是自签名的,不需要一个权威的数字证书机构签名认证 (3)如果要正式发布一个Android ,必须使用一个合适的私钥生成的数字证书来给程序签名,而不能使用adt插件或者ant工具生成的调试证书来发布。 (4)数字证书都是有有效期的,Android只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。
36.android中的动画有哪几类,它们的特点和区别是什么?
两种,一种是Tween动画、还有一种是Frame动画。 Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化; 可以通过布局文件,可以通过代码 1、 控制View的动画 a) alpha(AlphaAnimation) 渐变透明 b) scale(ScaleAnimation) 渐变尺寸伸缩 c) translate(TranslateAnimation) 画面转换、位置移动 d) rotate(RotateAnimation) 画面转移,旋转动画 2、 控制一个Layout里面子View的动画效果 a) layoutAnimation(LayoutAnimationController) b) gridAnimation(GridLayoutAnimationController) 另一种Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。
37.说说mvc模式的原理,它在android中的运用
Android中没有mvc,只有在j2ee中有,是用于逻辑也界面分离的 MVC英文即Model-View-Controller,即把一个应用的输入、处理、输出流程按照Model、View、Controller的方式进行分离,这样一个应用被分成三个层——模型层、视图层、控制层。 Android中界面部分也采用了当前比较流行的MVC框架,在Android中M就是应用程序中二进制的数据,V就是用户的界面。Android的界面直接采用XML文件保存的,界面开发变的很方便。在Android中C也是很简单的,一个Activity可以有多个界面,只需要将视图的ID传递到setContentView(),就指定了以哪个视图模型显示数据。 在Android SDK中的数据绑定,也都是采用了与MVC框架类似的方法来显示数据。在控制层上将数据按照视图模型的要求(也就是Android SDK中的Adapter)封装就可以直接在视图模型上显示了,从而实现了数据绑定。比如显示Cursor中所有数据的ListActivity,其视图层就是一个ListView,将数据封装为ListAdapter,并传递给ListView,数据就在ListView中显示。
38.通过点击一个网页上的url 就可以完成程序的自动安装,描述下原理
Day11 AddJavascriptInterface new Object{ callphone(); installapk(); } 将js与java相互调用再来一个例子,解决相互调用之间的关系。 首先说明一重要代码的情况: android中的关键代码 : webview.getSettings().setJavaScriptEnabled(true); webview.addJavascriptInterface(object,"name"); //把Name="name" 的对象添加到object中。object如果是this,就是window.name webview.loadUrl("file:///android_asset/index.html"); //注意这个资源的位置放在assets文件夹下。 js或html中调用android中方法代码: js中使用 window.name.java中的方法(); android中调用js的function方法: Callfunction(){ webview.loadUrl("javascript: function ()"); 需要注意的地方,很多数据类型js中不认识,最好是在android那边封装好,提供必要的方法接口。比如传到js中的list,在js中是没办法去得到里面的元素的。 addJavascriptInterface:addJavascriptInterface方法中要绑定的Java对象及方法要运行在另外的线程中,不能运行在构造他的线程中,也就是说不能运行在当前的activity线程中,就是把这个方法绑定到页面中,js也可以调用。 文档中的解释: Use this function to bind an object to Javascript so that the methods can be accessed from Javascript. The Java object that is bound runs in another thread and not in the thread that it was constructed in. 下面给出具体的测试代码: 1、Activity 代码 [java] view plaincopyprint? public class TestWebView extends Activity { private WebView mWebView; private List list; private int mkeyCode; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); mWebView = (WebView) findViewById(R.id.htmlview); initData(); WebSettings webSettings = mWebView.getSettings(); // 是否允许在webview中执行javascript webSettings.setJavaScriptEnabled( true ); mWebView.addJavascriptInterface( this , "javatojs" ); //加载网页 mWebView.loadUrl( "file:///android_asset/index.html" ); } @Override public boolean onKeyUp( int keyCode, KeyEvent event) { mkeyCode = keyCode; Log.i( "AA" , "keyCode=" +keyCode); mWebView.loadUrl( "javascript: OnKeyUp()" ); return super .onKeyUp(keyCode, event); } public int getKeyCode(){ return mkeyCode; } void initData() { list = new ArrayList(); for ( int i = 0 ; i < 5 ; i++) { list.add( "我是List中的第" + (i + 1 ) + "行" ); } } /** * 该方法将在js脚本中,通过window.javatojs.....()进行调用 * * @return */ public Object getObject( int index) { Log.i( "A" , "getObject" ); return list.get(index); } public int getSize() { Log.i( "A" , "getSize" ); return list.size(); } public void Callfunction() { Log.i( "A" , "Callfunction" ); mWebView.loadUrl( "javascript: GetList()" ); } public void printStr(String str){ Log.i( "A" , "GetList:" + str); } } 2、js 代码 index.html [javascript] view plaincopyprint? "-//W3C//DTD HTML 4.0 Transitional//EN" > "Content-Type" content= "text/html; charset=UTF-8" > demotitle> "background-color:#000;" > "400" align= "center" >
以上代码主要测试js与java相互调用,而由于按键这种系统事件被webview截获掉,有如下两种方式进行处理 1、把方向键的流程改成:先传给webcore,假如没处理,再在webview里面处理,这个需要修改webview.java代码 2、直接应用搞定,java捕获按键,然后调js函数,上面代码就是使用这种方法。 测试结果如下: 点击buttons按钮: I/A ( 4990): Callfunction I/A ( 4990): getSize I/A ( 4990): getObject I/A ( 4990): GetList:test I/A ( 4990): getObject I/A ( 4990): GetList:test I/A ( 4990): getObject I/A ( 4990): GetList:test I/A ( 4990): getObject I/A ( 4990): GetList:test I/A ( 4990): getObject I/A ( 4990): GetList:test you press KEY_RIGHT I/AA ( 4990): keyCode=22 I/A ( 4990): GetList:22 you press KEY_UP I/AA ( 4990): keyCode=19 I/A ( 4990): GetList:19 you press KEY_DOWN I/AA ( 4990): keyCode=20 I/A ( 4990): GetList:20 you press KEY_LEFT I/AA ( 4990): keyCode=21 I/A ( 4990): GetList:21 这里为何使用这种方式,是因为对于上下左右及确定这种功能键被webview截取掉了,无法传递到webcore中,而只能重载OnKeyDown/OnKeyUp方法,再由js调用java方法来获取得。 对于数字键的处理可以直接在js中进行处理: logcat中会有明显的打印,对于这些键没有截掉,所以可以直接获取得到: D/webcore ( 4990): proc key: code=12 D/webcore ( 4990): proc key: nativeKey return false D/webcore ( 4990): proc key: nativeKey return true js代码可以如此编写: [javascript] view plaincopyprint?
39.Service和Activity在同一个线程吗
40.ViewStub的应用
在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为 View . GONE ,然后在代码中动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是,耗费资源。虽然把View的初始可见 View . GONE 但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。 推荐的做法是使用 android.view.ViewStub ,ViewStub是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的在运行时,要还是不要显示某个布局。 但ViewStub也不是万能的,下面总结下ViewStub能做的事儿和什么时候该用ViewStub,什么时候该用可见性的控制。 首先来说说ViewStub的一些特点: 1. ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。 2. ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。 基于以上的特点,那么可以考虑使用ViewStub的情况有: 1. 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。 因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。 2. 想要控制显示与隐藏的是一个布局文件,而非某个View。 因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。 所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。 下面来看一个实例 在这个例子中,要显示二种不同的布局,一个是用TextView显示一段文字,另一个则是用ImageView显示一个图片。这二个是在onCreate()时决定是显示哪一个,这里就是应用ViewStub的最佳地点。 先来看看布局,一个是主布局,里面只定义二个ViewStub,一个用来控制TextView一个用来控制ImageView,另外就是一个是为显示文字的做的TextView布局,一个是为ImageView而做的布局: [html] view plaincopyprint? version = "1.0" encoding = "utf-8"?> xmlns:android = " http://schemas.android.com/apk/res/android " android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:gravity = "center_horizontal"]] > android:id = "@+id/viewstub_demo_text" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginLeft = "5dip" android:layout_marginRight = "5dip" android:layout_marginTop = "10dip" android:layout = "@layout/viewstub_demo_text_layout"/> android:id = "@+id/viewstub_demo_image" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginLeft = "5dip" android:layout_marginRight = "5dip" android:layout = "@layout/viewstub_demo_image_layout"/> 为TextView的布局: [html] view plaincopyprint? version = "1.0" encoding = "utf-8"?> xmlns:android = " http://schemas.android.com/apk/res/android " android:orientation = "vertical" android:layout_width = "wrap_content" android:layout_height = "wrap_content"]] > android:id = "@+id/viewstub_demo_textview" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:background = "#aa664411" android:textSize = "16sp"/> 为ImageView的布局: [html] view plaincopyprint? version = "1.0" encoding = "utf-8"?> xmlns:android = " http://schemas.android.com/apk/res/android " android:orientation = "vertical" android:layout_width = "wrap_content" android:layout_height = "wrap_content"]] > android:id = "@+id/viewstub_demo_imageview" android:layout_width = "wrap_content" android:layout_height = "wrap_content"/> 下面来看代码,决定来显示哪一个,只需要找到相应的ViewStub然后调用其infalte()就可以获得相应想要的布局: [java] view plaincopyprint? package com.effective; import android.app.Activity; import android.os.Bundle; import android.view.ViewStub; import android.widget.ImageView; import android.widget.TextView; public class ViewStubDemoActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.viewstub_demo_activity); if (((( int ) (Math.random() * 100 )) & 0x01 ) == 0 ) { // to show text // all you have to do is inflate the ViewStub for textview ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_text); stub.inflate(); TextView text = (TextView) findViewById(R.id.viewstub_demo_textview); text.setText( "The tree of liberty must be refreshed from time to time" + " with the blood of patroits and tyrants! Freedom is nothing but " + "a chance to be better!" ); } else { // to show image // all you have to do is inflate the ViewStub for imageview ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_image); stub.inflate(); ImageView image = (ImageView) findViewById(R.id.viewstub_demo_imageview); image.setImageResource(R.drawable.happy_running_dog); } } } 运行结果: 使用的时候的注意事项: 1. 某些布局属性要加在ViewStub而不是实际的布局上面,才会起作用,比如上面用的android:layout_margin*系列属性,如果加在TextView上面,则不会起作用,需要放在它的ViewStub上面才会起作用。而ViewStub的属性在inflate()后会都传给相应的布局。
41.android开发中怎么去调试bug
逻辑错误 1.断点 debug 2. logcat , 界面布局,显示 hierarchyviewer.bat
42.书写出android工程的目录结构以及相关作用
下面是HelloAndroid项目在eclipse中的目录层次结构: 由上图可以看出项目的根目录下共有九个文件(夹),下面就这九个文件(夹)进行详解: 1.1src文件夹和assets文件夹: 每个Android程序都包含资源目录(src)和资产目录(assets),资源和资产听起来感觉没有多大差别,但在存储外部内容时用资源(src)比较多,其中它们的区别在于存放在资源(src)下的内容可以通过应用程序的R类进行访问,而存放在资产(assets)下的内容会保持原始文件的格式,如果需要访问,则必须使用AssetManager以字节流的方式来读取,用起来非常的不方便。为了方便使用,通常文件和数据都会保存在资源(src)目录下 1.2res(Resource)目录:资源目录 可以存放一些图标,界面文件和应用中用到的文字信息,下图为res目录截图: 1.2.1 drawable-*dpi文件夹:将图标按分辨率的高低放入不同的目录,其中draeable-hdpi用来存放高分辨率的图标,drawable-mdpi用来存放中等分辨率的图标,drawable-ldpi用来存放低分辨率的图标 1.2.2 values文件夹:用来存放文字的信息 (1)strings.xml:用来定义字符串和数值 "1.0"encoding="utf-8" ?> "hello">Hello World, Hello 3G "app_name">Android1.1 "test">哥想你了 "startButton">按钮1 "start">按钮1 每个string标签生命了一个字符串,name属性指定它的引用值 (2)为什么要把这些出现的文字单独放在strings.xml文件中? 答案:一是为了国际化,如果需要将文件中的文字换成别的国家的语言,就可以只需要替换掉一个strings.xml文件就可以了 二是为了减少应用的体积,例如,我们要在应用中使用“哥想你了”这句话1000次,如果我们没有将“哥想你了”定义在strings.xml文件中,而是直接在应用中使用时写上这几个字,那么我们就会在应用中写4000个字。4000个字和4个字占用的内存可是有很大差距的啊,况且手机的内存本来就小,所以应该是能省就省 (3)另外还有arrays.xml,color.xml等定义数组,颜色的,都最好用单独的一个xml文档 1.2.3 layout文件:用来存放界面信息 本例中的布局文件是自动生成的“main.xml” "1.0"encoding="utf-8" ?> " http://schemas.android.com/apk/res/android " android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/test" /> 元素:线性布局的意思,在该元素下的所有子元素都会根据他的”orientation”属性来决定是按行还是按列或者按逐个显示进行布局的 元素:是一种显示控件,他的”text”属性指定了在这个元素上显示的内容 1.3 gen目录:gen目录下只有一个自动生成的“R.java”文件 /*AUTO-GENERATED FILE. DO NOT MODIFY. * * This class was automatically generated bythe * aapt tool from the resource data itfound. It * should not be modified by hand. */ package cn.csdn.android.demo; public final class R { public static final class attr { } public static final class drawable { public static final int ic_launcher=0x7f020000; } public static final class id { public static final int button1=0x7f050000; public static final int radioButton1=0x7f050001; public static final int toggleButton1=0x7f050002; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; public static final int start=0x7f040004; public static final int startButton=0x7f040003; public static final int test=0x7f040002; } } R.java文件:默认有attr,drawable,layout,string这四个静态内部类,每个静态内部类对应一中资源,如layout静态内部类对应layout中的界面文件,string静态内部类对应string内部的string标签。如果在layout中在增加一个界面文件或者在string内增加一个string标签,R.java会自动在其对应的内部类增加所增加的内容。 R.java除了自动标识资源的索引功能外,还有另一个功能,就是当res文件中的某个资源在应用中没有被用到,在这个应用被编译时,系统不会把对应的资源编译到应用中的APR包中。 1.4 AndroidManifest.xml 功能清单文件 每个应用程序都会有一个Android Manifest 在它的根目录里面。这个清单为Android系统提供了这个应用的基本信息,系统在运行之前必须知道这些信息,另外,如果我们使用系统自带的服务,如拨号服务,应用安装服务等,都必须在AndroidManifest.xml文件中声明权限 AndroidManifest.xml的功能: 命名应用程序的Java应用包,这个包名用来唯一标识应用程序; 描述应用程序的组件,对实现每个组件和公布其功能的类进行命名,这些声明使得Android系统了解这些组件以及它们在什么条件下可以被启动 决定哪个组件运行在哪个进程里面 声明应用程序必须具备的权限,用以访问受保护的API,以及和其他进程的交互 声明应用程序其他的必备权限,用以组件之间的交互 列举application所需要链接的库 以HelloAndroid项目的功能清单为例子进行讲解: "1.0"encoding="utf-8" ?> " http://schemas.android.com/apk/res/android " package="cn.csdn.android.demo" android:versionCode="1" android:versionName="1.0" > "8"/> android:icon="@drawable/ic_launcher" android:label="@string/app_name" > android:label="@string/app_name" android:name=".HelloActivity" > "android.intent.action.MAIN" /> "android.intent.category.LAUNCHER" /> 1.4.1 元素 " http://schemas.android.com/apk/res/android " package="cn.csdn.android.demo" android:versionCode="1" android:versionName="1.0" > 元素是AndroidManifest.xml的根元素,”xmlns:android”是指该文件的命名空间,“package”属性是Android应用所在的包,“android:versionCode”指定应用的版本号,如果应用不断升级,则需要修改这个值,”android:versionName”是版本的名称,这个可以根据自己的喜爱改变 1.4.2 元素 android:icon="@drawable/ic_launcher" android:label="@string/app_name" > android:label="@string/app_name" android:name=".HelloActivity" > "android.intent.action.MAIN"/> "android.intent.category.LAUNCHER" /> 元素是一个很重要的元素,开发组件都会在此下定义 元素的”icon”属性是用来设定应用的图标,其中“@drawable/ic_launcher”的意思是:在R.java文件中的drawable静态内部类下的icon,如下图所示 元素的“label”属性用来设定应用的名称,其中“@string/app_name”和上述的一样,也是R.java文件中的string静态内部类下的app_name 1.4.3 元素 android:label="@string/app_name" android:name=".HelloActivity" > "android.intent.action.MAIN" /> "android.intent.category.LAUNCHER" /> 元素的作用是注册一个activity信息,当我们在创建“HelloAndroid”这个项目时,指定了“Created Activity”属性为“HelloActivity”,然后ADT在生成项目时帮我们自动创建了一个Activity,就是“HelloActivity.java”; 元素的“name“属性指定的是Activity的类名,其中“.HelloActivity”中的“.”指的是元素中的“package”属性中指定的当前包,所以“.HelloActivity”就相当于“cn.csdn.android.demo.HelloActivity.java ”,如果Activity在应用的包中可以不写“.”,但是为了避免出错,还是写上这个点把 1.4.4元素 "android.intent.action.MAIN" /> "android.intent.category.LAUNCHER" /> 如果直接翻译的话是“意图过滤器”,组件通过告诉它们所具备的功能,就是能响应意图类型,在intent中设置action, data, categroy之后在对应的intentfilter中设置相同的属性即可通过过滤被activity调用 1.5应用要求运行的最低Android版本 1.6 存放Android自身的jar包
43.ddms 和traceview的区别.
daivilk debug manager system 1.在应用的主activity的onCreate方法中加入Debug.startMethodTracing("要生成的traceview文件的名字"); 2.同样在主activity的onStop方法中加入Debug.stopMethodTracing(); 3.同时要在AndroidManifest.xml文件中配置权限 3.重新编译,安装,启动服务,测试完成取对应的traceview文件(adb pull /sdcard/xxxx.trace)。 4.直接在命令行输入traceview xxxxtrace,弹出traceview窗口,分析对应的应用即可。 traceview 分析程序执行时间和效率 KPI : key performance information : 关键性能指标: splash界面不能超过5秒 从splash 界面加载mainactivity 不能超过0.7秒
44.谈谈NDK
NDK全称:Native Development Kit。 1、NDK是一系列工具的集合。 * NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。 [1] * NDK集成了 交叉编译器 ,并提供了相应的mk文件隔离平台、CPU、API等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。 * NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。 2、NDK提供了一份稳定、功能有限的API头文件声明。 Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。
45.请介绍下Android的数据存储方式。
一.SharedPreferences方式 二sdcard 三内部存储 四SqliteDatabase 五. 网络存储方式
46.谈谈推送,优缺点以及实现原理
本文主旨在于,对目前Android平台上最主流的几种消息推送方案进行分析和对比,比较客观地反映出这些推送方案的优缺点,帮助大家选择最合适的实施方案。 方案1、 使用GCM服务(Google Cloud Messaging) 简介:Google推出的云消息服务,即第二代的C2DM。 优点:Google提供的服务、原生、简单,无需实现和部署服务端。 缺点:Android版本限制(必须大于2.2版本),该服务在国内不够稳定、需要用户绑定Google帐号,受限于Google。 方案2、 使用XMPP协议(Openfire + Spark + Smack) 简介:基于XML协议的通讯协议,前身是Jabber,目前已由IETF国际标准化组织完成了标准化工作。 优点:协议成熟、强大、可扩展性强、目前主要应用于许多聊天系统中,且已有开源的Java版的开发实例androidpn。 缺点:协议较复杂、冗余(基于XML)、费流量、费电,部署硬件成本高。 方案3、 使用MQTT协议(更多信息见:http://mqtt.org/ ) 简介:轻量级的、基于代理的“发布/订阅”模式的消息传输协议。 优点:协议简洁、小巧、可扩展性强、省流量、省电,目前已经应用到企业领域(参考: http://mqtt.org/software ),且已有C++版的服务端组件rsmb。 缺点:不够成熟、实现较复杂、服务端组件rsmb不开源,部署硬件成本较高。 方案4、 使用HTTP轮循方式 简介:定时向HTTP服务端接口(Web Service API)获取最新消息。 优点:实现简单、可控性强,部署硬件成本低。 缺点:实时性差。 对各个方案的优缺点的研究和对比,推荐使用MQTT协议的方案进行实现,主要原因是:MQTT最快速,也最省流量(固定头长度仅为2字节),且极易扩展,适合二次开发 。接下来,我们就来分析使用MQTT方案进行Android消息的原理和方法,并架设自己的推送服务。 1、推送原理分析 实际上,其他推送系统(包括GCM、XMPP方案)的原理都与此类似。 2、推送服务端准备 a> 下载&解压rsmb安装包(下载地址: http://www.alphaworks.ibm.com/tech/rsmb ) b> 进入对应的目录,比如32位的Linux系统则应该进入linux_ia32目录。 c> 编辑配置文件broker_1883.cfg,配置如下: [html] view plaincopy port 1883 max_inflight_messages 10 max_queued_messages 1000 d> 运行./broker broker_1883.cfg,显示如下: 20120823 110454.039 CWNAN9999I Really Small Message Broker 20120823 110454.039 CWNAN9997I Licensed Materials - Property of IBM 20120823 110454.039 CWNAN9996I Copyright IBM Corp. 2007, 2010 All Rights Reserved 20120823 110454.039 CWNAN9995I US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 20120823 110454.039 CWNAN0049I Configuration file name is broker_1883.cfg 20120823 110454.040 CWNAN0053I Version 1.2.0, Aug 18 2010 17:03:35 20120823 110454.040 CWNAN0054I Features included: bridge 20120823 110454.040 CWNAN9993I Author: Ian Craggs ( [email protected] ) 20120823 110454.040 CWNAN0014I MQTT protocol starting, listening on port 1883 ... ... 这样,推送服务的服务端就已经准备好了,监听1883端口。 3、推送客户端准备 a> 下载&解压AndroidPushNotificationsDemo项目(下载地址: https://github.com/tokudu/AndroidPushNotificationsDemo ) b> 将该项目导入Eclipse中(File -> Export -> Existing Projects into Workspace) c> 修改PushService.java中的MQTT_HOST 常量为推送服务端的IP地址。 d> 启动Android模拟器,并安装该项目。 注意: 在新版本的Android SDK中可能会遇到以下错误。 ... ... 08-23 02:28:44.184: W/dalvikvm(282): VFY: unable to find class referenced in signature (Lcom/ibm/mqtt/MqttPersistence;) 08-23 02:28:44.194: I/dalvikvm(282): Failed resolving Lcom/tokudu/demo/PushService$MQTTConnection; interface 35 'Lcom/ibm/mqtt/MqttSimpleCallback;' 08-23 02:28:44.194: W/dalvikvm(282): Link of class 'Lcom/tokudu/demo/PushService$MQTTConnection;' failed 08-23 02:28:44.194: E/dalvikvm(282): Could not find class 'com.tokudu.demo.PushService$MQTTConnection', referenced from method com.tokudu.demo.PushService.connect 08-23 02:28:44.194: W/dalvikvm(282): VFY: unable to resolve new-instance 42 (Lcom/tokudu/demo/PushService$MQTTConnection;) in Lcom/tokudu/demo/PushService; ... ... 08-23 02:28:44.404: E/AndroidRuntime(282): java.lang.VerifyError: com.tokudu.demo.PushService 08-23 02:28:44.404: E/AndroidRuntime(282): at com.tokudu.demo.PushActivity$1.onClick(PushActivity.java:32) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.view.View.performClick(View.java:2408) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.view.View$PerformClick.run(View.java:8816) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.os.Handler.handleCallback(Handler.java:587) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.os.Handler.dispatchMessage(Handler.java:92) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.os.Looper.loop(Looper.java:123) 08-23 02:28:44.404: E/AndroidRuntime(282): at android.app.ActivityThread.main(ActivityThread.java:4627) 08-23 02:28:44.404: E/AndroidRuntime(282): at java.lang.reflect.Method.invokeNative(Native Method) 08-23 02:28:44.404: E/AndroidRuntime(282): at java.lang.reflect.Method.invoke(Method.java:521) 08-23 02:28:44.404: E/AndroidRuntime(282): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 08-23 02:28:44.404: E/AndroidRuntime(282): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 08-23 02:28:44.404: E/AndroidRuntime(282): at dalvik.system.NativeStart.main(Native Method) ... ... 原因是发布的时候没有加入wmqtt.jar包,解决办法如下: 1> 在项目根目录下创建libs目录,并把wmqtt.jar包移入该目录。 2> 重新配置项目的Java Build Path(右键菜单中的Properties选项中)。 3> 重新打包发布即可。 运行效果如下: 点击“Start Push Service”按钮即可开启推送服务。这时我们可以看到rsmb的服务日志中打出以下提示: 20120823 113742.297 CWNAN0033I Connection attempt to listener 1883 received from client tokudu/9774d56d682e549c on address 192.168.28.39:3345 其中的“9774d56d682e549c”就是对应的客户端ID号。 4、发送服务准备 a> 下载&解压PHP版的发送服务端代码send_mqtt.zip(下载地址: http://download.csdn.net/detail/shagoo/4520102 ) b> 修改etc/config.php中推送服务端的IP地址和端口号,即MQTT_SERVER_HOST 和MQTT_SERVER_POST 常量。 c> 打开对应的URL地址,就可以看到发送服务的界面,实际上就是向对应的推送客户端推送消息。
47.谈谈数据加密
数据加密又称密码学,它是一门历史悠久的技术,指通过 加密算法 和加密 密钥 将明文转变为密文,而解密则是通过解密算法和解密密钥将密文恢复为明文。数据加密目前仍是 计算机系统 对信息进行保护的一种最可靠的办法。它利用 密码技术 对信息进行加密,实现 信息隐蔽 ,从而起到保护信息的安全的作用。 用自己的话来说就是,只有双方才知道的协议。 数据加密 - 密码算法分类 1按发展进程分密码的发展:古典密码,对称密钥 密码公开密钥密码. 2按加密模式分对称算法:序列密码和分组密码. 经典密码 代替密码: 简单代替多名或同音代替多表代替多字母或多码代替 换位密码 : •对称加密算法 DES AES •非对称公钥算法 RSA 背包密码McEliece密码Rabin 椭圆曲线EIGamal D_H
48.解决问题和思考问题的方式
首先查看官方提供的API,通过自己对功能的理解,然后通过网络的途径,下载demo可以选择 github ,查找问题可以选择 stackover flow,然后可以问身边的朋友。
49.列举7到12个设计模式 以及它们的应用场景
设计模式,提供了很多软件工程问题所需处理的解决方案。 根据模式的目的可分为3类: 1.创建型模式:与对象的创建有关。 2.结构性模式:处理类与对象的组合。 3.行为性模式:对类或对象怎样交互和怎样 分配职责进行描述。 面向对象设计的2个基本原则: 1.针对接口编程,而不是针对实现编程。 2.优先使用对象组合,而不是类继承。 面向对象设计的5个设计原则: 1.单一职责原则(SRP) 2.开放封闭原则(OCP) 3.Liskov替换原则(LSP) 4.依赖倒置原则(DIP) 5.接口隔离原则(ISP) 23中设计模式: 1.创建型模式: (1).工厂方法模式 (2).抽象工厂模式 (3).创建者模式 (4).原型模式 (5).单例模式 2.结构型模式: (6).适配器模式 (7).桥模式 (8).组合模式 (9).装饰模式 (10).外观模式 (11).享元模式 (12).代理模式 3.行为型模式 (13).解释器模式 (14).模板方法模式 (15).职责链模式 (16).命令模式 (17).迭代器模式 (18).中介者模式 (19).备忘录模式 (20).观察者模式 (21).状态模式 (22).策略模式 (23).访问者模式 除此之外,后来人发现很多新的模式,如空模式等。 下面列举几个常见的问题导致重新设计,可能需要设计模式来分析解决: 1.通过显示的指定一个类来创建对象 2.对特殊操作的依赖 3.对硬件和软件平台的依赖 4.对对象表示或实现的依赖 5.算法依赖 6.紧耦合 7.通过生产子类来扩展功能 8.不能方便的对类进行修改 软件的设计臭味: 1.僵化性 2.脆弱性 3.顽固性 4.粘滞性 5.不必要的复杂性 6.不必要的重复 7.晦涩性 ... ... 总而言之,一句话,面向对象特性+原则+模式,折腾来折腾去就是这么个回事。 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。本章系 Java之美[从菜鸟到高手演变]系列 之设计模式,我们会以理论与实践相结合的方式来进行本章的学习,希望广大程序爱好者,学好设计模式,做一个优秀的软件工程师! 在阅读过程中有任何问题,请及时联系:egg。 邮箱:[email protected] 微博: http://weibo.com/xtfggef 如有转载,请说明出处: http://blog.csdn.net/zhangerqing 企业级项目实战(带源码)地址:http://zz563143188.iteye.com/blog/1825168 23种模式java实现源码及收集五年的开发资料下载地址 : http://pan.baidu.com/share/home?uk=4076915866&view=share 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下: 二、设计模式的六大原则 1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭 。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。 2、里氏代换原则(Liskov Substitution Principle) 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科 3、依赖倒转原则(Dependence Inversion Principle) 这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。 4、接口隔离原则(Interface Segregation Principle) 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。 5、迪米特法则(最少知道原则)(Demeter Principle) 为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 6、合成复用原则(Composite Reuse Principle) 原则是尽量使用合成/聚合的方式,而不是使用继承。 三、Java的23中设计模式 从这一块开始,我们详细介绍Java中23种设计模式的概念,应用场景等情况,并结合他们的特点及设计模式的原则进行分析。 1、工厂方法模式(Factory Method) 工厂方法模式分为三种: 11、普通工厂模式 ,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图: 举例如下:(我们举一个发送邮件和短信的例子) 首先,创建二者的共同接口: [java] view plaincopy public interface Sender { public void Send(); } 其次,创建实现类: [java] view plaincopy public class MailSender implements Sender { @Override public void Send() { System.out.println( "this is mailsender!" ); } } [java] view plaincopy public class SmsSender implements Sender { @Override public void Send() { System.out.println( "this is sms sender!" ); } } 最后,建工厂类: [java] view plaincopy public class SendFactory { public Sender produce(String type) { if ( "mail" .equals(type)) { return new MailSender(); } else if ( "sms" .equals(type)) { return new SmsSender(); } else { System.out.println( "请输入正确的类型!" ); return null ; } } } 我们来测试下: public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produce( "sms" ); sender.Send(); } } 输出:this is sms sender! 22、多个工厂方法模式 ,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图: 将上面的代码做下修改,改动下SendFactory类就行,如下: [java] view plaincopy public class SendFactory { public Sender produceMail(){ return new MailSender(); } public Sender produceSms(){ return new SmsSender(); } } 测试类如下: [java] view plaincopy public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produceMail(); sender.Send(); } } 输出:this is mailsender! 33、静态工厂方法模式 ,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。 [java] view plaincopy public class SendFactory { public static Sender produceMail(){ return new MailSender(); } public static Sender produceSms(){ return new SmsSender(); } } [java] view plaincopy public class FactoryTest { public static void main(String[] args) { Sender sender = SendFactory.produceMail(); sender.Send(); } } 输出:this is mailsender! 总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。 2、抽象工厂模式(Abstract Factory) 工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。 请看例子: [java] view plaincopy public interface Sender { public void Send(); } 两个实现类: [java] view plaincopy public class MailSender implements Sender { @Override public void Send() { System.out.println( "this is mailsender!" ); } } [java] view plaincopy public class SmsSender implements Sender { @Override public void Send() { System.out.println( "this is sms sender!" ); } } 两个工厂类: [java] view plaincopy public class SendMailFactory implements Provider { @Override public Sender produce(){ return new MailSender(); } } [java] view plaincopy public class SendSmsFactory implements Provider{ @Override public Sender produce() { return new SmsSender(); } } 在提供一个接口: [java] view plaincopy public interface Provider { public Sender produce(); } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { Provider provider = new SendMailFactory(); Sender sender = provider.produce(); sender.Send(); } } 其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好! 3、单例模式(Singleton) 单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处: 1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。 2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。 3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。 首先我们写一个简单的单例类: [java] view plaincopy public class Singleton { /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */ private static Singleton instance = null ; /* 私有构造方法,防止被实例化 */ private Singleton() { } /* 静态工程方法,创建实例 */ public static Singleton getInstance() { if (instance == null ) { instance = new Singleton(); } return instance; } /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */ public Object readResolve() { return instance; } } 这个类可以满足基本要求,但是,像这样毫无线程安全保护的类,如果我们把它放入多线程的环境下,肯定就会出现问题了,如何解决?我们首先会想到对getInstance方法加synchronized关键字,如下: [java] view plaincopy public static synchronized Singleton getInstance() { if (instance == null ) { instance = new Singleton(); } return instance; } 但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进。我们改成下面这个: [java] view plaincopy public static Singleton getInstance() { if (instance == null ) { synchronized (instance) { if (instance == null ) { instance = new Singleton(); } } } return instance; } 似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例: a>A、B线程同时进入了第一个if判断 b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton(); c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。 d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。 e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。 所以程序还是有可能发生错误,其实程序在运行过程是很复杂的,从这点我们就可以看出,尤其是在写多线程环境下的程序更有难度,有挑战性。我们对该程序做进一步优化: [java] view plaincopy private static class SingletonFactory{ private static Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonFactory.instance; } 实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这样我们暂时总结一个完美的单例模式: [java] view plaincopy public class Singleton { /* 私有构造方法,防止被实例化 */ private Singleton() { } /* 此处使用一个内部类来维护单例 */ private static class SingletonFactory { private static Singleton instance = new Singleton(); } /* 获取实例 */ public static Singleton getInstance() { return SingletonFactory.instance; } /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */ public Object readResolve() { return getInstance(); } } 其实说它完美,也不一定,如果在构造函数中抛出异常,实例将永远得不到创建,也会出错。所以说,十分完美的东西是没有的,我们只能根据实际情况,选择最适合自己应用场景的实现方法。也有人这样实现:因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字,也是可以的: [java] view plaincopy public class SingletonTest { private static SingletonTest instance = null ; private SingletonTest() { } private static synchronized void syncInit() { if (instance == null ) { instance = new SingletonTest(); } } public static SingletonTest getInstance() { if (instance == null ) { syncInit(); } return instance; } } 考虑性能的话,整个程序只需创建一次实例,所以性能也不会有什么影响。 补充: 采用"影子实例"的办法为单例对象的属性同步更新 [java] view plaincopy public class SingletonTest { private static SingletonTest instance = null ; private Vector properties = null ; public Vector getProperties() { return properties; } private SingletonTest() { } private static synchronized void syncInit() { if (instance == null ) { instance = new SingletonTest(); } } public static SingletonTest getInstance() { if (instance == null ) { syncInit(); } return instance; } public void updateProperties() { SingletonTest shadow = new SingletonTest(); properties = shadow.getProperties(); } } 通过单例模式的学习告诉我们: 1、单例模式理解起来简单,但是具体实现起来还是有一定的难度。 2、synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。 到这儿,单例模式基本已经讲完了,结尾处,笔者突然想到另一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同? 首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的) 其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。 再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。 最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题! 4、建造者模式(Builder) 工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。我们看一下代码: 还和前面一样,一个Sender接口,两个实现类MailSender和SmsSender。最后,建造者类如下: [java] view plaincopy public class Builder { private List list = new ArrayList(); public void produceMailSender( int count){ for ( int i= 0 ; i list.add( new MailSender()); } } public void produceSmsSender( int count){ for ( int i= 0 ; i list.add( new SmsSender()); } } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { Builder builder = new Builder(); builder.produceMailSender( 10 ); } } 从这点看出,建造者模式将很多功能集成到一个类里,这个类可以创造出比较复杂的东西。所以与工程模式的区别就是:工厂模式关注的是创建单个产品,而建造者模式则关注创建符合对象,多个部分。因此,是选择工厂模式还是建造者模式,依实际情况而定。 5、原型模式(Prototype) 原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。本小结会通过对象的复制,进行讲解。在Java中,复制对象是通过clone()实现的,先创建一个原型类: [java] view plaincopy public class Prototype implements Cloneable { public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super .clone(); return proto; } } 很简单,一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的,具体怎么实现,我会在另一篇文章中,关于解读Java中本地方法的调用,此处不再深究。在这儿,我将结合对象的浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念: 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。 此处,写一个深浅复制的例子: [java] view plaincopy public class Prototype implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String string; private SerializableObject obj; /* 浅复制 */ public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super .clone(); return proto; } /* 深复制 */ public Object deepClone() throws IOException, ClassNotFoundException { /* 写入当前对象的二进制流 */ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject( this ); /* 读出二进制流产生的新对象 */ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } public String getString() { return string; } public void setString(String string) { this .string = string; } public SerializableObject getObj() { return obj; } public void setObj(SerializableObject obj) { this .obj = obj; } } class SerializableObject implements Serializable { private static final long serialVersionUID = 1L; } 要实现深复制,需要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。 我们接着讨论设计模式,上篇文章我讲完了5种创建型模式,这章开始,我将讲下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源,我们看下面的图: 适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。首先,我们来看看 类的适配器模式 ,先看类图: 核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口时Targetable,通过Adapter类,将Source的功能扩展到Targetable里,看代码: [java] view plaincopy public class Source { public void method1() { System.out.println( "this is original method!" ); } } [java] view plaincopy public interface Targetable { /* 与原类中的方法相同 */ public void method1(); /* 新类的方法 */ public void method2(); } [java] view plaincopy public class Adapter extends Source implements Targetable { @Override public void method2() { System.out.println( "this is the targetable method!" ); } } Adapter类继承Source类,实现Targetable接口,下面是测试类: [java] view plaincopy public class AdapterTest { public static void main(String[] args) { Targetable target = new Adapter(); 接下来我们将要谈谈责任链模式,有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户 target.method1(); target.method2(); } } 输出: this is original method! this is the targetable method! 这样Targetable接口的实现类就具有了Source类的功能。 对象的适配器模式 基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。看图: 只需要修改Adapter类的源码即可: [java] view plaincopy public class Wrapper implements Targetable { private Source source; public Wrapper(Source source){ super (); this .source = source; } @Override public void method2() { System.out.println( "this is the targetable method!" ); } @Override public void method1() { source.method1(); } } 测试类: [java] view plaincopy public class AdapterTest { public static void main(String[] args) { Source source = new Source(); Targetable target = new Wrapper(source); target.method1(); target.method2(); } } 输出与第一种一样,只是适配的方法不同而已。 第三种适配器模式是 接口的适配器模式 ,接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。看一下类图: 这个很好理解,在实际开发中,我们也常会遇到这种接口中定义了太多的方法,以致于有时我们在一些实现类中并不是都需要。看代码: [java] view plaincopy public interface Sourceable { public void method1(); public void method2(); } 抽象类Wrapper2: [java] view plaincopy public abstract class Wrapper2 implements Sourceable{ public void method1(){} public void method2(){} } [java] view plaincopy public class SourceSub1 extends Wrapper2 { public void method1(){ System.out.println( "the sourceable interface's first Sub1!" ); } } [java] view plaincopy public class SourceSub2 extends Wrapper2 { public void method2(){ System.out.println( "the sourceable interface's second Sub2!" ); } } [java] view plaincopy public class WrapperTest { public static void main(String[] args) { Sourceable source1 = new SourceSub1(); Sourceable source2 = new SourceSub2(); source1.method1(); source1.method2(); source2.method1(); source2.method2(); } } 测试输出: the sourceable interface's first Sub1! the sourceable interface's second Sub2! 达到了我们的效果! 讲了这么多,总结一下三种适配器模式的应用场景: 类的适配器模式:当希望将 一个类 转换成满足 另一个新接口 的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。 对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。 7、装饰模式(Decorator) 顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个装饰类,可以为Source类动态的添加一些功能,代码如下: [java] view plaincopy public interface Sourceable { public void method(); } [java] view plaincopy public class Source implements Sourceable { @Override public void method() { System.out.println( "the original method!" ); } } [java] view plaincopy public class Decorator implements Sourceable { private Sourceable source; public Decorator(Sourceable source){ super (); this .source = source; } @Override public void method() { System.out.println( "before decorator!" ); source.method(); System.out.println( "after decorator!" ); } } 测试类: [java] view plaincopy public class DecoratorTest { public static void main(String[] args) { Sourceable source = new Source(); Sourceable obj = new Decorator(source); obj.method(); } } 输出: before decorator! the original method! after decorator! 装饰器模式的应用场景: 1、需要扩展一个类的功能。 2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。) 缺点:产生过多相似的对象,不易排错! 8、代理模式(Proxy) 其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。先来看看关系图: 根据上文的阐述,代理模式就比较容易的理解了,我们看下代码: [java] view plaincopy public interface Sourceable { public void method(); } [java] view plaincopy public class Source implements Sourceable { @Override public void method() { System.out.println( "the original method!" ); } } [java] view plaincopy public class Proxy implements Sourceable { private Source source; public Proxy(){ super (); this .source = new Source(); } @Override public void method() { before(); source.method(); atfer(); } private void atfer() { System.out.println( "after proxy!" ); } private void before() { System.out.println( "before proxy!" ); } } 测试类: [java] view plaincopy public class ProxyTest { public static void main(String[] args) { Sourceable source = new Proxy(); source.method(); } } 输出: before proxy! the original method! after proxy! 代理模式的应用场景: 如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法: 1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。 2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。 使用代理模式,可以将功能划分的更加清晰,有助于后期维护! 9、外观模式(Facade) 外观模式是为了解决类与类之家的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口,看下类图:(我们以一个计算机的启动过程为例) 我们先看下实现类: [java] view plaincopy public class CPU { public void startup(){ System.out.println( "cpu startup!" ); } public void shutdown(){ System.out.println( "cpu shutdown!" ); } } [java] view plaincopy public class Memory { public void startup(){ System.out.println( "memory startup!" ); } public void shutdown(){ System.out.println( "memory shutdown!" ); } } [java] view plaincopy public class Disk { public void startup(){ System.out.println( "disk startup!" ); } public void shutdown(){ System.out.println( "disk shutdown!" ); } } [java] view plaincopy public class Computer { private CPU cpu; private Memory memory; private Disk disk; public Computer(){ cpu = new CPU(); memory = new Memory(); disk = new Disk(); } public void startup(){ System.out.println( "start the computer!" ); cpu.startup(); memory.startup(); disk.startup(); System.out.println( "start computer finished!" ); } public void shutdown(){ System.out.println( "begin to close the computer!" ); cpu.shutdown(); memory.shutdown(); disk.shutdown(); System.out.println( "computer closed!" ); } } User类如下: [java] view plaincopy public class User { public static void main(String[] args) { Computer computer = new Computer(); computer.startup(); computer.shutdown(); } } 输出: start the computer! cpu startup! memory startup! disk startup! start computer finished! begin to close the computer! cpu shutdown! memory shutdown! disk shutdown! computer closed! 如果我们没有Computer类,那么,CPU、Memory、Disk他们之间将会相互持有实例,产生关系,这样会造成严重的依赖,修改一个类,可能会带来其他类的修改,这不是我们想要看到的,有了Computer类,他们之间的关系被放在了Computer类里,这样就起到了解耦的作用,这,就是外观模式! 10、桥接模式(Bridge) 桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化。桥接的用意是: 将抽象化与实现化解耦,使得二者可以独立变化 ,像我们常用的JDBC桥DriverManager一样,JDBC进行连接数据库的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不用动,原因就是JDBC提供统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了。我们来看看关系图: 实现代码: 先定义接口: [java] view plaincopy public interface Sourceable { public void method(); } 分别定义两个实现类: [java] view plaincopy public class SourceSub1 implements Sourceable { @Override public void method() { System.out.println( "this is the first sub!" ); } } [java] view plaincopy public class SourceSub2 implements Sourceable { @Override public void method() { System.out.println( "this is the second sub!" ); } } 定义一个桥,持有Sourceable的一个实例: [java] view plaincopy public abstract class Bridge { private Sourceable source; public void method(){ source.method(); } public Sourceable getSource() { return source; } public void setSource(Sourceable source) { this .source = source; } } [java] view plaincopy public class MyBridge extends Bridge { public void method(){ getSource().method(); } } 测试类: [java] view plaincopy public class BridgeTest { public static void main(String[] args) { Bridge bridge = new MyBridge(); /*调用第一个对象*/ Sourceable source1 = new SourceSub1(); bridge.setSource(source1); bridge.method(); /*调用第二个对象*/ Sourceable source2 = new SourceSub2(); bridge.setSource(source2); bridge.method(); } } output: this is the first sub! this is the second sub! 这样,就通过对Bridge类的调用,实现了对接口Sourceable的实现类SourceSub1和SourceSub2的调用。接下来我再画个图,大家就应该明白了,因为这个图是我们JDBC连接的原理,有数据库学习基础的,一结合就都懂了。 11、组合模式(Composite) 组合模式有时又叫部分-整体 模式在处理类似树形结构的问题时比较方便,看看关系图: 直接来看代码: [java] view plaincopy public class TreeNode { private String name; private TreeNode parent; private Vector children = new Vector(); public TreeNode(String name){ this .name = name; } public String getName() { return name; } public void setName(String name) { this .name = name; } public TreeNode getParent() { return parent; } public void setParent(TreeNode parent) { this .parent = parent; } //添加孩子节点 public void add(TreeNode node){ children.add(node); } //删除孩子节点 public void remove(TreeNode node){ children.remove(node); } //取得孩子节点 public Enumeration getChildren(){ return children.elements(); } } [java] view plaincopy public class Tree { TreeNode root = null ; public Tree(String name) { root = new TreeNode(name); } public static void main(String[] args) { Tree tree = new Tree( "A" ); TreeNode nodeB = new TreeNode( "B" ); TreeNode nodeC = new TreeNode( "C" ); nodeB.add(nodeC); tree.root.add(nodeB); System.out.println( "build the tree finished!" ); } } 使用场景:将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等。 12、享元模式(Flyweight) 享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。 FlyWeightFactory负责创建和管理享元单元,当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象,如果有,就返回已经存在的对象,如果没有,则创建一个新对象,FlyWeight是超类。一提到共享池,我们很容易联想到Java里面的JDBC连接池,想想每个连接的特点,我们不难总结出:适用于作共享的一些个对象,他们有一些共有的属性,就拿数据库连接池来说,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量。 看个例子: 看下数据库连接池的代码: [java] view plaincopy public class ConnectionPool { private Vector pool; /*公有属性*/ private String url = "jdbc:mysql://localhost:3306/test" ; private String username = "root" ; private String password = "root" ; private String driverClassName = "com.mysql.jdbc.Driver" ; private int poolSize = 100 ; private static ConnectionPool instance = null ; Connection conn = null ; /*构造方法,做一些初始化工作*/ private ConnectionPool() { pool = new Vector(poolSize); for ( int i = 0 ; i < poolSize; i++) { try { Class.forName(driverClassName); conn = DriverManager.getConnection(url, username, password); pool.add(conn); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } /* 返回连接到连接池 */ public synchronized void release() { pool.add(conn); } /* 返回连接池中的一个数据库连接 */ public synchronized Connection getConnection() { if (pool.size() > 0 ) { Connection conn = pool.get( 0 ); pool.remove(conn); return conn; } else { return null ; } } } 通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!本章讲解了7种结构型模式,因为篇幅的问题,剩下的11种行为型模式, 本章是关于设计模式的最后一讲,会讲到第三种设计模式——行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。这段时间一直在写关于设计模式的东西,终于写到一半了,写博文是个很费时间的东西,因为我得为读者负责,不论是图还是代码还是表述,都希望能尽量写清楚,以便读者理解,我想不论是我还是读者,都希望看到高质量的博文出来,从我本人出发,我会一直坚持下去,不断更新,源源动力来自于读者朋友们的不断支持,我会尽自己的努力,写好每一篇文章!希望大家能不断给出意见和建议,共同打造完美的博文! 先来张图,看看这11中模式的关系: 第一类:通过父类与子类的关系进行实现。第二类:两个类之间。第三类:类的状态。第四类:通过中间类 13、策略模式(strategy) 策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数,关系图如下: 图中ICalculator提供同意的方法, AbstractCalculator是辅助类,提供辅助方法,接下来,依次实现下每个类: 首先统一接口: [java] view plaincopy public interface ICalculator { public int calculate(String exp); } 辅助类: [java] view plaincopy public abstract class AbstractCalculator { public int [] split(String exp,String opt){ String array[] = exp.split(opt); int arrayInt[] = new int [ 2 ]; arrayInt[ 0 ] = Integer.parseInt(array[ 0 ]); arrayInt[ 1 ] = Integer.parseInt(array[ 1 ]); return arrayInt; } } 三个实现类: [java] view plaincopy public class Plus extends AbstractCalculator implements ICalculator { @Override public int calculate(String exp) { int arrayInt[] = split(exp, "\\+" ); return arrayInt[ 0 ]+arrayInt[ 1 ]; } } [java] view plaincopy public class Minus extends AbstractCalculator implements ICalculator { @Override public int calculate(String exp) { int arrayInt[] = split(exp, "-" ); return arrayInt[ 0 ]-arrayInt[ 1 ]; } } [java] view plaincopy public class Multiply extends AbstractCalculator implements ICalculator { @Override public int calculate(String exp) { int arrayInt[] = split(exp, "\\*" ); return arrayInt[ 0 ]*arrayInt[ 1 ]; } } 简单的测试类: [java] view plaincopy public class StrategyTest { public static void main(String[] args) { String exp = "2+8" ; ICalculator cal = new Plus(); int result = cal.calculate(exp); System.out.println(result); } } 输出:10 策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。 14、模板方法模式(Template Method) 解释一下模板方法模式,就是指:一个抽象类中,有一个主方法,再定义1...n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用,先看个关系图: 就是在AbstractCalculator类中定义一个主方法calculate,calculate()调用spilt()等,Plus和Minus分别继承AbstractCalculator类,通过对AbstractCalculator的调用实现对子类的调用,看下面的例子: [java] view plaincopy public abstract class AbstractCalculator { /*主方法,实现对本类其它方法的调用*/ public final int calculate(String exp,String opt){ int array[] = split(exp,opt); return calculate(array[ 0 ],array[ 1 ]); } /*被子类重写的方法*/ abstract public int calculate( int num1, int num2); public int [] split(String exp,String opt){ String array[] = exp.split(opt); int arrayInt[] = new int [ 2 ]; arrayInt[ 0 ] = Integer.parseInt(array[ 0 ]); arrayInt[ 1 ] = Integer.parseInt(array[ 1 ]); return arrayInt; } } [java] view plaincopy public class Plus extends AbstractCalculator { @Override public int calculate( int num1, int num2) { return num1 + num2; } } 测试类: [java] view plaincopy public class StrategyTest { public static void main(String[] args) { String exp = "8+8" ; AbstractCalculator cal = new Plus(); int result = cal.calculate(exp, "\\+" ); System.out.println(result); } } 我跟踪下这个小程序的执行过程:首先将exp和"\\+"做参数,调用AbstractCalculator类里的calculate(String,String)方法,在calculate(String,String)里调用同类的split(),之后再调用calculate(int ,int)方法,从这个方法进入到子类中,执行完return num1 + num2后,将值返回到AbstractCalculator类,赋给result,打印出来。正好验证了我们开头的思路。 15、观察者模式(Observer) 包括这个模式在内的接下来的四个模式,都是类和类之间的关系,不涉及到继承,学的时候应该 记得归纳,记得本文最开始的那个图。观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。先来看看关系图: 我解释下这些类的作用:MySubject类就是我们的主对象,Observer1和Observer2是依赖于MySubject的对象,当MySubject变化时,Observer1和Observer2必然变化。AbstractSubject类中定义着需要监控的对象列表,可以对其进行修改:增加或删除被监控对象,且当MySubject变化时,负责通知在列表内存在的对象。我们看实现代码: 一个Observer接口: [java] view plaincopy public interface Observer { public void update(); } 两个实现类: [java] view plaincopy public class Observer1 implements Observer { @Override public void update() { System.out.println( "observer1 has received!" ); } } [java] view plaincopy public class Observer2 implements Observer { @Override public void update() { System.out.println( "observer2 has received!" ); } } Subject接口及实现类: [java] view plaincopy public interface Subject { /*增加观察者*/ public void add(Observer observer); /*删除观察者*/ public void del(Observer observer); /*通知所有的观察者*/ public void notifyObservers(); /*自身的操作*/ public void operation(); } [java] view plaincopy public abstract class AbstractSubject implements Subject { private Vector vector = new Vector(); @Override public void add(Observer observer) { vector.add(observer); } @Override public void del(Observer observer) { vector.remove(observer); } @Override public void notifyObservers() { Enumeration enumo = vector.elements(); while (enumo.hasMoreElements()){ enumo.nextElement().update(); } } } [java] view plaincopy public class MySubject extends AbstractSubject { @Override public void operation() { System.out.println( "update self!" ); notifyObservers(); } } 测试类: [java] view plaincopy public class ObserverTest { public static void main(String[] args) { Subject sub = new MySubject(); sub.add( new Observer1()); sub.add( new Observer2()); sub.operation(); } } 输出: update self! observer1 has received! observer2 has received! 这些东西,其实不难,只是有些抽象,不太容易整体理解,建议读者: 根据关系图,新建项目,自己写代码(或者参考我的代码),按照总体思路走一遍,这样才能体会它的思想,理解起来容易! 16、迭代子模式(Iterator) 顾名思义,迭代器模式就是顺序访问聚集中的对象,一般来说,集合中非常常见,如果对集合类比较熟悉的话,理解本模式会十分轻松。这句话包含两层意思:一是需要遍历的对象,即聚集对象,二是迭代器对象,用于对聚集对象进行遍历访问。我们看下关系图: 这个思路和我们常用的一模一样,MyCollection中定义了集合的一些操作,MyIterator中定义了一系列迭代操作,且持有Collection实例,我们来看看实现代码: 两个接口: [java] view plaincopy public interface Collection { public Iterator iterator(); /*取得集合元素*/ public Object get( int i); /*取得集合大小*/ public int size(); } [java] view plaincopy public interface Iterator { //前移 public Object previous(); //后移 public Object next(); public boolean hasNext(); //取得第一个元素 public Object first(); } 两个实现: [java] view plaincopy public class MyCollection implements Collection { public String string[] = { "A" , "B" , "C" , "D" , "E" }; @Override public Iterator iterator() { return new MyIterator( this ); } @Override public Object get( int i) { return string[i]; } @Override public int size() { return string.length; } } [java] view plaincopy public class MyIterator implements Iterator { private Collection collection; private int pos = - 1 ; public MyIterator(Collection collection){ this .collection = collection; } @Override public Object previous() { if (pos > 0 ){ pos--; } return collection.get(pos); } @Override public Object next() { if (pos1 ){ pos++; } return collection.get(pos); } @Override public boolean hasNext() { if (pos1 ){ return true ; } else { return false ; } } @Override public Object first() { pos = 0 ; return collection.get(pos); } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { Collection collection = new MyCollection(); Iterator it = collection.iterator(); while (it.hasNext()){ System.out.println(it.next()); } } } 输出:A B C D E 此处我们貌似模拟了一个集合类的过程,感觉是不是很爽?其实JDK中各个类也都是这些基本的东西,加一些设计模式,再加一些优化放到一起的,只要我们把这些东西学会了,掌握好了,我们也可以写出自己的集合类,甚至框架! 17、责任链模式(Chain of Responsibility) 接下来我们将要谈谈责任链模式,有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整。先看看关系图: Abstracthandler类提供了get和set方法,方便MyHandle类设置和修改引用对象,MyHandle类是核心,实例化后生成一系列相互持有的对象,构成一条链。 [java] view plaincopy public interface Handler { public void operator(); } [java] view plaincopy public abstract class AbstractHandler { private Handler handler; public Handler getHandler() { return handler; } public void setHandler(Handler handler) { this .handler = handler; } } [java] view plaincopy public class MyHandler extends AbstractHandler implements Handler { private String name; public MyHandler(String name) { this .name = name; } @Override public void operator() { System.out.println(name+ "deal!" ); if (getHandler()!= null ){ getHandler().operator(); } } } [java] view plaincopy public class Test { public static void main(String[] args) { MyHandler h1 = new MyHandler( "h1" ); MyHandler h2 = new MyHandler( "h2" ); MyHandler h3 = new MyHandler( "h3" ); h1.setHandler(h2); h2.setHandler(h3); h1.operator(); } } 输出: h1deal! h2deal! h3deal! 此处强调一点就是,链接上的请求可以是一条链,可以是一个树,还可以是一个环,模式本身不约束这个,需要我们自己去实现,同时,在一个时刻,命令只允许由一个对象传给另一个对象,而不允许传给多个对象。 18、命令模式(Command) 命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。这个过程好在,三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己的事儿就行,司令员要的是结果,不会去关注到底士兵是怎么实现的。我们看看关系图: Invoker是调用者(司令员),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象,看实现代码: [java] view plaincopy public interface Command { public void exe(); } [java] view plaincopy public class MyCommand implements Command { private Receiver receiver; public MyCommand(Receiver receiver) { this .receiver = receiver; } @Override public void exe() { receiver.action(); } } [java] view plaincopy public class Receiver { public void action(){ System.out.println( "command received!" ); } } [java] view plaincopy public class Invoker { private Command command; public Invoker(Command command) { this .command = command; } public void action(){ command.exe(); } } [java] view plaincopy public class Test { public static void main(String[] args) { Receiver receiver = new Receiver(); Command cmd = new MyCommand(receiver); Invoker invoker = new Invoker(cmd); invoker.action(); } } 输出:command received! 这个很哈理解,命令模式的目的就是达到命令的发出者和执行者之间解耦,实现请求和执行分开,熟悉Struts的同学应该知道,Struts其实就是一种将请求和呈现分离的技术,其中必然涉及命令模式的思想! 其实每个设计模式都是很重要的一种思想,看上去很熟,其实是因为我们在学到的东西中都有涉及,尽管有时我们并不知道,其实在Java本身的设计之中处处都有体现,像AWT、JDBC、集合类、IO管道或者是Web框架,里面设计模式无处不在。因为我们篇幅有限,很难讲每一个设计模式都讲的很详细,不过我会尽我所能,尽量在有限的空间和篇幅内,把意思写清楚了,更好让大家明白。本章不出意外的话,应该是设计模式最后一讲了,首先还是上一下上篇开头的那个图: 本章讲讲第三类和第四类。 19、备忘录模式(Memento) 主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,个人觉得叫备份模式更形象些,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储A的一些内部状态,类C呢,就是一个用来存储备忘录的,且只能存储,不能修改等操作。做个图来分析一下: Original类是原始类,里面有需要保存的属性value及创建一个备忘录类,用来保存value值。Memento类是备忘录类,Storage类是存储备忘录的类,持有Memento类的实例,该模式很好理解。直接看源码: [java] view plaincopy public class Original { private String value; public String getValue() { return value; } public void setValue(String value) { this .value = value; } public Original(String value) { this .value = value; } public Memento createMemento(){ return new Memento(value); } public void restoreMemento(Memento memento){ this .value = memento.getValue(); } } [java] view plaincopy public class Memento { private String value; public Memento(String value) { this .value = value; } public String getValue() { return value; } public void setValue(String value) { this .value = value; } } [java] view plaincopy public class Storage { private Memento memento; public Storage(Memento memento) { this .memento = memento; } public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this .memento = memento; } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { // 创建原始类 Original origi = new Original( "egg" ); // 创建备忘录 Storage storage = new Storage(origi.createMemento()); // 修改原始类的状态 System.out.println( "初始化状态为:" + origi.getValue()); origi.setValue( "niu" ); System.out.println( "修改后的状态为:" + origi.getValue()); // 回复原始类的状态 origi.restoreMemento(storage.getMemento()); System.out.println( "恢复后的状态为:" + origi.getValue()); } } 输出: 初始化状态为:egg 修改后的状态为:niu 恢复后的状态为:egg 简单描述下:新建原始类时,value被初始化为egg,后经过修改,将value的值置为niu,最后倒数第二行进行恢复状态,结果成功恢复了。其实我觉得这个模式叫“备份-恢复”模式最形象。 20、状态模式(State) 核心思想就是:当对象的状态改变时,同时改变其行为,很好理解!就拿QQ来说,有几种状态,在线、隐身、忙碌等,每个状态对应不同的操作,而且你的好友也能看到你的状态,所以,状态模式就两点:1、可以通过改变状态来获得不同的行为。2、你的好友能同时看到你的变化。看图: State类是个状态类,Context类可以实现切换,我们来看看代码: [java] view plaincopy package com.xtfggef.dp.state; /** * 状态类的核心类 * 2012-12-1 * @author erqing * */ public class State { private String value; public String getValue() { return value; } public void setValue(String value) { this .value = value; } public void method1(){ System.out.println( "execute the first opt!" ); } public void method2(){ System.out.println( "execute the second opt!" ); } } [java] view plaincopy package com.xtfggef.dp.state; /** * 状态模式的切换类 2012-12-1 * @author erqing * */ public class Context { private State state; public Context(State state) { this .state = state; } public State getState() { return state; } public void setState(State state) { this .state = state; } public void method() { if (state.getValue().equals( "state1" )) { state.method1(); } else if (state.getValue().equals( "state2" )) { state.method2(); } } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { State state = new State(); Context context = new Context(state); //设置第一种状态 state.setValue( "state1" ); context.method(); //设置第二种状态 state.setValue( "state2" ); context.method(); } } 输出: execute the first opt! execute the second opt! 根据这个特性,状态模式在日常开发中用的挺多的,尤其是做网站的时候,我们有时希望根据对象的某一属性,区别开他们的一些功能,比如说简单的权限控制等。 21、访问者模式(Visitor) 访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。—— From 百科 简单来说,访问者模式就是一种分离对象数据结构与行为的方法,通过这种分离,可达到为一个被访问者动态添加新的操作而无需做其它的修改的效果。简单关系图: 来看看原码:一个Visitor类,存放要访问的对象, [java] view plaincopy public interface Visitor { public void visit(Subject sub); } [java] view plaincopy public class MyVisitor implements Visitor { @Override public void visit(Subject sub) { System.out.println( "visit the subject:" +sub.getSubject()); } } Subject类,accept方法,接受将要访问它的对象,getSubject()获取将要被访问的属性, [java] view plaincopy public interface Subject { public void accept(Visitor visitor); public String getSubject(); } [java] view plaincopy public class MySubject implements Subject { @Override public void accept(Visitor visitor) { visitor.visit( this ); } @Override public String getSubject() { return "love" ; } } 测试: [java] view plaincopy public class Test { public static void main(String[] args) { Visitor visitor = new MyVisitor(); Subject sub = new MySubject(); sub.accept(visitor); } } 输出:visit the subject:love 该模式适用场景:如果我们想为一个现有的类增加新功能,不得不考虑几个事情:1、新功能会不会与现有功能出现兼容性问题?2、以后会不会再需要添加?3、如果类不允许修改代码怎么办?面对这些问题,最好的解决方法就是使用访问者模式,访问者模式适用于数据结构相对稳定的系统,把数据结构和算法解耦, 22、中介者模式(Mediator) 中介者模式也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改。如果使用中介者模式,只需关心和Mediator类的关系,具体类类之间的关系及调度交给Mediator就行,这有点像spring容器的作用。先看看图: User类统一接口,User1和User2分别是不同的对象,二者之间有关联,如果不采用中介者模式,则需要二者相互持有引用,这样二者的耦合度很高,为了解耦,引入了Mediator类,提供统一接口,MyMediator为其实现类,里面持有User1和User2的实例,用来实现对User1和User2的控制。这样User1和User2两个对象相互独立,他们只需要保持好和Mediator之间的关系就行,剩下的全由MyMediator类来维护!基本实现: [java] view plaincopy public interface Mediator { public void createMediator(); public void workAll(); } [java] view plaincopy public class MyMediator implements Mediator { private User user1; private User user2; public User getUser1() { return user1; } public User getUser2() { return user2; } @Override public void createMediator() { user1 = new User1( this ); user2 = new User2( this ); } @Override public void workAll() { user1.work(); user2.work(); } } [java] view plaincopy public abstract class User { private Mediator mediator; public Mediator getMediator(){ return mediator; } public User(Mediator mediator) { this .mediator = mediator; } public abstract void work(); } [java] view plaincopy public class User1 extends User { public User1(Mediator mediator){ super (mediator); } @Override public void work() { System.out.println( "user1 exe!" ); } } [java] view plaincopy public class User2 extends User { public User2(Mediator mediator){ super (mediator); } @Override public void work() { System.out.println( "user2 exe!" ); } } 测试类: [java] view plaincopy public class Test { public static void main(String[] args) { Mediator mediator = new MyMediator(); mediator.createMediator(); mediator.workAll(); } } 输出: user1 exe! user2 exe! 23、解释器模式(Interpreter) 解释器模式是我们暂时的最后一讲,一般主要应用在OOP开发中的编译器的开发中,所以适用面比较窄。 Context类是一个上下文环境类,Plus和Minus分别是用来计算的实现,代码如下: [java] view plaincopy public interface Expression { public int interpret(Context context); } [java] view plaincopy public class Plus implements Expression { @Override public int interpret(Context context) { return context.getNum1()+context.getNum2(); } } [java] view plaincopy public class Minus implements Expression { @Override public int interpret(Context context) { return context.getNum1()-context.getNum2(); } } [java] view plaincopy public class Context { private int num1; private int num2; public Context( int num1, int num2) { this .num1 = num1; this .num2 = num2; } public int getNum1() { return num1; } public void setNum1( int num1) { this .num1 = num1; } public int getNum2() { return num2; } public void setNum2( int num2) { this .num2 = num2; } } [java] view plaincopy public class Test { public static void main(String[] args) { // 计算9+2-8的值 int result = new Minus().interpret(( new Context( new Plus() .interpret( new Context( 9 , 2 )), 8 ))); System.out.println(result); } } 最后输出正确的结果:3。 基本就这样,解释器模式用来做各种各样的解释器,如正则表达式等的解释器等等! 设计模式基本就这么大概讲完了,总体感觉有点简略,的确,这么点儿篇幅,不足以对整个23种设计模式做全面的阐述,此处读者可将它作为一个理论基础去学习,通过这四篇博文,先基本有个概念,虽然我讲的有些简单,但基本都能说明问题及他们的特点,如果对哪一个感兴趣,可以继续深入研究!同时我也会不断更新,尽量补全遗漏、修正不足,欢迎广大读者及时提出好的建议,我们一起学习!项目中涉及到的代码,已经放到了我的资源里:http://download. csdn.net/detail/zhangerqing/4835830(因为我不喜欢不劳而获,所以没有免积分,只设置了5个,如果有人实在没积分又急要,那么联系我吧,我给你发过去)。
50.谈谈你对框架的理解,设计框架的时候你是怎么考虑的,重构项目的时候你都遵循什么原则。
1. 框架不要为应用做过多的假设 关于框架为应用做过多的假设, 一个非常具体的现象就是, 框架越俎代庖, 把本来是应 用要做的事情揽过来自己做。 这是一种典型的吃力不讨好的做法。 框架越俎代庖, 也许会使 得某一个具体应用的开发变得简单, 却会给其它更多想使用该框架的应用增加了本没有必要 的束缚和负担。 2. 使用接口,保证框架提供的所有重要实现都是可以被替换的 框架终究不是应用, 所以框架无法考虑所有应用的具体情况, 保证所有重要的组件的实 现都是可以被替换的, 这一点非常重要, 它使得应用可以根据当前的实际情况来替换掉框架 提供的部分组件的默认实现。 使用接口来定义框架中各个组件及组件间的联系, 将提高框架 的可复用性。 3. 框架应当简洁、一致、且目标集中 框架应当简洁, 不要包含那些对框架目标来说无关紧要的东西, 保证框架中的每个组件 的存在都是为了支持框架目标的实现。包含过多无谓的元素(类、接口、枚举等) ,会使框 架变得难以理解, 尝试将这些对于框架核心目标不太重要的元素转移到类库中, 可以使得框 架更清晰、目标更集中。 4. 提供一个常用的骨架,但是不要固定骨架的结构,使骨架也是可以组装的 比如说, 如果是针对某种业务处理的框架, 那么框架不应该只提供一套不可变更的业务 处理流程,而是应该将处理流程 “ 单步 ” 化,使得各个步骤是可以重新组装的,如此一来,应 用便可以根据实际情况来改变框架默认的处理流程。 这种框架的可定制化能力可以极大地提 高框架的可复用性。 5. 不断地重构框架 如果说设计和实现一个高质量的框架有什么秘诀?答案只有一个,重构、不断地重构。 重构框架的实现代码、 甚至重构框架的设计。 重构的驱动力源于几个方面, 比如对要解决的 本质问题有了更清晰准备的认识,在使用框架的时候发现某些组件职责不明确、难以使用, 框架的层次结构不够清晰等。
51.LRU算法
假设 序列为 4 3 4 2 3 1 4 2 物理块有3个 则 首轮 4调入内存 4 次轮 3调入内存 3 4 之后 4调入内存 4 3 之后 2调入内存 2 4 3 之后 3调入内存 3 2 4 之后 1调入内存 1 3 2(因为最少使用的是4,所以丢弃4) 之后 4调入内存 4 1 3(原理同上) 最后 2调入内存 2 4 1 在指定内存中如果超过内存剔除最近最少用的。
51.自定义控件的生命周期
onFinishInflate() 当View中所有的子控件均被映射成xml后触发
onMeasure( int , int ) 确定所有子元素的大小
onLayout( boolean , int , int , int , int ) 当View分配所有的子元素的大小和位置时触发
onSizeChanged( int , int , int , int ) 当view的大小发生变化时触发
onDraw(Canvas) view渲染内容的细节
onKeyDown( int , KeyEvent) 有按键按下后触发
onKeyUp( int , KeyEvent) 有按键按下后弹起时触发
onTrackballEvent(MotionEvent) 轨迹球事件
onTouchEvent(MotionEvent) 触屏事件
onFocusChanged( boolean , int , Rect) 当View获取或失去焦点时触发
onWindowFocusChanged( boolean ) 当窗口包含的view获取或失去焦点时触发
onAttachedToWindow() 当view被附着到一个窗口时触发
onDetachedFromWindow() 当view离开附着的窗口时触发,Android123提示该方法和 onAttachedToWindow() 是相反的。
onWindowVisibilityChanged( int ) 当窗口中包含的可见的view发生变化时触发
你可能感兴趣的:(Android面试题,Android面试题)
Android面试题
学海无涯乐作舟
客户端面试 android
简单android基础对于面向对象的六大基本原则了解多少单一职责(SingleResponsibilityPrinciple):一个类只做一件事,可读性提高里式替换原则(LiskovSubstitutionPrinciple):依赖继承和多态,就是能用父类的地方就可以用子类替换,用子类的但不能用父类。依赖倒置原则(DependenceInversionPrinciple):依赖抽象,就是模块之间的
Android面试题
1b16bebb1c3c
ListView和RecyclerView区别参考链接:https://blog.csdn.net/shu_lan...既然RecyclerView在很多方面能取代ListView,Google为什么没把ListView划上一条过时的横线?答案:可以沿着回收机制来回答。ListView采用的是RecyclerBin的回收机制在一些轻量级的List显示时效率更高你用过MVP和MVVM的区别参考链接:
2024Android面试题合集整理(字节跳动+猿辅导,Android面试相关文章及Github学习资料
2401_83739472
2024年程序员学习 android 面试 职场和发展
斗鱼1.说说HashMap的原理2.说说Java的内存分区3.讲讲你对垃圾回收机制的了解,老年代有什么算法?4.说说你对volatile字段有什么用途?5.说说事件分发机制,怎么写一个不能滑动的ViewPager6.说说你对类加载机制的了解?DexClassLoader与PathClassLoader的区别7.说说插件化的原理,资源的插件化id重复如何解决?8.mvp与mvvm模式的区别是什么?9
Android架构组件JetPack之ViewModel(二),android面试题2024基础
高手程序员
2024年程序员学习 android 架构
概述ViewModel,从字面上理解的话,它肯定是跟视图(View)以及数据(Model)相关的。正像它字面意思一样,它是负责准备和管理和UI组件(Fragment/Activity)相关的数据类,也就是说ViewModel是用来管理UI相关的数据的,同时ViewModel还可以用来负责UI组件间的通信。之前存在的问题ViewModel用来存储和管理UI相关的数据,可于将一个Activity或Fr
2024Android面试题与答案(2)
it灰太狼
Android面试 android
Framework内核解析面试题汇总Android中多进程通信的方式有哪些?描述下Binder机制原理?(东方头条)为什么Android要采用Binder作为IPC机制?Binder线程池的工作过程是什么样?(东方头条)AIDL的全称是什么?如何工作?能处理哪些类型的数据?Android中Pid&Uid的区别和联系Handler怎么进行线程通信,原理是什么?(东方头条)ThreadLocal的原理
Android面试题之Kotlin协程一文搞定
AntDreamer
kotlin android kotlin 开发语言 面试
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点定义协程基于线程,是轻量级的线程作用处理耗时任务,这种任务常常会阻塞主线程保证主线程安全,即确保安全地从主线程调用任何suspend函数特点让异步逻辑同步化最核心的点就是,函数或者一段程序能够被挂起,稍后再在挂起得位置恢复挂起函数使用suspend关键字修饰的函数挂起函数只能在协程
安卓基础面试题
享哥。
android
自定义viewAndroid自定义View-CSDN博客view和viewgroupView和ViewGroup的区别-view的事件分发事件分发详解---历史最容易理解组件化Android-组件化开发什么是ANRAndroidANR详解-CSDN博客Android性能优化Android优化-CSDN博客Aroute原理Arouter框架原理浅解-简书2021年Android面试题汇总(初级)-简
Android面试题汇总(中高级)及答案解析,2023年企业面试题精选
代码不难写
Android android ui 面试
前言首先要声明的是:面试题的目的不是为了让大家背题,而是从不同维度帮助大家复习,取长补短。让我们正式进入正题:现在网上的面试题资料实在太多了,而且人人肯定都说自己的最好,那么就导致大家不知道怎么选了。大部分的博主推荐资料,也就是把各类技术点面试题一股脑整理一遍,水个目录,没有一条清晰系统有针对性的模块。所以今天我这个Android企业常问面试题解析就做做减法,给大家来个一条龙服务,Android常
膜拜大牛!灵魂一问-如何彻底防止APK反编译?成功定级腾讯T3-2
程序员东城
程序员 android 移动开发 面试
正文Android行业主要问题是初级Android太多了,会写xml和Activity的程序员太多了,初中级程序员面临很大的竞争,现状也就偏于高级开发者。越来越多的初中级Android程序员找不到满意的工作,甚至根本找不到工作!所以很多人觉得Android要凉了,甚至不惜转行,从头学其它技术。现在的Android招聘要求,已经不是多年之前的要求了。一、Android面试题Android面试题包括A
2018-04-12 Android面试题整理
王培921223
一、Android基本常识1、写10个简单的linux命令mkdir创建文件夹rmdir删除文件夹rm删除文件mv移动文件cp拷贝文件cat查看文件tail查看文件尾部more分页查看文件cd切换当前目录ls列出文件清单reboot重启date显示日期cal显示日历ps查看系统进程相当于windows的任务管理器ifconfig配置网络2、书写出android工程的目录结构src源文件gen生成的
从猿辅导一面挂,怒刷1000道Android面试题,成功入职字节跳动!
Kepler_II
缘起从16年毕业至今,就职过两家公司,大大小小项目做了几个,非常感谢我的两位老大,在我的android成长路上给予我很多指导,亦师亦友的关系。从年前至今参加面试了很多公司,从猿辅导一面挂,我深刻意识到Android开发内卷太严重了,面试都是需要背八股文,狂刷leecode。最后顺利拿到了字节跳动offer。总结下经验,也是对过去的一个回顾和总结吧。猿辅导(一面挂)自我介绍怎么学Android的聊了
来自非985&211的普通本科的Android面试题分享【网络安全】
不是程序媛呀
面试 职场和发展 网络安全 web安全 信息安全
文中附有详细的面试真题目,文末有我当时刷的面试真题还有一些对我帮助良多的复习资料,特别有用,希望也可以帮大家顺利上岸,顺便攒攒人品!个人的基本情况本人出生在一个普通家庭,自身学历很一般,并非985也并非211,就是一个差不多是三本的二本普通本科生应届毕业生。在读书期间有过一些简单的实习,也参与过一些小公司的项目,但我还是觉得自己在其它人的眼里还是很普通(所以,自己能够在今年特别不好找工作的期间被一
京东android面试题(2018 顶级互联网公司面试题系列)
40岁资深老架构师尼恩
java
以下来自于北京的一个兄弟的面试题1.静态内部类和非静态内部类有什么区别2.谈谈你对java多态的理解3.如何开启线程,run和runnable有什么区别4.线程池的好处5.说一下你知道的设计模式有哪些,介绍下适配器模式6.android四大组件,Activity启动模式,广播有哪些类型,app内广播原理7.IntentService和Service有什么区别8.AIDL9.内存优化疯狂创客圈:如果
2024 android面试题总结部分
后岔湾程序员
开发日常问题 android
进程间通信方式主要有intent,只支持Bundle支持的数据类型;Messenger支持一对多串行通信,用于发送消息及Bundle数据;AIDL功能强大,可调用服务端方法;ContentProvider主要支持进程间共享数据;BroadCastReceiver广播也可实现进程间通信,发送消息及数据线程间通信方式我们知道线程是CPU调度的最小单位。在Android中主线程是不能够做耗时操作的,子线
火爆知乎的Android面试题-为什么Flutter能最好地改变移动开发?讲的明明白白!
深圳之巅
程序员 Android
大佬带你走进Android开发的世界,掌握了这些知识点,学习Android也可以很轻松。核心分析内容对于怎么学习Android,主要解决的是3个问题:学什么、怎么学&怎么用。具体如下:下面,我将带着上述几个问题,**详细讲解自身学习Android的方法和Android学习路径;**最后,还会结合前面内容,给出综合的具体执行学习Android的建议。百度Android一面流程:0、谈谈项目1、MVP
Android面试题内存&性能篇
迷途小码农h
Android面试题内存&性能篇,由本人整理汇总,后续将继续推出系列篇,如果喜欢请持续关注和推荐。内存分配RAM(randomaccessmemory)随机存取存储器。说白了就是内存。一般Java在内存分配时会涉及到以下区域:寄存器(Registers):速度最快的存储场所,因为寄存器位于处理器内部,我们在程序中无法控制栈(Stack):存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是
android面试题记录
硕团团
[TOC]线程安全和不安全?简单来说,存在成员变量(全局变量)的线程是不安全的。使用局部变量的线程是安全的。ANR产生的原因和解决步骤ANR的全称是applicationnotresponding,意思就是程序未响应。出现ANR的三种情况:a.主线程对输入事件5秒内没有处理完毕b.主线程在执行BroadcastReceiver的onReceive()函数时10秒内没有处理完毕c.主线程在Servi
android面试题记录2
硕团团
ThreadLocal实现原理EventBus原理EventBus流程EventBus内ThreadMode类型分为4种HTTP请求报文结构HTTP相应报文结构cookie是用来干嘛的androidIntent传递数据最大限制synchronize关键字用法还知道哪些同步的方式?Activity启动模式View的绘制流程,测量传参的形式是什么内部类有什么作用?final关键字的作用单例模式为什么要
干货 干货 2019Android面试题
迷途小码农h
前言找工作还是需要大家不要紧张,有我们干这一行的接触人本来就不多难免看到面试官会紧张,主要是因为怕面试官问的问题到不上来,那时候不要着急,答不上了的千万不然胡扯一些,直接就给面试官说这块我还没接触到,以后如果工作当中遇到的话我可以很快的吧这个问题给解决了,但是我们有了这篇文章,就不一样了,基本上问的问题都有适当的看一下,到时候很快就可以拿到offer我在这里祝大家工作顺利,天天开心,好了下面就是正
Binder机制---IPC、RPC的过程,69个经典Android面试题和答案详解
flutter架构师
程序员 面试 移动开发 android
一个拥有独立空间的进程如何向另一个进程传递数据呢?显然要通过两个进程共享的内核空间。从内核的角度看,进程不过是一个作业单位,虽然各个进程的用户空间相对独立,但是运行在内核空间中的任务数据、代码都是彼此共享的。Linux本身就提供IPC工具,用于两个进程通过内核进行通信。Android中的binder功能更丰富,不仅可以进行IPC通信,还可以用来调用另一个进程的函数,即支持进程之间的RPC操作。IP
从Android面试题目溯源-2、Android为什么要使用Binder机制
PirateBrook
android binder
概念Binder是Android操作系统中用于进程间通信的一种机制为什么使用Binder相较于Linux提供的IPC机制,Binder性能优势,仅需要一次拷贝,性能好于除共享内存外的IPC方式稳定性,C/S架构,架构清晰,调用双方职责明确安全性,Binder和Android深度绑定,可以做到更细粒度的权限控制,比如服务调用方权限检查,限制未声明权限的客户端访问敏感信息,UID和PID校验系统服务的
Android面试题整理,腾讯,字节等大厂面试真题汇总,已开源
Java老猴子
程序员 android
前言程序员,近年来十分火爆的职业,凭着巨大的市场缺口和高额的薪水吸引着大量毕业生加入程序员的队伍。这其中就包括各类专业的学生,像我这种自动化专业的也在其内。这些不是计算机科班出身的可以看作是半路出家了。那么半路出家程序员和计算机专业出身学生有什么区别呢?先来看一张计算机专业的大学课程表:数据结构与算法、计算机组成原理、汇编语言程序设计、Java语言程序设计、C/C++程序设计、操作系统、计算机系统
从Android面试题目溯源-1、创建线程有那几种方式
PirateBrook
面试 android 面试 职场和发展
概念程序执行流的最小单位,处理器调度调度和分派的基本单位。如何理解这个概念如下图,可以简单类比吉他,六根弦代表六个线程,每个线程独立且单独运行,且持有上一个音的状态,每根手指可类比为一个CPU的核心,在Arm架构中,大小核架构可以类比吉他的高底音弦,震动频率高的1,2,3弦为大核,震动频率相对较低的4,5,6弦为小核(之后针对Arm架构单独讨论)Java的创建方式继承Thread实现Runnabl
Android面试题收集
Keung丶
面试题 android
1.静态和动态广播的区别?生存期:静态广播的生存期可以比动态广播的长很多,因为静态广播很多都是用来对系统时间进行监听,比如我们可以监听手机开机。而动态广播会随着context的终止而终止优先级:动态广播的优先级比静态广播高注册:动态广播无需在AndroidManifest.xml中声明即可直接使用(用receiver注册),也即动态;而静态广播则需要,有时候还要在AndroidManifest.x
武汉腾讯会议Android面试题
Keung丶
面试题 android flutter 面试
1.数组和链表的区别(1)数组的元素个数是固定的,而组成链表的结点个数可按需要增减;(2)数组元素的存诸单元在数组定义时分配,链表结点的存储单元在程序执行时动态向系统申请;(3)数组中的元素顺序关系由元素在数组中的位置(即下标)确定,链表中的结点顺序关系由结点所包含的指针来体现。(4)对于不是固定长度的列表,用可能最大长度的数组来描述,会浪费许多内存空间。(5)对于元素的插人、删除操作非常频繁的列
Android面试题 - 01
其子昱舟
Android面试题 android
一、简述Android的4大组件是哪些,它们的作用?Android的四大基本组件包括Activity、Service、ContentProvider和BroadcastReceiver。Activity:一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。Activity之间通过Intent进行通信,Intent的描述结构中有两个最重要的部分:动作
史上最全的《Android面试题及解析》,面试必会
web大美女
程序员 android 移动开发 面试
IT行业的前景近几年来,大数据、人工智能AI、物联网等一些技术不断发展,也让人们看到了IT行业的繁荣与良好的前景。越来越多的高校学府加大了对计算机的投入,设立相应的热门专业来吸引招生。当然也有越来越多的人选择从事这个行业,希望能从这个行业中分得一杯羹。从初中级到高级,移动端程序员的进阶宝典想要成为一名优秀的Android开发,你需要一份完备的知识体系,在这里,让我们一起成长为自己所想的那样。下面我
【面试】Android面试题
傲丿奈我何
合集 android java android studio
AndroidFrameWork架构图包含内容启动分析应用程序启动分析APK中的线程自定义Thread与UI线程的区别APK程序的运行过程Acticity概念生命周期Activity状态dialog会不会影响Activity生命周期Activity启动模式Activity任务栈退出ActivityActivity之间传输数据的方法横竖屏切换生命周期Activity跳转必然执行的方法将Activit
Android高级面试题汇总
cao苗子
前言金三银四,很多同学心里大概都准备着年后找工作或者跳槽。最近有很多同学都在交流群里求大厂面试题。正好我电脑里面有这方面的整理,于是就发上来分享给大家。这些题目是网友去百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。主要分为以下几部分:(1)java面试题(2)Android面试题(3)高级开发技术面
Android面试题 2018
一点墨汁
转自:https://juejin.im/post/5af82ee1f265da0b934865baAndroid面试题整理(2018)本文分为Java基础、Android知识点、设计模式、算法、网络等,抛砖引玉,大家可酌情服用水平一般,个人整理题目来源于网络搜集结合右下角目录食用更佳不再更新了(作者两年经验,断断续续写了四个月左右,之后集中面了魔都30多家一二线的互联网公司,拿到了2/3的off
项目中 枚举与注解的结合使用
飞翔的马甲
java enum annotation
前言:版本兼容,一直是迭代开发头疼的事,最近新版本加上了支持新题型,如果新创建一份问卷包含了新题型,那旧版本客户端就不支持,如果新创建的问卷不包含新题型,那么新旧客户端都支持。这里面我们通过给问卷类型枚举增加自定义注解的方式完成。顺便巩固下枚举与注解。
一、枚举
1.在创建枚举类的时候,该类已继承java.lang.Enum类,所以自定义枚举类无法继承别的类,但可以实现接口。
【Scala十七】Scala核心十一:下划线_的用法
bit1129
scala
下划线_在Scala中广泛应用,_的基本含义是作为占位符使用。_在使用时是出问题非常多的地方,本文将不断完善_的使用场景以及所表达的含义
1. 在高阶函数中使用
scala> val list = List(-3,8,7,9)
list: List[Int] = List(-3, 8, 7, 9)
scala> list.filter(_ > 7)
r
web缓存基础:术语、http报头和缓存策略
dalan_123
Web
对于很多人来说,去访问某一个站点,若是该站点能够提供智能化的内容缓存来提高用户体验,那么最终该站点的访问者将络绎不绝。缓存或者对之前的请求临时存储,是http协议实现中最核心的内容分发策略之一。分发路径中的组件均可以缓存内容来加速后续的请求,这是受控于对该内容所声明的缓存策略。接下来将讨web内容缓存策略的基本概念,具体包括如如何选择缓存策略以保证互联网范围内的缓存能够正确处理的您的内容,并谈论下
crontab 问题
周凡杨
linux crontab unix
一: 0481-079 Reached a symbol that is not expected.
背景:
*/5 * * * * /usr/IBMIHS/rsync.sh
让tomcat支持2级域名共享session
g21121
session
tomcat默认情况下是不支持2级域名共享session的,所有有些情况下登陆后从主域名跳转到子域名会发生链接session不相同的情况,但是只需修改几处配置就可以了。
打开tomcat下conf下context.xml文件
找到Context标签,修改为如下内容
如果你的域名是www.test.com
<Context sessionCookiePath="/path&q
web报表工具FineReport常用函数的用法总结(数学和三角函数)
老A不折腾
Web finereport 总结
ABS
ABS(number):返回指定数字的绝对值。绝对值是指没有正负符号的数值。
Number:需要求出绝对值的任意实数。
示例:
ABS(-1.5)等于1.5。
ABS(0)等于0。
ABS(2.5)等于2.5。
ACOS
ACOS(number):返回指定数值的反余弦值。反余弦值为一个角度,返回角度以弧度形式表示。
Number:需要返回角
linux 启动java进程 sh文件
墙头上一根草
linux shell jar
#!/bin/bash
#初始化服务器的进程PId变量
user_pid=0;
robot_pid=0;
loadlort_pid=0;
gateway_pid=0;
#########
#检查相关服务器是否启动成功
#说明:
#使用JDK自带的JPS命令及grep命令组合,准确查找pid
#jps 加 l 参数,表示显示java的完整包路径
#使用awk,分割出pid
我的spring学习笔记5-如何使用ApplicationContext替换BeanFactory
aijuans
Spring 3 系列
如何使用ApplicationContext替换BeanFactory?
package onlyfun.caterpillar.device;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import
Linux 内存使用方法详细解析
annan211
linux 内存 Linux内存解析
来源 http://blog.jobbole.com/45748/
我是一名程序员,那么我在这里以一个程序员的角度来讲解Linux内存的使用。
一提到内存管理,我们头脑中闪出的两个概念,就是虚拟内存,与物理内存。这两个概念主要来自于linux内核的支持。
Linux在内存管理上份为两级,一级是线性区,类似于00c73000-00c88000,对应于虚拟内存,它实际上不占用
数据库的单表查询常用命令及使用方法(-)
百合不是茶
oracle 函数 单表查询
创建数据库;
--建表
create table bloguser(username varchar2(20),userage number(10),usersex char(2));
创建bloguser表,里面有三个字段
&nbs
多线程基础知识
bijian1013
java 多线程 thread java多线程
一.进程和线程
进程就是一个在内存中独立运行的程序,有自己的地址空间。如正在运行的写字板程序就是一个进程。
“多任务”:指操作系统能同时运行多个进程(程序)。如WINDOWS系统可以同时运行写字板程序、画图程序、WORD、Eclipse等。
线程:是进程内部单一的一个顺序控制流。
线程和进程
a. 每个进程都有独立的
fastjson简单使用实例
bijian1013
fastjson
一.简介
阿里巴巴fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库;包括“序列化”和“反序列化”两部分,它具备如下特征:  
【RPC框架Burlap】Spring集成Burlap
bit1129
spring
Burlap和Hessian同属于codehaus的RPC调用框架,但是Burlap已经几年不更新,所以Spring在4.0里已经将Burlap的支持置为Deprecated,所以在选择RPC框架时,不应该考虑Burlap了。
这篇文章还是记录下Burlap的用法吧,主要是复制粘贴了Hessian与Spring集成一文,【RPC框架Hessian四】Hessian与Spring集成
 
【Mahout一】基于Mahout 命令参数含义
bit1129
Mahout
1. mahout seqdirectory
$ mahout seqdirectory
--input (-i) input Path to job input directory(原始文本文件).
--output (-o) output The directory pathna
linux使用flock文件锁解决脚本重复执行问题
ronin47
linux lock 重复执行
linux的crontab命令,可以定时执行操作,最小周期是每分钟执行一次。关于crontab实现每秒执行可参考我之前的文章《linux crontab 实现每秒执行》现在有个问题,如果设定了任务每分钟执行一次,但有可能一分钟内任务并没有执行完成,这时系统会再执行任务。导致两个相同的任务在执行。
例如:
<?
//
test
.php
java-74-数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字
bylijinnan
java
public class OcuppyMoreThanHalf {
/**
* Q74 数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字
* two solutions:
* 1.O(n)
* see <beauty of coding>--每次删除两个不同的数字,不改变数组的特性
* 2.O(nlogn)
* 排序。中间
linux 系统相关命令
candiio
linux
系统参数
cat /proc/cpuinfo cpu相关参数
cat /proc/meminfo 内存相关参数
cat /proc/loadavg 负载情况
性能参数
1)top
M:按内存使用排序
P:按CPU占用排序
1:显示各CPU的使用情况
k:kill进程
o:更多排序规则
回车:刷新数据
2)ulimit
ulimit -a:显示本用户的系统限制参
[经营与资产]保持独立性和稳定性对于软件开发的重要意义
comsci
软件开发
一个软件的架构从诞生到成熟,中间要经过很多次的修正和改造
如果在这个过程中,外界的其它行业的资本不断的介入这种软件架构的升级过程中
那么软件开发者原有的设计思想和开发路线
在CentOS5.5上编译OpenJDK6
Cwind
linux OpenJDK
几番周折终于在自己的CentOS5.5上编译成功了OpenJDK6,将编译过程和遇到的问题作一简要记录,备查。
0. OpenJDK介绍
OpenJDK是Sun(现Oracle)公司发布的基于GPL许可的Java平台的实现。其优点:
1、它的核心代码与同时期Sun(-> Oracle)的产品版基本上是一样的,血统纯正,不用担心性能问题,也基本上没什么兼容性问题;(代码上最主要的差异是
java乱码问题
dashuaifu
java乱码问题 js中文乱码
swfupload上传文件参数值为中文传递到后台接收中文乱码 在js中用setPostParams({"tag" : encodeURI( document.getElementByIdx_x("filetag").value,"utf-8")});
然后在servlet中String t
cygwin很多命令显示command not found的解决办法
dcj3sjt126com
cygwin
cygwin很多命令显示command not found的解决办法
修改cygwin.BAT文件如下
@echo off
D:
set CYGWIN=tty notitle glob
set PATH=%PATH%;d:\cygwin\bin;d:\cygwin\sbin;d:\cygwin\usr\bin;d:\cygwin\usr\sbin;d:\cygwin\us
[介绍]从 Yii 1.1 升级
dcj3sjt126com
PHP yii2
2.0 版框架是完全重写的,在 1.1 和 2.0 两个版本之间存在相当多差异。因此从 1.1 版升级并不像小版本间的跨越那么简单,通过本指南你将会了解两个版本间主要的不同之处。
如果你之前没有用过 Yii 1.1,可以跳过本章,直接从"入门篇"开始读起。
请注意,Yii 2.0 引入了很多本章并没有涉及到的新功能。强烈建议你通读整部权威指南来了解所有新特性。这样有可能会发
Linux SSH免登录配置总结
eksliang
ssh-keygen Linux SSH免登录认证 Linux SSH互信
转载请出自出处:http://eksliang.iteye.com/blog/2187265 一、原理
我们使用ssh-keygen在ServerA上生成私钥跟公钥,将生成的公钥拷贝到远程机器ServerB上后,就可以使用ssh命令无需密码登录到另外一台机器ServerB上。
生成公钥与私钥有两种加密方式,第一种是
手势滑动销毁Activity
gundumw100
android
老是效仿ios,做android的真悲催!
有需求:需要手势滑动销毁一个Activity
怎么办尼?自己写?
不用~,网上先问一下百度。
结果:
http://blog.csdn.net/xiaanming/article/details/20934541
首先将你需要的Activity继承SwipeBackActivity,它会在你的布局根目录新增一层SwipeBackLay
JavaScript变换表格边框颜色
ini
JavaScript html Web html5 css
效果查看:http://hovertree.com/texiao/js/2.htm代码如下,保存到HTML文件也可以查看效果:
<html>
<head>
<meta charset="utf-8">
<title>表格边框变换颜色代码-何问起</title>
</head>
<body&
Kafka Rest : Confluent
kane_xie
kafka REST confluent
最近拿到一个kafka rest的需求,但kafka暂时还没有提供rest api(应该是有在开发中,毕竟rest这么火),上网搜了一下,找到一个Confluent Platform,本文简单介绍一下安装。
这里插一句,给大家推荐一个九尾搜索,原名叫谷粉SOSO,不想fanqiang谷歌的可以用这个。以前在外企用谷歌用习惯了,出来之后用度娘搜技术问题,那匹配度简直感人。
环境声明:Ubu
Calender不是单例
men4661273
单例 Calender
在我们使用Calender的时候,使用过Calendar.getInstance()来获取一个日期类的对象,这种方式跟单例的获取方式一样,那么它到底是不是单例呢,如果是单例的话,一个对象修改内容之后,另外一个线程中的数据不久乱套了吗?从试验以及源码中可以得出,Calendar不是单例。
测试:
Calendar c1 =
线程内存和主内存之间联系
qifeifei
java thread
1, java多线程共享主内存中变量的时候,一共会经过几个阶段,
lock:将主内存中的变量锁定,为一个线程所独占。
unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量。
read:将主内存中的变量值读到工作内存当中。
load:将read读取的值保存到工作内存中的变量副本中。
schedule和scheduleAtFixedRate
tangqi609567707
java timer schedule
原文地址:http://blog.csdn.net/weidan1121/article/details/527307
import java.util.Timer;import java.util.TimerTask;import java.util.Date;
/** * @author vincent */public class TimerTest {
 
erlang 部署
wudixiaotie
erlang
1.如果在启动节点的时候报这个错 :
{"init terminating in do_boot",{'cannot load',elf_format,get_files}}
则需要在reltool.config中加入
{app, hipe, [{incl_cond, exclude}]},
2.当generate时,遇到:
ERROR