文档章节

Android 高级工程师面试(二)

O
 Oschina_wlc
发布于 2016/11/08 17:35
字数 22357
阅读 70
收藏 4

五、Android中的动画
1、Android中的动画有哪几类,它们的特点和区别是什么
Android 中动画分为两种,一种是Tween 动画、还有一种是 Frame 动画。
Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化;
Frame 动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。


2、如何修改Activity进入和退出动画
可 以 通 过 两 种 方 式 , 一 是 通 过 定 义 Activity 的 主 题 , 二 是 通 过 覆 写 Activity 的
overridePendingTransition方法。
通过设置主题样式
在styles.xml中编辑如下代码:
<style name="AnimationActivity" parent="@android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">@anim/slide_in_left</item>
<item name="android:activityOpenExitAnimation">@anim/slide_out_left</item>
<item name="android:activityCloseEnterAnimation">@anim/slide_in_right</item>
<item name="android:activityCloseExitAnimation">@anim/slide_out_right</item>
</style>
添加themes.xml文件:
<style name="ThemeActivity">
<item name="android:windowAnimationStyle">@style/AnimationActivity</item>
<item name="android:windowNoTitle">true</item>
</style>
在AndroidManifest.xml中给指定的 Activity 指定 theme。
覆写 overridePendingTransition方法
overridePendingTransition(R.anim.fade, R.anim.hold);
3、属性动画,例如一个 button从A 移动到B 点,B 点还是可以响应点击事件,这个原理是什么?
补间动画只是显示的位置变动,View 的实际位置未改变,表现为 View 移动到其他地方,点击事
件仍在原处才能响应。而属性动画控件移动后事件相应就在控件移动后本身进行处理


