Android面试重点项目回答笔记.docx
- 文档编号:23859270
- 上传时间:2023-05-21
- 格式:DOCX
- 页数:39
- 大小:45.86KB
Android面试重点项目回答笔记.docx
《Android面试重点项目回答笔记.docx》由会员分享,可在线阅读,更多相关《Android面试重点项目回答笔记.docx(39页珍藏版)》请在冰豆网上搜索。
Android面试重点项目回答笔记
1.项目怎么说
先大致介绍,再分层次去说
1.1.网络层
1.1.1.普通网络请求,线程+Handler/AsyncTask/线程池,xUtils2.x(接口回调),JSON-JavaBean,Gson
1.1.2.普通数据缓存,读本地,先显示本地数据,拿时间戳访问服务器,
如果有更新,返回新数据+时间戳,缓存到本地(应用私有目录/SD卡/数据库),重新显示.
1.1.3.图片请求,图片缓存
1.1.4.断点下载/上传,range,DownloadTask,存数据库,Handler,DownloadListener,ViewHolder
比较有含金量
1.2.业务逻辑层
1.2.1.JavaBean,页面显示,下拉刷新,加载更多,收藏,登录,分享,商城(购物车,支付),XX地图
1.2.2.数据存储
1.2.3.Service(起线程,保持连接,推送),BroadcastReceiver(起服务,组件间通信工具)
1.3.页面层
1.3.1.Activity,抽取BaseActivity,onCreate,initView,initDate,访问网络/回调,
用集合记录打开/关闭的Activity,写一个方法退出应用,startAnActivity
1.3.2.Fragment,show/hide,replace
1.3.3.常用控件,ListView,ViewPager(JazzyViewPager),LinearLayout,RelativeLayout,FrameLayout
1.3.4.自定义控件,举例:
可拖动的GridView
1.3.5.屏幕适配,除了新闻客户端讲的那几种,再加上PercentRelativeLayout、PercentFrameLayout
1.3.6.动画
1.4.优化(掺杂在前三部分里)
1.4.1.布局优化,include,merge,ViewStub,addView/removeView
1.4.2.代码优化,注解框架,ButterKnife,Dagger2,xUtils3,lint
1.4.3.内存/性能优化,OOM,内存泄露,MAT
1.4.4.电量优化
1.5.WebView,HTML5,5.0新特性,...
2.自定义控件
2.1.怎么创建一个自定控件,继承View/ViewGroup/已有控件,构造方法串起来,第三个参数
2.2.onMeasure(测量,两个参数),RatioFrameLayout,onLayout(布局,ViewGroup),流式布局FlowLayout
onDraw(绘制,canvas,paint,不要在onDraw里new对象,Path),快速索引
2.3.onTouchEvent(返回值),invalidate,dispatchTouchEvent,onInterceptTouchEvent(ViewGroup)
requestDisallowInterceptTouchEvent
2.4.回调,定义状态,定义回调接口,回调方法(参数),成员变量(set),在适当位置调用回调方法,外部使用
2.5.动画(帧动画,View/补间动画,属性动画,区别),插补器,估值器(TypeEvaluator)ValueAnimator
2.6.ViewDragHelper,nineoldandroid.jar(没有真正改变view的属性)
3.图片缓存
DisplayingBitmaps
3.1.不能崩(OOM),压缩处理,
xUtils2.xcom.lidroid.xutils.bitmap.BitmapDisplayConfig,optimizeMaxSizeByView
3.2.不能卡,异步,Thread,AsyncTask
3.3.不能错位,ListView/GridView,setTag,AsyncDrawable
3.4.快,缓存,内存缓存(LruCache),硬盘缓存
finalintmaxMemory=(int)(Runtime.getRuntime().maxMemory()/1024);
//Use1/8thoftheavailablememoryforthismemorycache.
finalintcacheSize=maxMemory/8;
mMemoryCache=newLruCache
@Override
protectedintsizeOf(Stringkey,Bitmapbitmap){
//Thecachesizewillbemeasuredinkilobytesratherthan
//numberofitems.
returnbitmap.getByteCount()/1024;
}
};
4.Handler
4.1.为什么要有Handler
4.1.1.主线程不能做耗时操作,要放在子线程
4.1.2.子线程不能修改主线程的UI,就需要Handler
4.2.newHandler(),重写handleMessage,sendMessage,post,Message,
4.3.消息队列MessageQueue,Looper.prepare,Looper.loop
4.4.所有的界面操作,都依赖于Handler机制
4.5.子线程只要调用了Looper.prepare,Looper.loop,就可以在这两行代码之间使用WindowManager修改UI,
主线程也不能修改子线程创建的UI
4.6.Handler是线程间通信的工具
android-support-v7-appcompat支持ActionBar效果,可以兼容2.x版本,让2.x也能够展示Actionbar效果
断点续传
我们编写的是Andorid的HTTP协议多线程断点下载应用程序。
直接使用单线程下载HTTP文件对我们来说是一件非常简单的事。
那么,多线程断点需要什么功能?
1.多线程下载,
2.支持断点。
●使用多线程的好处:
使用多线程下载会提升文件下载的速度。
●多线程下载文件的过程是:
(1)首先获得下载文件的长度,然后设置本地文件的长度。
HttpURLConnection.getContentLength();//获取下载文件的长度
RandomAccessFilefile=newRandomAccessFile("QQWubiSetup.exe","rwd");
file.setLength(filesize);//设置本地文件的长度
(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。
如:
文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示。
例如10M大小,使用3个线程来下载,
线程下载的数据长度(10%3==0?
10/3:
10/3+1),第1,2个线程下载长度是4M,第三个线程下载长度为2M
下载开始位置:
线程id*每条线程下载的数据长度=?
下载结束位置:
(线程id+1)*每条线程下载的数据长度-1=?
(3)使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,
如:
指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止
代码如下:
HttpURLConnection.setRequestProperty("Range","bytes=2097152-4194303");
(4)保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。
RandomAccessFilethreadfile=newRandomAccessFile("QQWubiSetup.exe","rwd");
threadfile.seek(2097152);//从文件的什么位置开始写入数据
高效加载大图
图片有不同的形状与大小。
在大多数情况下它们的实际大小都比需要呈现的尺寸大很多。
例如,系统的图库应用会显示那些我们使用相机拍摄的照片,但是那些图片的分辨率通常都比设备屏幕的分辨率要高很多。
考虑到应用是在有限的内存下工作的,理想情况是我们只需要在内存中加载一个低分辨率的照片即可。
为了更便于显示,这个低分辨率的照片应该是与其对应的UI控件大小相匹配的。
加载一个超过屏幕分辨率的高分辨率照片不仅没有任何显而易见的好处,还会占用宝贵的内存资源,另外在快速滑动图片时容易产生额外的效率问题。
这一课会介绍如何通过加载一个缩小版本的图片,从而避免超出程序的内存限制。
●读取位图的尺寸与类型(ReadBitmapDimensionsandType)
BitmapFactory提供了一些解码(decode)的方法(decodeByteArray(),decodeFile(),decodeResource()等),用来从不同的资源中创建一个Bitmap。
我们应该根据图片的数据源来选择合适的解码方法。
这些方法在构造位图的时候会尝试分配内存,因此会容易导致OutOfMemory的异常。
每一种解码方法都可以通过BitmapFactory.Options设置一些附加的标记,以此来指定解码选项。
设置inJustDecodeBounds属性为true可以在解码的时候避免内存的分配,它会返回一个null的Bitmap,但是可以获取到outWidth,outHeight与outMimeType。
该技术可以允许你在构造Bitmap之前优先读图片的尺寸与类型。
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeResource(getResources(),R.id.myimage,options);
intimageHeight=options.outHeight;
intimageWidth=options.outWidth;
StringimageType=options.outMimeType;
为了避免java.lang.OutOfMemory 的异常,我们需要在真正解析图片之前检查它的尺寸(除非你能确定这个数据源提供了准确无误的图片且不会导致占用过多的内存)。
●加载一个按比例缩小的版本到内存中(LoadaScaledDownVersionintoMemory)
通过上面的步骤我们已经获取到了图片的尺寸,这些数据可以用来帮助我们决定应该加载整个图片到内存中还是加载一个缩小的版本。
有下面一些因素需要考虑:
☐评估加载完整图片所需要耗费的内存。
☐程序在加载这张图片时可能涉及到的其他内存需求。
☐呈现这张图片的控件的尺寸大小。
☐屏幕大小与当前设备的屏幕密度。
为了告诉解码器去加载一个缩小版本的图片到内存中,需要在BitmapFactory.Options中设置inSampleSize的值。
例如,一个分辨率为2048x1536的图片,如果设置inSampleSize为4,那么会产出一个大约512x384大小的Bitmap。
加载这张缩小的图片仅仅使用大概0.75MB的内存,如果是加载完整尺寸的图片,那么大概需要花费12MB(前提都是Bitmap的配置是ARGB_8888)。
下面有一段根据目标图片大小来计算Sample图片大小的代码示例:
publicstaticintcalculateInSampleSize(
BitmapFactory.Optionsoptions,intreqWidth,intreqHeight){
//Rawheightandwidthofimage
finalintheight=options.outHeight;
finalintwidth=options.outWidth;
intinSampleSize=1;
if(height>reqHeight||width>reqWidth){
finalinthalfHeight=height/2;
finalinthalfWidth=width/2;
//CalculatethelargestinSampleSizevaluethatisapowerof2andkeepsboth
//heightandwidthlargerthantherequestedheightandwidth.
while((halfHeight/inSampleSize)>reqHeight
&&(halfWidth/inSampleSize)>reqWidth){
inSampleSize*=2;
}
}
returninSampleSize;
}
Note:
设置inSampleSize为2的幂是因为解码器最终还是会对非2的幂的数进行向下处理,获取到最靠近2的幂的数。
为了使用该方法,首先需要设置inJustDecodeBounds为true,把options的值传递过来,然后设置inSampleSize的值并设置inJustDecodeBounds为false,之后重新调用相关的解码方法。
publicstaticBitmapdecodeSampledBitmapFromResource(Resourcesres,intresId,
intreqWidth,intreqHeight){
//FirstdecodewithinJustDecodeBounds=truetocheckdimensions
finalBitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeResource(res,resId,options);
//CalculateinSampleSize
options.inSampleSize=calculateInSampleSize(options,reqWidth,reqHeight);
//DecodebitmapwithinSampleSizeset
options.inJustDecodeBounds=false;
returnBitmapFactory.decodeResource(res,resId,options);
}
使用上面这个方法可以简单地加载一张任意大小的图片。
如下面的代码样例显示了一个接近 100x100像素的缩略图:
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),R.id.myimage,100,100));
我们可以通过替换合适的BitmapFactory.decode*方法来实现一个类似的方法,从其他的数据源解析Bitmap
非UI线程处理Bitmap
在上一课中介绍了一系列的BitmapFactory.decode*方法,当图片来源是网络或者是存储卡时(或者是任何不在内存中的形式),这些方法都不应该在UI线程中执行。
因为在上述情况下加载数据时,其执行时间是不可估计的,它依赖于许多因素(从网络或者存储卡读取数据的速度,图片的大小,CPU的速度等)。
如果其中任何一个子操作阻塞了UI线程,系统都会容易出现应用无响应的错误。
这一节课会介绍如何使用AsyncTask在后台线程中处理Bitmap并且演示如何处理并发(concurrency)的问题。
●使用AsyncTask(UseaAsyncTask)
AsyncTask类提供了一个在后台线程执行一些操作的简单方法,它还可以把后台的执行结果呈现到UI线程中。
下面是一个加载大图的示例:
classBitmapWorkerTaskextendsAsyncTask{
privatefinalWeakReferenceimageViewReference;
privateintdata=0;
publicBitmapWorkerTask(ImageViewimageView){
//UseaWeakReferencetoensuretheImageViewcanbegarbagecollected
imageViewReference=newWeakReference(imageView);
}
//Decodeimageinbackground.
@Override
protectedBitmapdoInBackground(Integer...params){
data=params[0];
returndecodeSampledBitmapFromResource(getResources(),data,100,100));
}
//Oncecomplete,seeifImageViewisstillaroundandsetbitmap.
@Override
protectedvoidonPostExecute(Bitmapbitmap){
if(imageViewReference!
=null&&bitmap!
=null){
finalImageViewimageView=imageViewReference.get();
if(imageView!
=null){
imageView.setImageBitmap(bitmap);
}
}
}
}
为ImageView使用WeakReference确保了AsyncTask所引用的资源可以被垃圾回收器回收。
由于当任务结束时不能确保ImageView仍然存在,因此我们必须在onPostExecute()里面对引用进行检查。
该ImageView在有些情况下可能已经不存在了,例如,在任务结束之前用户使用了回退操作,或者是配置发生了改变(如旋转屏幕等)。
开始异步加载位图,只需要创建一个新的任务并执行它即可:
publicvoidloadBitmap(intresId,ImageViewimageView){
BitmapWorkerTasktask=newBitmapWorkerTask(imageView);
task.execute(resId);
}
●处理并发问题(HandleConcurrency)
通常类似ListView与GridView等视图控件在使用上面演示的AsyncTask方法时,会同时带来并发的问题。
首先为了更高的效率,ListView与GridView的子Item视图会在用户滑动屏幕时被循环使用。
如果每一个子视图都触发一个AsyncTask,那么就无法确保关联的视图在结束任务时,分配的视图已经进入循环队列中,给另外一个子视图进行重用。
而且,无法确保所有的异步任务的完成顺序和他们本身的启动顺序保持一致。
MultithreadingforPerformance这篇博文更进一步的讨论了如何处理并发问题,并且提供了一种解决方法:
ImageView保存最近使用的AsyncTask的引用,这个引用可以在任务完成的时候再次读取检查。
使用这种方式,就可以对前面提到的AsyncTask进行扩展。
创建一个专用的Drawable的子类来储存任务的引用。
在这种情况下,我们使用了一个BitmapDrawable,在任务执行的过程中,一个占位图片会显示在ImageView中:
staticclassAsyncDrawableextendsBitmapDrawable{
privatefinalWeakReferencebitmapWorkerTaskReference;
publicAsyncDrawable(Resourcesres,Bitmapbitmap,
BitmapWorkerTaskbitmapWorkerTask){
super(res,bitmap);
bitmapWorkerTaskReference=
newWeakReference(bitmapWorkerTask);
}
publicBitmapWorkerTaskgetBitmapWorkerTask(){
returnbitmapWorkerTaskReference.get();
}
}
在执行BitmapWorkerTask之前,你需要创建一个AsyncDrawable并且将它绑定到目标控件ImageView中:
publicvoidloadBitmap(intresId,ImageViewimageView){
if(cancelPotentialWork(resId,imageView)){
finalBitmapWorkerTasktask=newBitmapWorkerTask(imageView);
finalAsyncDrawableasyncDrawable=
newAsyncDrawable(getResources(),mPlaceHolderBitmap,task);
imageView.setImageDrawable(asyncDrawable);
task.execute(resId);
}
}
在上面的代码示例中,cancelPotentialWork方法检查是否有另一个正在执行的任务与该ImageView关联了起来,如果的确是这样,它通过执行cancel()方法来取消另一个任务。
在少数情况下,新创建的任务数据可能会与已经存在的任务相吻合,这样的话就不需要进行下一步动作了。
下面是cancelPotentialWork方法的实现。
publicstaticbooleancancelPotentialWork(intdata,ImageViewimageView){
finalBitmapWork
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 面试 重点项目 回答 笔记
![提示](https://static.bdocx.com/images/bang_tan.gif)