六、ContentObserver 内容观察者作用及特点
一、 ContentObserver 目的是观察(捕捉)特定 Uri引起的数据库的变化, 继而做一些相应的处理。
它类似于数据库技术中的触发器(Trigger),当 ContentObserver 所观察的 Uri 发生变化时,便
会 触发 它 。 触发 器 分为 表 触发 器 、 行触 发 器, 相 应地 ContentObserver 也 分为 “表
“ContentObserver、“行”ContentObserver,当然这是与它所监听的 Uri MIME Type 有关的。
1) 注册ContentObserver 方法
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer)
功能:为指定的 Uri 注册一个 ContentObserver 派生类实例,当给定的 Uri 发生改变时,回调
该实例对象去处理。
参数: uri 表示需要观察的 Uri
notifyForDescendents 为 false 表示精确匹配,即只匹配该 Uri。 为 true 表示可以同时匹配
其派生的Uri。
取消注册ContentObserver 方法
public final void unregisterContentObserver(ContentObserver observer)
功能:取消对给定Uri的观察
参数: observer ContentObserver的派生类实例
ContentObserver 类介绍
构造方法 ContentObserver(Handler h)
void onChange(boolean selfChange) 功能:当观察到的 Uri 发生变化时,回调该方法去处理。
所有 ContentObserver 的派生类都需要重载该方法去处理逻辑。
3.观察特定 Uri 的步骤如下:
1、创建我们特定的ContentObserver 派生类,必须重载父类构造方法,必须重载 onChange()
方法去处理回调后的功能实现
2 、 利 用 context.getContentResolover() 获 ContentResolover 对 象 , 接 着 调 用
registerContentObserver()方法去注册内容观察者
3、在不需要时,需要手动的调用 unregisterContentObserver()去取消注册。
例子:监听短信内容变化
在 Activity 中:
public class Day0108_contentobserverActivity extends Activity {
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 100:
String body = (String) msg.obj;
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(body);
break;
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ContentResolver cr = getContentResolver();
ContentObserver smsObserver = new
SmsContentObserver(this,handler);
//第二个参数,true表示观察所有有关短信的
cr.registerContentObserver(Uri.parse("content://sms"),
true, smsObserver);
//content://sms/inbox //收件箱
//content://sms/sent //已发送
//content://sms/draft //草稿箱
//content://sms/outbox //发件箱
//content://sms/failed //失败短信
//content://sms/queued //代发队列
}
}
//SmsContentObserver代码如下:
public class SmsContentObserver extends ContentObserver {
private Handler handler;
private Context context;
public SmsContentObserver(Context context,Handler
handler) {
super(handler);
this.handler = handler;
this.context = context;
}
@Override
public void onChange(boolean selfChange) {
ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(Uri.parse("content://sms/inbox"),
null, "0", null, "date desc");
StringBuilder sb = new StringBuilder();
while(c.moveToNext()){
//发件人手机号码
String sendNumber = c.getString(
c.getColumnIndex("address"));
//信息内容
String body =
c.getString(c.getColumnIndex("body"));
//readType 表示是否已经读
int hasRead = c.getInt(c.getColumnIndex("read"));
if(hasRead == 0){//表示短信未读
System.out.println("短信未读"+sendNumber);
}
sb.append(sendNumber+":"+body+"\n");
}
handler.obtainMessage(100,sb.toString()).sendToTarget();
}
}
项目框架的使用(★★★)
一、 自我介绍
从姓名,工作多长时间,及项目开发的周期来说。
(1)姓名
(2)工作时间
(3)开发周期
例如, 你好,我是 XXX,到现在为止我工作了一年半,期间有做过三款 app。最近的一个项目开
发了两个月。(这时候可以把你准备好的手机里的app 打开给面试官看)
二、 开发中都使用过哪些框架、平台
1.EventBus(事件处理)
2.xUtils(网络、图片、ORM)
xUtils 分为四大模块:
1 DbUtils模块:Android中的orm框架(对象关系映射,它的作用是在关系型
数据库和业务实体对象之间作为一个映射),一行代码就可以进行增删改查。(Logo
新闻内容缓存到数据库 当没有网络的时候)
2 ViewUtils模块:android中的ioc框架(生命周期由框架控制),完全注解的方
式就可以进行对UI绑定和事件的绑定。
3 HttpUtils模块:(请求服务器 客户端 传过去标示 head=”md5”)
a. 支持同步,异步方式的请求。
b. 支持大文件上传,上传大文件不会oom(内存溢出)。
c. 支持 GET,POST,DELETE 请求。
4 BitmapUtil模块:
可以先说下三级缓存的原理:
1. 从缓存中加载。
2. 从本地文件中加载(数据库,SD)
3. 从网络加载。
a.加载bitmap的时候无需考虑bitmap加载过程中出现的oom(内存溢出)和android容器快速
滑动的时候出现的图片错位等现象。(16M)
b. 支持加载网络图片和本地图片。
c. 内存管理使用的 lru算法(移除里面是有频率最少的对象),更好的管理bitmap 的内存。
d.可配置线程加载的数量,缓存的大小,缓存的路径,加载显示的动画等。
清除缓存是怎么做的?
(1)清除内存的缓存。
(2)数据库,SD。
注:需要添加一下权限<uses-permission android:name="android.permission.INTERNET" /> <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
3.JPush(推送平台)
推送的好处:
a. 及时主动性。(这是推送服务最基本的特点,即当有新的信息需要提交时,依据传送信息的类型
和重要性不同,推送软件会主动提醒用户接收新信息。从而提高了用户获取信息的及时性。)
b. 针对目的性。(推送服务提供的信息是根据用户的特定需求定的,这充分体现了用户的个性化需
求。这种个性化的服务还是动态的,用户只需在定制之初描述信息需求,推送软件就会自动跟踪
用户的使用倾向,实时地完成特定信息的推送。)
c. 便捷高效性。(用户只需输入一次信息请求,就可获得连续的信息服务。推送服务还采用信息代
理机制,可以自动跟踪用户的信息需求。这样的推送服务既节省了用户主动拉取的时间,又减少
了冗余信息的传递提高了信息的匹配度,从而大大方便了用户,提高了效率。)
我们在项目中主要使用的是极光推送, 在极光的官网里 (https://www.jpush.cn/) 下载 android
的 demo,将 demo中的 aapid 换成自己申请的,测试推送,然后集成到自己的项目中去。
4.友盟(统计平台)
5.有米(优米)(广告平台)
6.百度地图
1) 下载百度地图移动版API(Android)开发包
要在 Android 应用中使用百度地图API,就需要在工程中引用百度地图API 开发包,这个开发包包
含两个文件:baidumapapi.jar和 libBMapApiEngine.so。下载地址:
http://dev.baidu.com/wiki/static/imap/files/BaiduMapApi_Lib_Android_1.0.zip
2) 申请API Key
和使用 Google map api 一样,在使用百度地图 API 之前也需要获取相应的 API Key。百度地图 API
Key 与你的百度账户相关联,因此您必须先有百度帐户,才能获得 API Key;并且,该 Key 与您引用
API 的程序名称有关。
百度 API Key 的申请要比 Google的简单多了,其实只要你有百度帐号,应该不超过 30秒就能完成
API Key 的申请。申请地址:http://dev.baidu.com/wiki/static/imap/key/
3) 创建一个Android工程
这里需要强调一点:百度地图移动版api 支持 Android 1.5 及以上系统,因此我们创建的工程应
基于 Android SDK 1.5 及以上。
工程创建完成后,将 baidumapapi.jar 和 libBMapApiEngine.so 分别拷贝到工程的根目录及
libs/armeabi 目录下,并在工程属性->Java Build Path->Libraries 中选择“Add JARs”,选
定 baidumapapi.jar,这样就可以在应用中使用百度地图API 了。
7.bmob(服务器平台、短信验证、邮箱验证、第三方支付)
8.阿里云OSS(云存储)
9.ShareSDK(分享平台、第三方登录)
SDK 简介: ShareSDK 是为 iOS 的 APP 提供社会化功能的一个组件,开发者只需 10 分钟
即可集成到自己的APP 中,它不仅支持如 QQ、微信、新浪微博、腾讯微博、开心网、人人网、
豆瓣、网易微博、搜狐微博、facebook、twitter、google+等国内外主流社交平台,还有强大
的统计分析管理后台,可以实时了解用户、信息流、回流率、传播效应等数据,有效的指导日常
运营与推广,同时为APP引入更多的社会化流量。
主要功能:
a. 支持分享到主流的各大平台上。 (国内主要的分享平台: QQ ,微信 , 新浪微博 , 腾讯微博 国
外的:facebook twitter google+)
b. 支持获取授权用户资料及其他用户资料,可以通过sdk 制作使用新浪微博登录,QQ 登录等。
c. 支持关注官方微博,支持@好友,插入话题,图片。
d. 支持一键分享,用户可以一次性将内容分享至全部的社交平台。
使用:
(1)获取SharedSDK。(SharedSDK官网:http://wiki.mob.com/)
(2)将SharedSDK 集成(导入)到项目的libs目录下。
(3)配置AndroidManifest.xml 权限
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
(4)添加代码,启动SDK。SMSSDK.initSDK(this, "<您的 appkey>", "<您的 appsecret>");
10.Gson(解析json数据框架)
根据服务器返回的Gson 数据来设计类的模型,让 Gson 解析字符串为对应的对象模型。简
单来讲就是 根据 json的数据结构定义出相应的 javabean --->"new"出 Gson 的实例
gson---->gson.fromJson( jsonString,JavaBean.class) 即可.
面试概要:
可以先说下 Gson 的作用,然后在向后拓展下。(Gson 呢,是 google 提供的一个快速解析 json
数据的开源框架,原来我们解析数据的时候都是jsonObject jsonArray 一层层解析, 我发现这样层层
解析很浪费时间,于是我在业余时间研究了 Gson,Gson 满足了我们快速开发的特性,只要从服务
器拿到 json数据用 Gson 解析,Gson 就会返回一个数据对象,我们就可以直接对数据进行操作了。
原来解析可能需要十几分钟的事,现在两三分钟就搞定了)
补充:为什么数据要以json形式传输?
1 易读性
2 高效率
11.imageLoader (图片处理框架)
12.zxing (二维码扫描)
三、 都使用过哪些自定义控件
1.pull2RefreshListView
2.LazyViewPager
3.SlidingMenu
4.SmoothProgressBar
5.自定义组合控件
6.ToggleButton
7.自定义吐司(Toast)
四、 自定义控件:绘制圆环的实现过程
使用自定义控件绘制一个圆环,需要重现的方法是OnDraw()实现对view 的绘制, 从而
输出符合自己需求的view 控件
观察圆环的组成部分:
外层圆+中间百分比文字+不断变化进度的弧形圈
--->分析:每一个组成部分需要的属性,构成几个关键的自定义属性
1:外层圆的颜色
2:弧形进度圈的颜色
3:中间百分比文字的颜色
4:中间百分比文字的大小
5:圆环的宽度(作为进度弧形圈的宽度)
6:*首页当中也有一个圆环进度,为了兼容使用首页的圆环进度,增加一个自
定义属性,绘制进度弧形圈的风格(实心[Fill],空心[Stroken])
分析完毕-->绘制步骤:
1:构造方法当中初始化画笔对象,获取自定义的属性值.
2:重写Ondraw方法
---2.1:绘制最外层的圆
-关键方法canvas.drawCircle(center, center, radius, paint); //画出圆环
*:计算半径、中心点坐标、画笔设置
paint.setColor(roundColor); //设置圆环的颜色
paint.setStyle(Paint.Style.STROKE); //设置空心
paint.setStrokeWidth(roundWidth); //设置圆环的宽度---这个宽度也是提
供给进度弧形圈绘制的时候覆盖的宽度
paint.setAntiAlias(true); //消除锯齿
中心点坐标
int center = getWidth() / 2; //获取圆心的x坐标
半径:
int radius = (int) (center - roundWidth/2) ---画图说明最容易理解
---2.2:绘制中间的百分比文字
--关键方法:canvas.drawText(percent + "%", center - textWidth / 2,
center + textSize / 2, paint); //画出进度百分比
测量画笔上的文本宽度
float textWidth = paint.measureText(percent + "%");
画笔设置
paint.setStrokeWidth(0);
paint.setColor(textColor);
paint.setTextSize(textSize);
paint.setTypeface(Typeface.DEFAULT_BOLD); //设置字体
绘制的文字的位置,由参数2,3 的X,Y 坐标值决定--圆环的中心点位置显示
X:表示从哪开始绘制,如果你直接中心点开始绘制-->画图说明最容易理解
-->正确的 X=center - textWidth / 2;Y = center + textSize / 2 --(因为
android坐标系与数学坐标系Y 轴值是相反的,也可以画图说明,这里的textsize就可
以代表高度,paint.measureText 测量方法执行之后,默认的文字高度就是根据文字大
小计算的,相当于wrap_content,所以textSize就是本身文字所占的高度值)
*:绘制的进度要转换为百分比形式:int percent = (int) (((float) progress /
(float) max) * 100);
---2.3:绘制进度弧形圈
---关键方法:canvas.drawArc(oval, 0, 360 * progress / max, false, paint);
//根据进度画圆弧
参数解释:
oval:绘制的弧形的范围轮廓
0:从多少角度开始绘制
360 * progress / max:绘制弧形扫过的角度对应的区域
false:不包含圆心,如果是true,表示包含圆心
paint:绘制使用的画笔
画笔设置
paint.setStrokeWidth(roundWidth); //设置进度弧形圈的宽度,必须保持
和外层圆的StrokeWidth一致,确保弧形圈绘制的时候覆盖的范围就是外层圆的宽度
paint.setColor(roundProgressColor); //设置进度的颜色
弧形范围计算
RectF oval = new RectF(center - radius, center - radius, center
+ radius, center + radius); --->画图说明最容易理解
left:center - radius
top:center-radius
right:center+radius
bottom:center+radius
*:注意,因为progress是相对于100 当中占比多少,而弧形总共是按照角度
分成360 分的,所以绘制弧形圈指定参数扫过的区域角度需要计算转换一下
=360 * progress / max(max=100)
*:对应自定义属性中的最后一个属性是实心还是空心, 绘制的时候需要判断一
下,兼容首页的圆环进度处理
switch (style) {
case STROKE:{
paint.setStyle(Paint.Style.STROKE);
canvas.drawArc(oval, 0, 360 *
progress / max, false, paint); //根据进度画圆弧
break;
}
case FILL:{
paint.setStyle(Paint.Style.FILL_AND_STROKE);
if(progress !=0)
canvas.drawArc(oval, 0, 360 *
progress / max, true, paint); //根据进度画圆弧
break;
}
}
最后提供一个设置进度,根据进度重新绘制圆环的方法
public void setProgress(int progress) {
if(progress < 0){
throw new
IllegalArgumentException("progress not less than
0");
}
if(progress > max){
progress = max;
}
if(progress <= max){
this.progress = progress;
postInvalidate();
}
}
五、 自定义控件:摩天轮的实现过程
1 摩天轮控件是可以通过触摸旋转的,但旋转的过程中保持子View 的方向。
2 摩天轮控件中触摸旋转, 惯性转动的基础是自控件的摆放, 使用了三角函数来确定子view
的中心点位置,注意在分析阶段我们把摩天轮的中心点作为参考点(0,0),在写代码的时候,记得
偏移到控件左上方。
3 在触摸旋转和惯性旋转时,我们需要改变所有的孩子的位置,其实也就是孩子中心点与
圆心连线的角度,但因为角度间隔相等,所以只需要改变第一个孩子的角度,然后其他孩子与第
一个孩子保持角度间隔即可,然后调用requestLayout重新摆放孩子即可。
4 触摸旋转和惯性转动,都使用了 GestureDector 帮助我们判断触摸事件的类型,以及提
供给我们所需要的参数。
5 在触摸旋转中,我们通过计算当前点的角度和上一次点的角度,再算出两点的差,就可
以知道需要旋转多少角度了。
6 比较难的地方就是把惯性滑动的像素速度转化为角速度,对于没有学过微积分的同学可
能想不到。然后我们使用了值动画不断地改变角度来模拟转动,又使用了减速插值器来模拟减速。
7 因为摩天轮的触摸事件处理都是写在了 onTouchEven,t 方法中,如果子控件消费了触
摸 事 件 , 会 导 致 摩 天 轮 的 onToucheEvent 方 法 没 有 被 调 用 , 所 以 我 们 需 要 在
onInterceptTouchEvent方法中返回 ture,然后再检测单击事件发送给被点击的孩子。
六、 自定义控件:可拖拽排序的GridLayout 的实现过程
8 为什么没有使用GridView,而是使用了GridLayout;
因为 GridView必然需要一个 Adapter,而 Adapter需要数据集,如果在拖动中想要处理好
三者的关系,在编码实现上具有一定的难度。
GridLayout是安卓 4.0出现的一个新的布局,不需要适配器即可让每个子 View 占据一定的
格子,需要注意的是GridLayout的孩子可以横向、纵向地合并单元格。
9 布局动画是什么?
可详见 http://www.cnblogs.com/mengdd/p/3305973.html
布局动画可帮助我们非常简单地处理 ViewGroup的子控件的出现、消失、移动,是安卓 3.0
后出现的一个类。
10 Drag Drop框架是怎么回事?
DragDrop框架是安卓 3.0 后出现的,用户可以通过此框架以控件的形式移动“数据”,其
重要的方法有两个,都是view 上的:startDrag 和 setOnDragListener。
startDrag 方法要传递4 个参数,但最重要的就是第二个 ShadowBuilder,用于构建跟随手
指移动的影子,一般可在创建ShadowBuilder对象时,传入一个 view 作为影子的原形即可;
当产生影子后,安卓系统会发送 DragEvent 给当前应用中所有可见的View,如果想要接收
DragEvent,可通过 View 的 setOnDragListener方法,设置一个拖拽监听;
DragEvent有 6 种类型,分别是开始,结束、进入、退出、移动、放下。需要注意的是,如
果影子的中心点在设置了监听的控件之外移动或放下,是不会收到相应事件的。
在不同的事件类型中,还可以获得不同的数据,如图:
其中,x 和 y 是对于对设置监听的控件的左上角的位置,而 Clip数据是 startDrag 的第一个
参数的数据,LocalState是 startDrag 的第三个数据,Result是 Drop 事件的返回值。
七、 流式布局的实现过程
流式布局的特点以及应用场景
特点:当上面一行的空间不够容纳新的TextView 时候,
才开辟下一行的空间
原理图:
场景:主要用于关键词搜索或者热门标签等场景
2.自定义 ViewGroup,重点重写下面两个方法
1) onMeasure:测量子 view 的宽高,设置自己的宽和高
2) onLayout:设置子 view 的位置
onMeasure:根据子 view 的布局文件中属性,来为子view 设置测量模式和测量值
测量=测量模式+测量值;
测量模式有 3种:
EXACTLY:表示设置了精确的值,一般当 childView设置其宽、高为精确值、match_parent
时,ViewGroup会将其设置为 EXACTLY;
AT_MOST:表示子布局被限制在一个最大值内,一般当childView 设置其宽、高为
wrap_content时,ViewGroup会将其设置为AT_MOST;
UNSPECIFIED:表示子布局想要多大就多大,一般出现在AadapterView 的 item的
heightMode 中、ScrollView 的 childView 的 heightMode 中;此种模式比较少见
3) LayoutParams
ViewGroup LayoutParams :每个 ViewGroup 对应一个 LayoutParams; 即 ViewGroup ->
LayoutParams
getLayoutParams 不知道转为哪个对应的LayoutParams ,其实很简单,就是如下:
子View.getLayoutParams 得到的 LayoutParams对应的就是 子 View 所在的父控件的
LayoutParams;
例如,LinearLayout 里面的子 view.getLayoutParams ->LinearLayout.LayoutParams
所以 咱们的FlowLayout 也需要一个LayoutParams, 由于上面的效果图是子View的 margin,
所以应该使用 MarginLayoutParams。即 FlowLayout->MarginLayoutParams
八、 项目的流程
这个在项目中不一定问,但是大家要知道项目开发的流程,作为有经验的程序员程序
的流程是一定知道的。
按时间轴来排列:
立项:确定项目、负责人、开发的周期、成本、人力、物力
需求:文档、原型图
开发:编码
测试:测试人员
上线:产品部门
维护:修复新的bug
升级:改版、添加新的功能
九、 项目中常见的问题(11.9 更新)
1. 新闻详细页WebView 是怎么使用的?
WebView 是 View 的子类,可以让你在 activity 中显示网页。
1) 添加网络访问权限。
2) 调用 webview 的 loadUrl加载网络地址。
2. 如何去记录用户是否看过这条新闻?
1) 在新闻详情页用sharePrefence存入当前新闻的 id。
2) 在新闻列表的getView 方法中判断当前 id在数据中是否存在,存在的话将字体设置为灰色。
3. 在项目中,你是如何缓存数据的?
1) 我们可以说下数据是存在数据库中,并延伸到DButil的使用中去。
2) 将数据缓存到SD中。
4. 如何清除webview的缓存
1) LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
2) LOAD_DEFAULT: 根据 cache-control决定是否从网络上取数据。
3) LOAD_CACHE_NORMAL: API level 17 中 已 经 废 弃 , 从 API level 11 开 始 作 用 同
LOAD_DEFAULT模式
4) LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
5) LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者 no-cache,都使用缓存
中的数据。
6) 总结:根据以上两种模式,建议缓存策略为,判断是否有网络,有的话,使用 LOAD_DEFAULT,
无网络时,使用LOAD_CACHE_ELSE_NETWORK。
public class MainActivity extends AppCompatActivity { private WebView wView; private Button
btn_clear_cache;
private Button btn_refresh; private static final String APP_CACHE_DIRNAME = "/webcache"; //
web缓存目录
private static final String URL = "http://blog.csdn.net/coder_pig";
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main); wView = (WebView) findViewById(R.id.wView);
btn_clear_cache = (Button) findViewById(R.id.btn_clear_cache);
btn_refresh = (Button) findViewById(R.id.btn_refresh);
wView.loadUrl(URL); wView.setWebViewClient(new WebViewClient()
{ //设置在webView 点击打开的新网页在当前界面显示,而不跳转到新的浏览器中
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url); return true;
}
});
WebSettings settings = wView.getSettings(); settings.setJavaScriptEnabled(true); //设置缓存模式
settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); // 开启 DOM storage API
功能 settings.setDomStorageEnabled(true); // 开启database storage API 功能
settings.setDatabaseEnabled(true); String cacheDirPath = getFilesDir().getAbsolutePath() +
APP_CACHE_DIRNAME; Log.i("cachePath", cacheDirPath); // 设置数据库缓存路径
settings.setAppCachePath(cacheDirPath); settings.setAppCacheEnabled(true);
Log.i("databasepath", settings.getDatabasePath());
btn_clear_cache.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
wView.clearCache(true);
}
});
btn_refresh.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View
v) {
wView.reload();
}
}
);
} //重写回退按钮的点击事件 @Override public void onBackPressed()
{ if(wView.canGoBack()){ wView.goBack(); }else{ super.onBackPressed();
}
}
}
上面的示例,我们通过调用WebView 的 clearCache(true)方法,已经实现了对缓存的删除!
除了这种方法外,还有下述方法:
setting.setCacheMode(WebSettings.LOAD_NO_CACHE);
deleteDatabase(“WebView.db”);和 deleteDatabase(“WebViewCache.db”);
webView.clearHistory();
webView.clearFormData();
getCacheDir().delete();
手动写 delete方法,循环迭代删除缓存文件夹!
5. 如何实现第三方登录(以微信为例子)
1) 下载微信官方最新的sdk,集成到app 中。如下图:
2) 注册到微信
可以在 app 的某个 Activity 的 onCreate 方法中注册,这里也可以在 app 的 application 的
onCreate()方法中注册,这样,在整个app 的中都可以使用。例如:
public class CarApplication extends Application{
…… …… ……
public static IWXAPI api;
public void onCreate() {
//注册微信
api = WXAPIFactory.createWXAPI(this, “你的应用在微信上申请的 app_id”, true);
api.registerApp(“你的应用在微信上申请的app_id”);
在 app 的包名目录下新建一个wxapi目录, 然后在此目录下新建WXEntryActivity.java文件, 如下,
app 的包名为carjob.com.cn,新建的wxapi目录如下。(注意:一定是包名目录下新建,不要在
其他目录新建,否则WXEntryActivity.java里的 public void onResp(BaseResp resp)方法不会被
调用)
WXEntryActivity 继承 Activity,实现IWXAPIEventHandler,并重写
protected void onNewIntent(Intent intent)、public void onReq(BaseReq arg0)、
public void onResp(BaseResp resp)方法。WXEntryActivity.java文件可以见最后附录。
3) 发送微信登录的请求
app 中点击某一个view,发送微信登录的请求如下:
final SendAuth.Req req = new SendAuth.Req();
req.scope = "snsapi_userinfo";
req.state = "carjob_wx_login";
CarApplication.api.sendReq(req);
其中,CarApplication.api就是第 2 步中注册的 IWXAPI对象。
请求成功后,可拉起微信的授权登录页面,如下。用户点击“确认登录”后,SDK通过 SendAuth
的 Resp返回数据给调用方(即app),此时WXEntryActivity 中的
public void onResp(BaseResp resp)方法被调用 (微信、 朋友圈分享成功后, 此方法同样会被调用) ,
微信登录的返回值说明如下。这里app 可以做相关的处理,见WXEntryActivity.java文件中的处理,
取 code为下一步获取 access_token 和 openid 等信息做准备。
6. 如何实现文件断点上传
在 Android 中上传文件可以采用HTTP 方式,也可以采用 Socket方式,但是 HTTP 方式不能上传
大文件,这里介绍一种通过Socket方式来进行断点续传的方式,服务端会记录下文件的上传进度,
当某一次上传过程意外终止后,下一次可以继续上传,这里用到的其实还是J2SE 里的知识。
这个上传程序的原理是:客户端第一次上传时向服务端发送
“Content-Length=35;filename=WinRAR_3.90_SC.exe;sourceid=“这种格式的字符串,服务端
收到后会查找该文件是否有上传记录,如果有就返回已经上传的位置,否则返回新生成的sourceid
以及 position为 0,类似 sourceid=2324838389;position=0“这样的字符串,客户端收到返回后
的字符串后再从指定的位置开始上传文件。
7. 什么是socket?
所谓Socket通常也称作“套接字”,用于描述 IP 地址和端口,是一个通信连的句柄,应用程序
通常通过“套接字”向网络发送请求或者响应网络请求,它就是网络通信过程中端点的抽象表示。
主要包括以下两个协议:
TCP (Transmission Control Protocol 传输控制协议):传输控制协议,提供的是面向连接、可靠
的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个 TCP连接,之后才能
传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到
另一端。
UDP (User Datagram Protocl 用户数据报协议):用户数据报协议,是一个简单的面向数据报
的运输层协议。UDP不提供可靠性,它只是把应用程序传给 IP层的数据报发送出去,但是并不能保
证它们能到达目的地。由于 UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超
时重发等机制,故而传输速度很快。
8. 谈谈你在工作中是怎样解决一个bug
思路大体和上面差不多,
1) 异常附近多打印log信息;
2) 分析 log日志,实在不行的话进行断点调试;
3) 调试不出结果,上Stack Overflow 贴上异常信息,请教大牛
4) 再多看看代码,或者从源代码中查找相关信息
5) 实在不行就 GG了,找师傅来解决!
9. 怎样对android进行优化?
1) 对 listview的优化。
2) 对图片的优化。
3) 对内存的优化。
尽量不要使用过多的静态类static
数据库使用完成后要记得关闭cursor
广播使用完之后要注销
10. 谈谈你对Bitmap的理解, 什么时候应该手动调用bitmap.recycle()(重要)
Bitmap是android 中经常使用的一个类,它代表了一个图片资源。 Bitmap 消耗内存很严重,如果
不注意优化代码,经常会出现 OOM 问题,优化方式通常有这么几种: 1. 使用缓存; 2. 压缩图片;
3. 及时回收;
至于什么时候需要手动调用recycle,这就看具体场景了,原则是当我们不再使用Bitmap 时,需要
回收之。另外,我们需要注意,2.3之前 Bitmap对象与像素数据是分开存放的,Bitmap 对象存在
java Heap 中而像素数据存放在 Native Memory 中, 这时很有必要调用 recycle 回收内存。 但是 2.3
之后,Bitmap对象和像素数据都是存在Heap 中,GC 可以回收其内存。
11. 请介绍下AsyncTask的内部实现,适用的场景是
AsyncTask内部也是 Handler 机制来完成的,只不过 Android 提供了执行框架来提供线程池来
执行相应地任务,因为线程池的大小问题,所以 AsyncTask 只应该用来执行耗时时间较短的任务,
比如 HTTP 请求,大规模的下载和数据库的更改不适用于AsyncTask,因为会导致线程池堵塞,没有
线程来执行其他的任务,导致的情形是会发生AsyncTask根本执行不了的问题。
12. 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 内存泄露的根本原因就是 保存了不可能再被访问的变量类型的引用
检测内存工具 heap
13. 说说mvc 模式的原理,它在android中的运用。(重要)
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中显示。
另一种方式解da:
a.模型(model)对象:是应用程序的主体部分,所有的业务逻辑都应该写在该层。
b. 视图(view)对象:是应用程序中负责生成用户界面的部分。也是在整个mvc架构中用户唯
一可以看到的一层,接收用户的输入,显示处理结果。
c.控制器(control)对象:是根据用户的输入,控制用户界面数据显示及更新 model 对象状态
的部分
View:自定义 View 或 ViewGroup,负责将用户的请求通知 Controller,并根据 model 更新界
面;
Controller:Activity 或者 Fragment,接收用户请求并更新 model;
Model:数据模型,负责数据处理相关的逻辑,封装应用程序状态,响应状态查询,通知 View
改变,对应 Android 中的 datebase、SharePreference等。
14. 你一般在开发项目中都使用什么设计模式?如何来重构,优化你的代码?
较为常用的就是单例设计模式和工厂设计模式以及观察者设计模式,一般需要保证对象在内存中
的唯一性时就是用单例模式,例如对数据库操作的 SqliteOpenHelper 的对象。厂模式主要是为创建
对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通
知并被自动更新
15. Android应用中验证码登陆都有哪些实现方案
验证码应该只有两种获取方式: 从服务器端获取图片, 通过短信服务,将验证码发送给客户端
这两种。
16. 定位项目中,如何选取定位方案,如何平衡耗电与实时位置的精度?
始定位,Application持有一个全局的公共位置对象,然后隔一定时间自动刷新位置,每次刷新成功
都把新的位置信息赋值到全局的位置对象, 然后每个需要使用位置请求的地方都使用全局的位置信息
进行请求。 该方案好处:请求的时候无需再反复定位,每次请求都使用全局的位置对象,节省时间。
该方案弊端:耗电,每隔一定时间自动刷新位置,对电量的消耗比较大。
方案 2:按需定位,每次请求前都进行定位。这样做的好处是比较省电,而且节省资源,但是请求时
间会变得相对较长。

17. andorid应用第二次登录实现自动登录
我来说一个实际案例的流程吧。前置条件是所有用户相关接口都走https,非用户相关列表类数据
走 http。 1. 第一次登陆 getUserInfo里带有一个长效 token,该长效token用来判断用户是否登
陆和换取短 token 2. 把长效 token保存到SharedPreferences 3. 接口请求用长效 token换取短
token,短 token服务端可以根据你的接口最后一次请求作为标示,超时时间为一天。 4. 所有接口
都用短效token 5. 如果返回短效 token失效,执行 3 再直接当前接口 6. 如果长效 token失效(用
户换设备或超过两周),提示用户登录。
18. 说说LruCache底层原理
LruCache使用一个LinkedHashMap 简单的实现内存的缓存,没有软引用,都是强引用。如果添
加的数据大于设置的最大值,就删除最先缓存的数据来调整内存。
maxSize 是通过构造方法初始化的值,他表示这个缓存能缓存的最大值是多少。
size在添加和移除缓存都被更新值, 他通过 safeSizeOf这个方法更新值。 safeSizeOf 默认返回1,
但一般我们会根据maxSize 重写这个方法,比如认为maxSize 代表是 KB 的话,那么就以 KB 为单
位返回该项所占的内存大小。
除异常外首先会判断size 是否超过maxSize,如果超过了就取出最先插入的缓存,如果不为空就
删掉,并把 size 减去该项所占的大小。这个操作将一直循环下去,直到 size 比 maxSize 小或者缓存
为空。
19. jni的调用过程?
1. 安装和下载 Cygwin,下载 Android NDK。
2. ndk项目中 JNI接口的设计。
3. 使用 C/C++实现本地方法。
4. JNI生成动态链接库.so 文件。
5. 将动态链接库复制到java工程,在 java工程中调用,运行 java工程即可。
20. 手机APP安全登录的几种方式
一、登录过程的用户认证,常见的手段有密码加密传输、动态密码、验证码等。
1、密码加密。
目前互联网行业的移动 APP 有不少在使用最简单的做法:根据密码生成一个散列值,把散列值
发送给服务器。服务器计算库中用户密码的散列值,然后和客户端传来的散列值比较,一致的话,登
录成功。
如果安全性要求更高一些的话,常见的做法就是公钥加密。具体做法是这样,登录前先向服务器
请求一个公钥密钥,用公钥密钥加密一串根据密码生成的散列值,然后发送给服务器。服务器使用私
钥密钥解密,然后与根据数据库中的用户密码计算出来的散列值进行比较,一致的话,登录成功。当
然,还可以做的更优化一些,就是控制公钥密钥的有效期来增强安全性,比如公钥 10秒钟失效、只
能 使 用 一 次 等 。 关 于 公 钥 加 密 , 可 以 参 考 这 篇 文 章 :
http://www.360doc.com/content/11/0406/17/4146412_107621805.shtml
2、动态密码。
关于动态密码,其本质就是选择另外一种可以识别用户身份唯一性的方式来和用户的静态密码一
起 做 用 户 认 证 。 具 体 常 见 的 几 种 实 现 手 段 , 可 以 参 考 这 篇 文 章 :
http://baike.soso.com/v5973952.htm
目前市面上适合 App 使用的最常见的方式是利用手机短信进行动态密码认证。即用户常规登录
时,如果服务器发现有异常,可以向用户手机发送一条包含动态密码的短信,用户在有效期(常见的
是 30秒到1 分钟)内把用户名、用户密码、动态密码一起发送给服务器进行验证。这个对用户来说,
操作门槛比较低,也很方便。
3、验证码。
服务器一旦发现登录有异常,如IP 变化、短时间内登录次数过多等,会向App 下发一个图片,
用户把图片中要求输入的数据和用户名、用户密码一起提交给服务器。
为了降低用户登录过程的复杂性,通常情况下,用户只需要输入用户名和密码,只有服务器发现
异常情况才会启用验证码、动态密码等机制。
二、减少用户输入次数的自动登录。
App 登录成功后,服务器会告诉App 一个 session,后续交流都使用 session。但通常为了安全
起见 session都是要设置有效期的,从 1 星期到20 天都见过。那么,为了不让用户在session 失效
后重新登录,减少用户的手动输入用户名和用户密码的次数,引入了“自动登录”概念。
流程如下:
登录成功后,服务器给 App 下发 sesion的同时,还下发一个认证token,客户端把 token做为
应用程序的私有数据存储起来。以后,每当 session 过期后,就把 token 发送给服务器获取新的
session。整个过程都是对用户透明的,对用户来说,输入一次用户名和密码后,就再也没有登录这
个事情了。
当然,这种自动登录的前提,是能保证 token 的安全性远大于 session。我们知道,由于手机
OS 的安全机制,token 做为应用程序的私有数据,对其它应用是不可见的,可以保证token的安全
性。我们还可以再上一个锁,把 token和用户使用 App 的那个设备做绑定。可供选择的绑定数据有
imsi,mac等。这样的话,只要用户手机不丢,就没事。
没有一种安全机制是绝对安全的,我们需要在实际应用过程中综合运用 App 使用场景、具体业
务类型、用户习惯等各种方式来平衡安全性、用户体验还有商业应用中很重要的成本。
十、 即时通讯是是怎么做的?
1.我在之前的项目中使用了asmark开源框架实现的即时通讯功能.该框架基于开源的XMPP即时
通信协议,采用 C/S 体系结构,通过 GPRS 无线网络用 TCP 协议连接到服务器,以架设开源的
Openfn'e服务器作为即时通讯平台。
2. 客户端基于 Android 平台进行开发。负责初始化通信过程,进行即时通信时,由客户端负责向
服务器发起创建连接请求。系统通过GPRS 无线网络与 Internet网络建立连接,通过服务器实现与
Android 客户端的即时通信脚。
3.服务器端则采用 Openfire 作为服务器。 允许多个客户端同时登录并且并发的连接到一个服务器
上。服务器对每个客户端的连接进行认证,对认证通过的客户端创建会话,客户
端与服务器端之间的通信就在该会话的上下文中进行。
客户端的补充内容:
a. 客户端分为五大模块开发:
通讯模块负责与服务器建立通讯旧。通过创建 3个线程来进行处理。分别负责消息的发送、接收和系
统信息的发送.
解析模块主要用来解析XML数据流根据解析元素不同类型封装成不同的数据对象.
数据模块定义整个客户端中大部分的数据类型和对象;
应用模块包括即时通信、图片浏览和音乐播放。是客户端和用户交流的接口.
加密模块对发送和接收的消息进行加解密。以确保通讯数据的安全。
b. xmpp 协议补充内容:
1.XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)
以及在线现场探测。它在促进服务器之间的准即时操作。这个协议可能最终允许因特网用户向因特网
上的其他任何人发送即时消息,即使其操作系统和浏览器不同。
2.XMPP协议的优势
与 HTTP 相比,XMPP具有如下的优势:
(1)能够“推送”数据,而不是“拉”。
(2)防火墙友好
(3)牢固的身份验证和安全机制
(4)为许多不同的问题提供大量即开即用的工具
3.XMPP协议的不足
每种协议都有各自的优缺点,在许多场合中XMPP并不是完成任务的最佳工具或受到某种限制。
(1)有状态协议
(2)社区和部署不及HTTP 广泛
(3)对于简单的请求,其开销比HTTP 大
(4)仍然需要zhuan门的实现
4.XMPP协议的数据格式
在 XMPP中,各项工作都是通过在一个XMPP流上发送和接收 XMPP节来完成的。核心 XMPP工
具集由三种基本节组成,这三种节分别为<presence>、出席<message>、<iq>。
XMPP流由两份 XML文档组成,通信的每个方向均有一份文档。这份文档有一个根元素
<stream:stream>,这个根元素的子元素由可路由的节以及与流相关的顶级子元素构成。
下面给出一段简短的XMPP会话:roster 花名册
拉取联系人
<stream:stream>
<iq type='get'>
<query xmlns='jabber:iq:roster'/>
</iq>
<presence type=’available’>
<message from='laowang@itcast.cn' />
</stream:stream>
简单解释下:
(1)laowang 登陆后,将自己的第一节(一个<iq>元素)发送出去,这个<iq>元素请求 laowang
的联系人列表。
(2)接下来,他使用<presence>节通知服务器他在线并且可以访问。
(3)当 laowang 注意到 cui也在线时,他发送了一条<message>节给 cui。
(4)最后,laowang发送了一个<presence>节告诉服务器自己不可访问并关闭<stream:stream>
元素,然后结束会话。
所有三种节都支持一组通用的属性:
(1)from
(2)to
(3)type
(4)id
5.1 presence 节
<presence>节控制并报告实体Jid的可访问性,
Mode: 在线chat、离线 away 、离开xa、请勿打扰 dnd
Type:available, unavailable,subscribe,subscribed,unsubscribe,
Unsubscribed,error
此外,这个节还用来建立和终止向其他实体发布出席订阅。
普通 presence节
普通<presence>节不含 type 属性,或者 type 属性值为 unavailable或 error。type 属性没有
available值,因为可以通过缺少type属性来指出这种情况。
用户通过发送不带to属性,直接发往服务器的<presence>节来操纵自己的出席状态。
<presence/>
<presence type='unavailable'/>
<presence>
<show>away</show>
<status>at the ball</status>
<presence/>
<presence>
<status>touring the countryside</status>
<priority>10</priority>
</presence>
<presence>
<priority>10</priority>
</presence>
简单解释:
(1)<show>元素用来传达用户的可访问性,只能出现在<presence>节中。该元素的值可以为:
away、chat、dnd和 xa,分别表示离开、有意聊天、不希望被打扰和长期离开。
(2)<status>元素时一个人类可读的字符串,在接收者的聊天客户端中,这个字符串一般会紧挨着
联系人名字显示。
(3)<priority>元素用来指明连接资源的优先级,介于-128~127,默认值为 0。
扩展 presence节
开发人员希望能够扩展<presence>节以包含更详细的信息,比如用户当前听的歌或个人的情绪。
因为<presence>节会广播给所有联系人,并且在XMPP网络流量中占据了很大的份额,所以不鼓
励这种做法。这类扩展应该交给额外信息传送协议来处理。
出席订阅
用户的服务器会自动地将出席信息广播给那些订阅该用户出席信息的联系人。类似的,用户从所有他
已经出席订阅的联系人那里接收到出席更新信息。
与一些社交网络和IM 系统不同,在XMPP中,出席订阅是有方向的。我订阅了你的出席信息,但
是你并不一定订阅了我的出席信息。
可以通过设置type的值来识别出席订阅节:subscribe(请求加好友)、unsubscribe(删除好友)、
subscribed(接受加好友的请求)、unsubscribed(拒绝加好友的请求)。
public enum Type {
/**
* The user is available to receive messages (default).
*/
available,
/**
* The user is unavailable to receive messages.
*/
unavailable,
/**
* Request subscription to recipient's presence.
*/
subscribe,
/**
* Grant subscription to sender's presence.
*/
subscribed,
/**
* Request removal of subscription to sender's
presence.
*/
unsubscribe,
/**
* Grant removal of subscription to sender's
presence.
*/
unsubscribed,
/**
* The presence packet contains an error message.
*/
error
}
定向出席
定向出席是一种直接发给另一个用户或其他实体的普通<presence>节,这种节用来向那些没有进行
出席订阅(通常因为只是临时需要出席信息)的实体传达出席状态信息。
message 节
<message>节用来从一个实体向另一个实体发送消息。这些可以是简单的聊天信息,也可以是任何
结构化信息。例如,绘制指令、游戏状态和新游戏变动状况。
<message>属于发送后不管的类型,没有内在的可靠性,就像电子邮件一样。在有些情况下(比如
向不存在的服务器发送信息),发送者可能会收到一个错误提示节,从中了解出现的问题。可以通过
在应用程序协议中增加确认机制来实现可靠传送。
消息类型
<message>节有几种不同的类型,这些类型由 type 属性指出,可取的值有:chat、error、normal、
groupchat和 headline。该属性是可选的,如果没有指定type 值,默认为 normal。
normal a normal text message used in email like interface
groupchat Chat message sent to a groupchat server for group chats.
chat Chat message sent to a groupchat server for group chats
消息内容
尽管<message>节可以包含任意扩展元素,但<body>和<thread>元素是为向消息中添加内容提
供的正常机制。这两种子元素均是可选的。
Sets the thread id of the message, which is a unique identifier for a sequence of "chat"
messages. thread the thread id of the message.
IQ 节
<iq>节表示的是 Info/Query,它为 XMPP通信提供请求和响应机制。它与 HTTP 协议的基本工作
原理非常相似,允许获取和设置查询,与HTTP 的 GET 和 POST 动作类似。
<iq>节有四种,通过type 属性区分,其中两种请求get和 set,两种响应 result和 error。每一个
IQ-get或 IQ-set节均必须接收响应的 IQ-result和 IQ-error节。此外,每一对<iq>必须匹配 id 属
性。
Get: 获取当前域值
Set: 设置或替换get查询的值
Result: 说明成功的响应了先前的查询
Error: 查询和响应中出现的错误
The base IQ (Info/Query) packet. IQ packets are used to get
and set information on the server, including
authentication, roster operations, and creating accounts.
Each IQ packet has a specific type that indicates what type of
action is being taken: "get", "set", "result", or "error".
IQ packets can contain a single child element that exists in a
specific XML namespace. The combination of the element
name and namespace determines what type of IQ packet it is.
query xmlns="jabber:iq:auth"
十一、设计模式六大原则
1.单一职责原则:不要存在多于一个导致类变更的原因。
通俗的说:即一个类只负责一项职责。
2.里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象。
通俗的说:当使用继承时。类B 继承类 A时,除添加新的方法完成新增功能P2
外,尽量不要重写父类A
的方法, 也尽量不要重载父类A的方法。 如果子类对这些非抽象方法任意修改,
就会对整个继承体系造
成破坏。子类可以扩展父类的功能,但不能改变父类原有的功能。
3.依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不
应该依赖细节;细节应
该依赖抽象。
通俗的说:在 java 中,抽象指的是接口或者抽象类,细节就是具体的实现类,
使用接口或者抽象类的目的
是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他
们的实现类去完成。依赖
倒置原则的核心思想是面向接口编程.
4.接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应
该建立在最小的接口上。
通俗的说:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的
方法尽量少。也就是说,
我们要为各个类建立zhuan用的接口,而不要试图去建立一个很庞大的接口供所有
依赖它的类去调用。
5.迪米特法则:一个对象应该对其他对象保持最少的了解
通俗的说:尽量降低类与类之间的耦合。
6.开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
通俗的说:用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,
只要抽象的合理,可以基本保持软件
架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,
当软件需要发生变化时,我们只需要根
据需求重新派生一个实现类来扩展就可以了。
十二、 第三方登陆
参考资料:http://blog.csdn.net/infsafe/article/details/10209401
1、你们需要支持用户注册
2、你们需要在应用登录的时候提供第三方平台的图标
3、用户点击第三方平台图标以后,你们尝试判断用户是否已经授权
4、如果用户授权,获取他的唯一识别符,比方说WeiboDb 里面的 weiboId 这个字段
5、如果用户没有授权,引导用户授权,授权成功后也可以获取 weibo Id
6、然后用这个唯一识别符登录你们的系统,如果用户已经注册,则应该让用户登录到你们的系统,
流程结束
7、如果你们的系统发现用户没有注册,引导用户进入你们应用的注册页面,并通过 share sdk 的
showuser方法获取用户资料,自动帮助用户完成注册资料的填写,然后等待用户确认
8、如果用户确认了注册信息,你们的应用就根据他的信息完成这注册操作,如果操作成功,则应该
让用户登录到你们的系统,流程结束
十三、 第三方支付
申请流程
注册支付宝账号??进行实名认证??提交审核资料??审核通过
备注:申请通过后会获得:合作者身份 ID(PID),该 ID 在项目配置中需要用到
开发流程:
第一步:
下载 API 开发文档后,即可获取官方 Demo,该 Demo 中需要将审核通过后获取的 PID 替换,并且输入支付宝收
款账户即可。这里非常简单,就不过多叙述。
第二步:
官方 Api 开发文档中,存在一个 openssl 的文件夹,该文件夹主要是用于生成支付宝所需要用到的公钥以及私钥。
打开该文件夹可以看到详细的生成方式,根据提示生成公钥及私钥,请注意,密钥需要经过 pkcs8 二次加密。
第三步:
将生成的公钥和私钥配置到 Demo 中。
第四步(可省略):
为了方便后期维护,建议将支付宝相关的方法及配置项抽取出来做为单独的一个类,后期需要使用直接调用即可。
十四、 常见框架分析
1.Otto 与 EventBus
这两个框架的实现原理差不多, 在开发中常用 Otto.
我们假设这样一种业务场景,现在在做一款及时聊天应用,我们在聊天页面进行收发信息,同时也要实时更新前
一页面的聊天记录,这时我们该如何去实现?可以使用的是广播接收器 BroadCastReceiver,在接收和发送消息的
时候就不停去发送广播,然后在需要实时更新的地方进行接收更新。实现的思想比较简单,也不存在代码上的耦合
问题,但是有个弊端。弊端就是需要去在很多地方实现 BroadCastRecevier,代码虽不算冗余,但比较多,看起来
很是不爽。使用 Otto 能解决代码体积的问题。Otto 是一款目前比较流行事件总线框架,旨在保持应用各页面和模
块之间通信高效的前提下,对应用进行解耦。Otto 是基于观察者设计模式,简单来说,如果你想订阅某个消息,
使用@Subcribe注解即可进行接收,同时使用
Bus.post(Object obj)进行消息的发布,这样的设计达到了完全的解耦。
Otto 使用过程:
一、Bus实例化
Bus这个类是整个框架的灵魂,它负责消息的发布和接收,整个流程都是经过这个 Bus去实现的。Bus的实例化推
荐使用单例,就是说整个应用内只实例化一个 Bus 对象,所有的消息的处理都是经过这单一的实例去实现。因为要
实现消息的接受者接收到发布的消息, 一定要经过同一个 Bus对象的处理。 Bus 的构造器可以接收 ThreadEnforcer
类型的参数,ThreadEnforcer 其实是一个接口,它自身有两个实现,分别表示 Bus 运行在 Main Thread 中还是异
步线程中。
二、注册和解绑 Bus
根据具体的业务需求进行 Bus 的注册和解绑,对于 android 中的组件,一般是基于生命周期方法中去实现;同时
如果是任意你自定义的类中都可以进行。下面展示的是在 Activity 和 Fragment 里面实现。
三、消息的发布
发布消息是整个框架中最重要的部分,它允许你告诉所有的订阅者一个事件已经触发。任何一个类的实例对象都可
以通过总线 Bus 去发布,同时也只能被订阅这种对象的接受者所接收。下面展示的是通过 Bus 去发布一个消息,
消息的内容是 LocationChangeEvent,所以 LocationChangeEvent 的接受者都能接收到此发布的消息。注意的
是,发布消息只能一个 Object 对象。
四、消息的订阅
消息的订阅和发布之前都要在当前的类中进行 Bus 的注册。 订阅是对消息发布的补充, 当消息发布的事件调用之后,
对应的消息订阅者就能立即接收到此消息。实现订阅功能是通过自定义方法实现的,方法的名称可以随意,同时还
得需要满足三个条件。
1、方法前使用@Subscribe 注解
2、访问修饰符为 public
3、单一参数,根据你想订阅的消息进行设置
注:使用之前,记得进行注册;使用完毕,记得释放。
五、消息的 produce
当订阅者注册完毕,针对特定的消息,通常也需要获取当前已知的值。这个时候,就需要用到 produce。同样的使
用 produce的方法名称可以随意,同时有三点需要注意。
1、方法前使用@produce注解
2、访问修饰符为 public
3、无参,返回值是基于订阅者参数类型
当然 Otto 的缺点也是有的,要实现上述订阅/发布模型的功能,付出的代价就是对各个注册 Bus 的类进行反射。
果大量的使用的情况下,对应用的性能多少有点副影响。
实现原理:
这个框架所实现的功能本质是在一个对象中调用任意的另一个或多个对象中的方法, 而不需要将这个或者这些
对象传入调用者.
如果把它们都传入调用者去调用它们的方法, 那么调用者就依赖这些对象, 程序的耦合度就高了, 所以说这个框架
是用来解耦的.
无论 EventBus 还是 Otto都有一个注册(register)的方法, 方法参数是需要订阅事件的对象.
register 方法会拿到参数的 class 文件,
Otto 通过反射获取类中有@Subscribe 注解的方法,
将该 Method 对象和参数放入 Otto 内部的一个集合中,
在发布事件时调用 post 方法, post 方法会根据参数类型, 在这个集合中找到 register 时放入的相对应 Method 对
象,
调用这个Method所需要的对象是register时传入的参数, 所需的参数是post时传入的参数, 这些都已经有了, 直
接将它 invoke
EventBus 与 Otto 不同仅在于 Otto 是通过注解来确定哪些方法是需要接收事件的方法, 而 EventBus 是通过固定
的方法名来确定的, 所以在项目上线, 代码混淆时, 使用了 EventBus 的类都不能混淆, 因此在项目中使用 Otto 会
更多一点.
2.ImageLoader
一个强大的图片加载框架, 很好的处理了图片加载的多线程,缓存,内存溢出等问题.
1. 多线程异步加载和显示图片(图片来源于网络、sd 卡、assets 文件夹,drawable 文件夹(不能加载 9patch)
可以加载视频缩略图)
Uri 参数:
http:// site.com/image.png
file:/// mnt/sdcard/image.png
file:/// mnt/sdcard/video.mp4
content:// media/external/images/media/13
content://media/external/video/media/13
assets:// image.png
drawable://R.drawable.img
可以这么使用
assets: Scheme.ASSETS.wrap(path)
drawable: Scheme.DRAWABLE.wrap(path)
file: Scheme.FILE.wrap(path)
content: Scheme.CONTENT.wrap(path)
http: Scheme.HTTP.wrap(path)
https: Scheme.HTTPS.wrap(path)
2、支持监视加载的过程,可以暂停加载图片,在经常使用的 ListView、GridView 中,可以设置滑动时暂停加载,
停止滑动时加载图片
3、高度可定制化(可以根据自己的需求进行各种配置,如:线程池,图片下载器,内存缓存策略等)
4、支持图片的内存缓存,SD卡(文件)缓存
5、在网络速度较慢时,还可以对图片进行加载并设置下载监听
6、减少加载大图片 OOM 的情况
7、避免同一 Uri 加载过程中重复开启任务加载
框架中三个核心类:
ImageLoader
ImageLoaderConfiguration
DisplayImageOptions
ImageLoaderConfiguration 是给ImageLoader做配置的, DisplayImageOptions是显示图片的一些配置. 这两
个类都使用了构建器模式.
下面是使用的例子, 代码中的注释写的很详细:
MyApplication.java
最简单的使用范例:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
File cacheDir = StorageUtils.getCacheDirectory(this);
ImageLoaderConfiguration config = new ImageLoaderConfiguration
.Builder(this)
.denyCacheImageMultipleSizesInMemory()
.diskCache(new UnlimitedDiskCache(cacheDir))
.diskCacheExtraOptions(480, 800, null)
.build();
ImageLoader.getInstance().init(config);
}
}
在 AndroidManifest 文件的 application 节点下配置:
android:name="cn.itcast.demo.app.MyApplication"
使用:
ImageLoader.getInstance().displayImage(url);
ImageLoader 显示图片一般使用 displayImage 方法, 它的执行流程图:
可以看到就是讲过的三级缓存.
3.BufferKnife和AndroidAnnotations
这是两个轻量级的IOC框架, 类似J2ee的Spring. 安卓类似的框架还有很多, 这两个用的比较多, 也较具有代表性,
这两个框架的实现原理不是很重要, 但是它的思想必须要了解.
IOC 是面向对象编程中非常重要的一个原则, IOC 的意思是控制反转: Inversion of Control, 控制反转分为依赖注
入和依赖查找, 这两个框架是依赖注入.
控制反转指的是创建对象的功能转移了,可以把它看做是工厂模式的升华, 也是为了解耦
ButterKnife 是通过注解+反射来实现的, 作用在于解耦和减少代码书写量. 缺点在于使用反射实现, 会影响程序运
行速度.
注解: 其实注解没有什么其它的用途, 它只是一个标志, 当你需要给某个类, 莫个方法,或某个属性打一个特定的标
记, 就可以使用注解.
ButterKnife 的使用比较简单, 举个栗子, 如果你想自动 findViewById, 那么需要两步
1. 给属性加上@InjectView(R.id.xx) 括号中的参数是这个控件的 id
2. 在 Activity 的 setContentView 之后调用 ButterKnife.inject(this);
实现过程:
inject方法会拿到传入的 Activity 的 class 对象,
获取类中所有的 Field,
判断该属性是否被@InjectView 注解,
如果被注解, 获取注解的值
调用 findViewById()传入注解的值, 获取 view 对象
将 view 对象设置给这个 field
AndroidAnnotations 框架是另一种实现模式, 它在编译时会给注解的类生成一个子类, 在这个子类做了初始化和
绑定事件等操作, 在使用时应该使用这个子类, 比如注解 Activity 时, 在 AndroidManifest 文件配置时是配置生成
的这个子类而不是原类, 子类的类名是原类类名+_,比如原类名是 MainActivity, 生成的子类类名就是
MainActivity_.
相比其它 IOC 框架它的优点在于没有使用反射运行更快, 缺点在于会生成大量类文件, 增加 apk 体积.
ButterKnife 使用示例:
public class MainActivity extends Activity {
//相当于 findViewById(R.id.tv)
@InjectView(R.id.tv)
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);//将对象注入,就能对它用 ButterKnife 的注解
}
//给 id=R.id.tv 的控件设置点击事件
@OnClick(R.id.tv)
public void show(View v){
Toast.makeText(this,"butterKnif!", Toast.LENGTH_LONG).show();
}
}
4.Picasso, ImageLoader, Fresco, Glide优劣
首先看 Fresco, 它的优点是其他几个框架没有的, 或者说是其他几个框架的短板.
Fresco:
优点:
1. 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中, 图片的中间缓冲数据也存放在本地堆内存,
所以, 应用程序有更多的内存使用, 不会因为图片加载而导致 oom, 同时也减少垃圾回收器频繁调用回收 Bitmap
导致的界面卡顿, 性能更高.
2. 渐进式加载 JPEG 图片, 支持图片从模糊到清晰加载
3. 图片可以以任意的中心点显示在 ImageView, 而不仅仅是图片的中心.
4. JPEG 图片改变大小也是在 native进行的, 不是在虚拟机的堆内存, 同样减少 OOM
5. 很好的支持 GIF图片的显示
缺点:
1. 框架较大, 影响 Apk 体积
2. 使用较繁琐
ImageLoader, Picasso, Glide: 这三者实现机制都差不多
ImageLoader:
比较老的框架, 稳定, 加载速度适中, 缺点在于不支持GIF图片加载, 使用稍微繁琐, 并且缓存机制没有和http的缓
存很好的结合, 完全是自己的一套缓存机制.
Picasso:
使用方便, 一行代码完成加载图片并显示, 框架体积小,
缺点在于不支持 GIF, 并且它可能是想让服务器去处理图片的缩放, 它缓存的图片是未缩放的, 并且默认使用
ARGB_8888 格式缓存图片, 缓存体积大.
Glide:
可以说是 Picasso 的升级版, 有 Picasso 的优点, 并且支持 GIF 图片加载显示, 图片缓存也会自动缩放, 默认使用
RGB_565 格式缓存图片, 是 Picasso 缓存体积的一半.
5.Volley和Ok-http,android-async-http,retrofit
volley 是一个简单的异步 http 库,仅此而已。比较适合小的而频繁的 Http 请求
缺点是不支持同步,这点会限制开发模式;
不能 post 大数据,所以不适合用来上传文件。
android-async-http,与 volley 一样是异步网络库,使用了 nio 的方式实现, 不过 nio 更适合大量连接的情况,对
于移动平台有点杀鸡用牛刀的味道。 volley是封装的httpUrlConnection, android-async-http封装的httpClient,
而 android 平台不推荐用 HttpClient 了,所以这个库已经不适合 android 平台了。
okhttp 是高性能的 http 库,支持同步、异步,而且实现了 spdy、http2、websocket 协议,api 很简洁易用,和
volley 一样实现了 http 协议的缓存。picasso 就是利用 okhttp 的缓存机制实现其文件缓存,实现的很优雅,很正
确,反例就是 UIL(universal image loader),自己做的文件缓存,而且不遵守 http 缓存机制。
retrofit与 picasso一样都是在 okhttp 基础之上做的封装,项目中可以直接用了。
picasso、uil 都不支持 inbitmap,项目中有用到 picasso 的富图片应用需要注意这点。
okhttp 和 async http 是一个基础的通信库,都很强大,但需要自己封装使用才更方便。另外 okhttp 已经被谷歌
官方用在 android 源码中了。retrofit 和 volley 是属于比较高级点的封装库了, 其中 retrofit 是默认使用 okhttp,
volley 也支持 okhttp 作为其底层通信的部件。retrofit 的特点是使用清晰简单的接口,非常方便,而 volley 在使
用的时候也还简单,不过要使用高级一点的功能需要自己自定义很多东西.
推荐使用 retrofit+okhttp. 最新的 retorfit 已经支持 nio 了, 而且 retorfit 内置了 RxJava.
6. RxJava
RxJava 是一个异步操作库, 一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库.它是仿
照.net 的 Reactive Extensions(Rx)类库设计的, 可以帮助我们更容易的进行相应式编程. RxJava 的优势在于简
洁.
这个简洁不是指代码书写量少, 而是代码逻辑与结构简洁. 异步操作很关键的一点是程序的简洁性,因为在调度过
程比较复杂的情况下,异步代码经常会既难写也难被读懂。 Android 创造的 AsyncTask 和 Handler ,其实都是
为了让异步代码更加简洁。
RxJava 的简洁的与众不同之处在于,随着程序逻辑变得越来越复杂,它依然能够保持简洁, 能够很大程度提升代
码的阅读性, 易于后期升级维护. 他通过一种扩展的观察者模式来实现的, RxJava 有四个基本概念:Observable
(可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅事件)。Observable 和 Observer 通过
subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer.
它的缺点在于有一定的学习成本.
7. Volley
Volley 的主要特点
(1). 扩展性强。Volley 中大多是基于接口的设计,可配置性强。
(2). 一定程度符合 Http 规范,包括返回 ResponseCode(2xx、3xx、4xx、5xx)的处理,请求头的处理,缓存
机制的支持等。并支持重试及优先级定义。
(3). 默认 Android2.3 及以上基于 HttpURLConnection,2.3 以下基于 HttpClient 实现
(4). 提供简便的图片加载工具。
上面是 Volley 的总体设计图,主要是通过两种 Diapatch Thread 不断从 RequestQueue 中取出请求,根据是否
已缓存调用 Cache 或 Network 这两类数据获取接口之一,从内存缓存或是服务器取得请求的数据,然后交由
ResponseDelivery 去做结果分发及回调处理. 也是三级缓存.
Volley 的优缺点:
优点: Volley的优点在于请求队列的管理, 适合小而频繁的请求, 如果app比较小, 网络请求要求不高的情况下可以
使用 volley, 通常情况下是要结合其他框架一起来使用, 比如 volley+okhttp.
缺点: 下载大文件性能不佳, 不支持大文件上传
Volley 简单使用示范:
注意要添加联网权限.
public class MainActivity extends Activity {
@InjectView(R.id.tv)
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
}
@OnClick(R.id.tv)
public void show(View v){
String url =
"http://news.xinhuanet.com/photo/2016-01/29/128684788_14540614045291n.jpg
";
RequestQueue requestQueue = Volley.newRequestQueue(this);
MyResponseListener responseListener = new MyResponseListener();
ImageRequest imageRequest = new ImageRequest(
url, //图片的 url
new MyResponseListener(), //响应回调接口
720, //图片宽
1280, //图片高
ImageView.ScaleType.FIT_XY,
Bitmap.Config.RGB_565,
new MyErrorListener()); //请求错误的回调接口
requestQueue.add(imageRequest); //添加到请求队列
}
private class MyErrorListener implements Response.ErrorListener{
@Override
public void onErrorResponse(VolleyError error) {
//Do Something...
}
}
private class MyResponseListener implements Response.Listener<Bitmap>{
@Override
public void onResponse(Bitmap response) {
Drawable drawable = (Drawable) new
BitmapDrawable(getResources(), response);
tv.setBackground(drawable);
}
}
}
Ok-http 使用简单范例
public class MainActivity extends Activity {
@InjectView(R.id.tv)
TextView tv;
private OkHttpClient okHttpClient;
private Call call;
private ResponseCallBack responseCallBack;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
okHttpClient = new OkHttpClient(); //创建 Client
String url =
"http://news.xinhuanet.com/photo/2016-01/29/128684788_14540614045291n.jpg
";
Request request = new Request.Builder() //创建请求
.url(url)
.build();
call = okHttpClient.newCall(request); //创建调用对象
responseCallBack = new ResponseCallBack(); //创建回调接口
call.enqueue(responseCallBack); // 调用
}
private class ResponseCallBack implements Callback{
@Override
public void onFailure(Call call, IOException e) { }
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream in = response.body().byteStream();
Bitmap bitmap = BitmapFactory.decodeStream(in);
final Drawable drawable = (Drawable) new
BitmapDrawable(getResources(), bitmap);
runOnUiThread(new Runnable() {
@Override
public void run() {
tv.setBackground(drawable);
}
});
}
}
}
Java 面试题(10.23 更新)(★★)
一、Java基础(★★)
1、Java中引用类型都有哪些
(1)在虚拟机内存不足的情况下,也不会回收强引用对象。如果我们把(强引用)对象置为 null,
会大大加大 垃圾回收执行频率。几乎只要我们给出建议(GC),jvm 就会回收。
强引用,例如下面代码:
Object o=new Object();
Object o1=o;
(2)对于软引用,如果不显式的置为 null 的话,和强引用差不多,垃圾回收不会执行。只会等到内
存不足的时候才会调用。
(3)对于弱引用,就算你不显式的把他置为null,垃圾回收也会立即执行。
(4 )虚引用,相当于null。
2、什么是重载,什么是重写,有什么区别?
重载(Overloading):
(1) Overloading 是一个类中多态性的一种表现, 让类以统一的方式处理不同类型数据的一种手段。
多个同名函数同时存在,具有不同的参数个数/类型。
(2)重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同,也可以不相
同。无法以返回型别作为重载函数的区分标准。
重写(Overriding):
(1) 父类与子类之间的多态性,对父类的函数进行重新定义。即在子类中定义某方法与其父类有相
同的名称和参数。
(2)若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖
原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
3、String、StringBuffer 和 StringBuilder 的区别
JAVA早期平台提供了两个类:String 和 StringBuffer,它们可以储存和操作字符串,即包含多个字
符的字符数据。这个 String 类提供了数值不可改变的字符串。而这个 StringBuffer类提供的字符串
可以进行修改。当你知道字符数据要改变的时候你就可以使用 StringBuffer。。String 类是不可变
类,任何对 String的改变都会引发新的 String 对象的生成;而 StringBuffer 则是可变类,任何对
它所指代的字符串的改变都不会产生新的对象。
StringBuilder是后面引入的,它与 StringBuffer类的区别在于,新引入的StringBuilder 类不是线
程安全的,但其在单线程中的性能比StringBuffer 高。(有兴趣的可以去读下《Think in Java》描
述 HashTable 和 HashMap 区别的那部分章节比较熟悉的话,就是支持线程同步保证线程安全而导
致性能下降的问题)
典型地,你可以使用 StringBuffers 来动态构造字符数据。另外,String 实现了 equals 方法,new
String(“abc”).equals(newString(“abc”)的结果为 true,而 StringBuffer没有实现 equals方法,
所以,new StringBuffer(“abc”).equals(newStringBuffer(“abc”)的结果为 false。
4、关键字final 和static 是怎么使用的
final 有着“终态的”“这是无法改变的”含义,阻止了多态和继承。
具体使用有:
final 类不能被继承,没有子类,final类中的方法默认是final 的。
final 方法不能被子类的方法覆盖,但可以被继承。
final 成员变量表示常量,只能被赋值一次,赋值后值不再改变。
final 不能用于修饰构造方法。
注意: 父类的 private 成员方法是不能被子类方法覆盖的,因此 private 类型的方法默认是final 类型
的。
static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代
码块,但是 Java语言中没有全局变量的概念。
被 static 修饰的成员变量和成员方法独立于该类的任何对象,static 对象可以在它的任何对象创建之
前访问,无需引用任何对象。
static前面也可用 public或 private 来修饰,其中 private 是访问权限限定,static 表示不要实例化
就可以使用。
主要用于静态变量,静态方法,static代码块
静态变量:对于静态变量在内存中只有一个拷贝(节省内存),JVM 只为静态分配一次内存,在加
载类的过程中完成静态变量的内存分配, 可用类名直接访问 (方便) , 当然也可以通过对象来访问(但
是这是不推荐的)。
静态方法:静态方法可以直接通过类名调用, 任何的实例也都可以调用, 因此静态方法中不能用 this
和 super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static 的成员变量和成员成
员方法),只能访问所属类的静态成员变量和成员方法。因为实例成员与特定的对象关联!
static代码块:atic代码块也叫静态代码块,是在类中独立于类成员的 static语句块,可以有多个,
位置可以随便放,它不在任何的方法体内,JVM 加载类时会执行这些静态的代码块,如果 static 代
码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次
static和 final 一起使用:
static final 用来修饰成员变量和成员方法,可简单理解为“全局常量”!
对于变量,表示一旦给值就不可修改,并且通过类名可以访问。
对于方法,表示不可覆盖,并且可以通过类名直接访问。
特别要注意一个问题:
对于被 static 和 final 修饰过的实例常量,实例本身不能再改变了,但对于一些容器类型(比如,
ArrayList、HashMap)的实例变量,不可以改变容器变量本身,但可以修改容器中存放的对象,这
一点在编程中用到很多。
5、TCP/IP 协议簇分哪几层?TCP、IP、XMPP、HTTP、分别属于哪一层?
(2016.01.24)
通讯协议采用了4层的层级结构,每一层都呼叫下一层所提供的网络来完成自己的需求。这
4层分别为:
应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网
络远程访问协议(Telnet)、超文本传输协议(HTTP)、可扩展通讯和表示协议(XMPP)等。
传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据
报协议(UDP)等,TCP和 UDP 给数据包加入传输数据并把它传输到下一层中,这一层负责传
送数据,并且确定数据已被送达并接收。
互连网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但
不检查是否被正确接收),如网际协议(IP)。
网络接口层:对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、SerialLine
等)来传送数据。
二、Java中的设计模式
1、你所知道的设计模式有哪些
Java中一般认为有 23 种设计模式,我们不需要所有的都会,但是其中常用的几种设计模式应该去掌
握。下面列出了所有的设计模式。需要掌握的设计模式我单独列出来了,当然能掌握的越多越好。
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元
模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模
式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
2、单例设计模式
最好理解的一种设计模式,分为懒汉式和饿汉式。
饿汉式:
public class Singleton {
// 直接创建对象
public static Singleton instance = new Singleton();
// 私有化构造函数
private Singleton() {
}
// 返回对象实例
public static Singleton getInstance() {
return instance;
}
}
懒汉式:
public class Singleton {
// 声明变量
private static volatile Singleton singleton2 = null;
// 私有构造函数
private Singleton2() {
}
// 提供对外方法
public static Singleton2 getInstance() {
if (singleton2 == null) {
synchronized (Singleton2.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
3、工厂设计模式
工厂模式分为工厂方法模式和抽象工厂模式。
工厂方法模式
工厂方法模式分为三种:普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例
的创建。
多个工厂方法模式, 是对普通工厂方法模式的改进, 在普通工厂方法模式中, 如果传递的字符串出错,
则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即
可。
普通工厂模式
public interface Sender {
public void Send();
}
public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("this is mail sender!");
}
}
public class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("this is sms sender!");
}
}
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 SendFactory {
public Sender produceMail(){
return new MailSender();
}
public Sender produceSms(){
return new SmsSender();
}
}
public class FactoryTest {
public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produceMail();
sender.send();
}
}
静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直
接调用即可。
public class SendFactory {
public static Sender produceMail(){
return new MailSender();
}
public static Sender produceSms(){
return new SmsSender();
}
}
public class FactoryTest {
public static void main(String[] args) {
Sender sender = SendFactory.produceMail();
sender.send();
}
}
抽象工厂模式
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工
厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象
工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修
改之前的代码。
public interface Provider {
public Sender produce();
}
-------------------------------------------------------------------------------------
public interface Sender {
public void send();
}
-------------------------------------------------------------------------------------
public class MailSender implements Sender {
@Override
public void send() {
System.out.println("this is mail sender!");
}
}
-------------------------------------------------------------------------------------
public class SmsSender implements Sender {
@Override
public void send() {
System.out.println("this is sms sender!");
}
}
-------------------------------------------------------------------------------------
public class SendSmsFactory implements Provider {
@Override
public Sender produce() {
return new SmsSender();
}
}
public class SendMailFactory implements Provider {
@Override
public Sender produce() {
return new MailSender();
}
}
-------------------------------------------------------------------------------------
public class Test {
public static void main(String[] args) {
Provider provider = new SendMailFactory();
Sender sender = provider.produce();
sender.send();
}
}
4、建造者模式(Builder)
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来
创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式
和最后的Test结合起来得到的。
public class Builder {
private List<Sender> list = new ArrayList<Sender>();
public void produceMailSender(int count) {
for (int i = 0; i < count; i++) {
list.add(new MailSender());
}
}
public void produceSmsSender(int count) {
for (int i = 0; i < count; i++) {
list.add(new SmsSender());
}
}
}
public class TestBuilder {
public static void main(String[] args) {
Builder builder = new Builder();
builder.produceMailSender(10);
}
}
5、适配器设计模式
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配
所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。
类的适配器模式
public class Source {
public void method1() {
System.out.println("this is original method!");
}
}
-------------------------------------------------------------
public interface Targetable {
/* 与原类中的方法相同 */
public void method1();
/* 新类的方法 */
public void method2();
}
public class Adapter extends Source implements Targetable {
@Override
public void method2() {
System.out.println("this is the targetable method!");
}
}
public class AdapterTest {
public static void main(String[] args) {
Targetable target = new Adapter();
target.method1();
target.method2();
}
}
对象的适配器模式
基本思路和类的适配器模式相同,只是将 Adapter类作修改,这次不继承 Source 类,而是持有
Source类的实例,以达到解决兼容性的问题。
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();
}
}
--------------------------------------------------------------
public class AdapterTest {
public static void main(String[] args) {
Source source = new Source();
Targetable target = new Wrapper(source);
target.method1();
target.method2();
}
}
接口的适配器模式
接口的适配器是这样的: 有时我们写的一个接口中有多个抽象方法, 当我们写该接口的实现类时,
必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只
需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类
实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我
们写一个类,继承该抽象类,重写我们需要的方法就行。
6、装饰模式(Decorator)
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰
对象实现同一个接口,装饰对象持有被装饰对象的实例。
public interface Sourceable {
public void method();
}
----------------------------------------------------
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!");
}
}
----------------------------------------------------
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!");
}
}
----------------------------------------------------
public class DecoratorTest {
public static void main(String[] args) {
Sourceable source = new Source();
Sourceable obj = new Decorator(source);
obj.method();
}
}
7、策略模式(strategy)
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会
影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接
口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。策略模式的决定权在用户,系统本
身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系
统中,外部用户只需要决定用哪个算法即可。
public interface ICalculator {
public int calculate(String exp);
}
---------------------------------------------------------
public class Minus extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp, "-");
return arrayInt[0] - arrayInt[1];
}
}
---------------------------------------------------------
public class Plus extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp, "\\+");
return arrayInt[0] + arrayInt[1];
}
}
--------------------------------------------------------
public 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;
}
}
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);
}
}
8、观察者模式(Observer)
观察者模式很好理解,类似于邮件订阅和 RSS 订阅,当我们浏览一些博客或 wiki 时,经常会看
到 RSS 图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来
讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是
一种一对多的关系。
public interface Observer {
public void update();
}
public class Observer1 implements Observer {
@Override
public void update() {
System.out.println("observer1 has received!");
}
}
public class Observer2 implements Observer {
@Override
public void update() {
System.out.println("observer2 has received!");
}
}
public interface Subject {
/*增加观察者*/
public void add(Observer observer);
/*删除观察者*/
public void del(Observer observer);
/*通知所有的观察者*/
public void notifyObservers();
/*自身的操作*/
public void operation();
}
public abstract class AbstractSubject implements Subject {
private Vector<Observer> vector = new Vector<Observer>();
@Override
public void add(Observer observer) {
vector.add(observer);
}
@Override
public void del(Observer observer) {
vector.remove(observer);
}
@Override
public void notifyObservers() {
Enumeration<Observer> enumo = vector.elements();
while (enumo.hasMoreElements()) {
enumo.nextElement().update();
}
}
}
public class MySubject extends AbstractSubject {
@Override
public void operation() {
System.out.println("update self!");
notifyObservers();
}
}
public class ObserverTest {
public static void main(String[] args) {
Subject sub = new MySubject();
sub.add(new Observer1());
sub.add(new Observer2());
sub.operation();

}

}

本文转载自:

共有 人打赏支持
O
粉丝 0
博文 17
码字总数 298
作品 0
东城
【必看】Android干货整理

哗啦啦,为方便大家更好的学习交流,小编特地整理了一大波干货!预备 前方高能预警,一大波干货袭来,接住了!!!!!!!!!!!! 如果你是零基础小白,不知如何上手Android开发,不知应学习哪些工具...

慕课网官方_运营中心
08/01
0
0
2018 Android 面试心得,已拿到 offer

code小生,一个专注于 Android 领域的技术分享平台 作者:huisonma 链接:https://www.jianshu.com/p/855ff21e0a13 声明:本文是 huisonma 原创,转发等请联系原作者授权。 从 16 年毕业至今...

h176nhx7
04/16
0
0
投稿006期| 回忆一次美团Android校招

写在前面 今天和一同学吃饭,互相诉了一波苦。他吐槽了一下这周五去美团面试不是很顺利,我吐槽了一下,业务大改版。这一个月恐怕要疯狂加班... 他提到美团的时候,这让我想起来了2017年10月...

挚爱灬丶
07/17
0
0
回忆一次美团Android校招

写在前面 今天和一同学吃饭,互相诉了一波苦。他吐槽了一下这周五去美团面试不是很顺利,我吐槽了一下,业务大改版。这一个月恐怕要疯狂加班... 他提到美团的时候,这让我想起来了2017年10月...

MDove
07/16
0
0
2018年美团Android校招

写在前面 今天和一同学吃饭,互相诉了一波苦。他吐槽了一下这周五去美团面试不是很顺利,我吐槽了一下,业务大改版。这一个月恐怕要疯狂加班... 他提到美团的时候,这让我想起来了2017年10月...

MDove
07/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

nginx 负载均衡

一.配置方式 1.轮询(默认) 优点:实现简单; 缺点:不考虑每台服务器处理能力 2.权重 weight默认是1。如果有多个配置权重的节点,比较相对值。 15:10,只代表访问8080端口的概率是访问908...

imbiao
33分钟前
1
0
jQuery学习笔记180923

jQuery 操作 CSS jQuery 拥有若干进行 CSS 操作的方法。我们将学习下面这些: addClass() - 向被选元素添加一个或多个类 removeClass() - 从被选元素删除一个或多个类 toggleClass() - 对被选...

颖伙虫
44分钟前
1
0
[python] colorama 模块 - 改变控制台输出文本的颜色

除了使用 PyQt 这样的图形化开发框架外,基本上 python 程序都是跑在控制台中的。很多时候,单纯使用黑白的文字不能很好地突出我们要显示的信息。有时候我们需要将错误的提示使用红色标注,而...

cometeme
49分钟前
1
0
Makefile 学习 2 - 基于若干 Blog 的汇总

基于若干 Blog 汇总的 makefile 教程 陈皓 https://blog.csdn.net/haoel/article/details/2886 Makefile 进阶 1. Makefile 中的内容 显式规则。显式规则说明了,如何生成一个或多的的目标文件...

公孙衍
今天
1
0
NIO与BIO的区别、NIO的运行原理和并发使用场景

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的...

Java干货分享
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部