今天面试去深圳卷皮网络科技有限公司去面试,面试官是个女的,而且还算是美女,好吧,面试完后,我感觉除了以上应该还是女才子+女汉子之综合体。
下面记录下面试相关问题,和自己以后可能需要改进的地方:
首先,很长时间没有出去面试,确实在面试过程中可能暴露一些。
其次,确实技术方面还是有技不如人的地方,这个在以后工作中尽快弥补。
第三,可能以后除了在工作中发现不足外,应该隔断时间出去面试下,即使不是面试到好公司,被大神/大婶虐一把也是极好的,反正知道自己不足,就会去弥补,也会进行技术上的提升和发展方向的确定。
以上是感悟,一下是技术点相关:
1,Listview优化相关?
(1),首先通过viewHolder来实现convertview缓存的。
(2),多种type的处理:重载getItemType()和getviewTypeCount(),在getview里面switch切换不同布局,切换不同holder,根据不同的item.type设置UI上显示的内容。
(3),加载耗时,不要每次都开启线程,尽量使用线程池来代替开启每条线程。
(4),Listview滚动停止加载图片:
如果使用umloader的话:
使用ImageLoader的pauseonscrolllistener方法可以设置为listview滑动停止后加载图片,这个是解决卡顿很好的方法
private void applyScrollListener() { //pauseOnsceoll和pauseOnFling都设置为true,表示滑动停止后才进行加载图片 listView.setOnScrollListener(new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling)); }
2.配置ImageLoader的时候不使用.memoryCache(new LruMemoryCache(2 * 1024 * 1024))或者.memoryCache(new WeakMemoryCache())能使listview回滑的时候图片显示正确,不需要重新加载,我想应该是缓存生命周期变长了,所有图片直接从内存读取,速度快吧。
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()) . threadPoolSize(3). threadPriority(Thread.NORM_PRIORITY - 1). denyCacheImageMultipleSizesInMemory(). discCacheFileNameGenerator(new Md5FileNameGenerator()). tasksProcessingOrder(QueueProcessingType.LIFO). discCacheExtraOptions(240, 400, CompressFormat.PNG, 40,null). memoryCacheExtraOptions(240, 400). discCacheFileCount(1000). writeDebugLogs(). defaultDisplayImageOptions(doGetOptions()). build(); ImageLoader.getInstance().init(config);
(5).listview的xml配置要设置为match_parent而不用wrap_content,这也会影响listview的流畅度
android:layout_width="match_parent"
android:layout_height="match_parent"
(6),在adapter的getview()里想设置每个item的默认图片的话要用.setImageResource()而不用.setBackgroundResource()
(7),Listview图片错乱的问题,原因是因为convertView的重用机制导致的,解决办法:设置tag为图片Url
2,进程间通信除了AIDL,还有那些方式进行实现?
除了AIDL,还有广播和contentProvider,后面两个没回答上来,主要可能是没那么深刻。
3,Activity四种启动模式,除了理论,讲下实际工作中的使用?
standard:默认模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。
singleTop:可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。
singleTask:只有一个实例。在同一个应用程序中启动他的时候,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它Activity destory掉并调用它的onNewIntent方法。
如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity,singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。
singleInstance:只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。
4,viewPager+fragement第一次加载,第二次不加载?
5,Listview下拉刷新,上拉加载如何实现,从代码角度讲下?
下拉数据刷新——实现功能分析
1、添加ListView的hearder头布局
1)、写一个顶部布局文件head.xml
2)、写一个继承自ListView类(注意重写三种构造方法),用作列表项,自定义方便在初始化时添加表头
3)、定义一个View header通过LayoutInflater获取顶部布局文件head.xml
4)、通过listview.addHeaderView(header)来为ListView添加头部布局
5)、LayoutParams相当于一个Layout的信息包,它封装了Layout的位置、高、宽等信息。如果将一个View添加到一个 Layout中,最好告诉Layout用户期望的布局方式,也就是将一个认可的layoutParams传递进去。
Android的UI界面都是由View和ViewGroup及其派生类组合而成的,作为容器的ViewGroup可以包含作为叶子节点的View,也可以包含作为更低层次的子ViewGroup
getLayoutParams就是将布局参数的引用返回来
makeMeasureSpec()创建基于所提供的大小和模式来返回MeasureSpec值
2、监听ListView的onScrollListener()事件,根据firstViewItem判断是否在顶端,当前第一个可见的item位置。
3、监听ListView的onTouch()事件 按下,移动,抬起对下拉,释放,正常状态进行控制动作的监听,来改变当前顶部布局的控件状态以及内容显示。
4、通过接口回调将刷新/刷新完成,加载更多/加载更多完成的方法供Activity调用。
分享一片看到的文章:http://www.cnblogs.com/likeandroid/p/4445455.html
6,Umloader底层设计到那些算法,说下具体几个?
这个我说道LRU算法,但是没细讲;
LinkedHashMap 先进先出 链表结构,能够记住存储顺序,存储的时候会判断缓存是否超出构造方法传进去的缓存大小,如果超出了,会删除最早插入的内容
内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了快速访问的方法。其中最核心的类是LruCache (此类在android-support-v4的包中提供) 。这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。
在过去,我们经常会使用一种非常流行的内存缓存技术的实现,即软引用或弱引用 (SoftReference or WeakReference)。但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃。
LRU算法代码:
public class LruMemoryCache implements MemoryCache { private final LinkedHashMap<String, Bitmap> map; private final int maxSize;//最大缓存数byte /** Size of this cache in bytes */ private int size;//当前缓存的大小 /** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */ public LruMemoryCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } this.maxSize = maxSize; this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true); } /** * Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head * of the queue. This returns null if a Bitmap is not cached. */ @Override public final Bitmap get(String key) { if (key == null) { throw new NullPointerException("key == null"); } synchronized (this) { return map.get(key); } } /** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */ @Override public final boolean put(String key, Bitmap value) { if (key == null || value == null) { throw new NullPointerException("key == null || value == null"); } synchronized (this) { size += sizeOf(key, value); Bitmap previous = map.put(key, value); if (previous != null) { size -= sizeOf(key, previous); } } trimToSize(maxSize); return true; } /** * Remove the eldest entries until the total of remaining entries is at or below the requested size. * * @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements. */ private void trimToSize(int maxSize) { while (true) { String key; Bitmap value; synchronized (this) { if (size < 0 || (map.isEmpty() && size != 0)) { throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!"); } if (size <= maxSize || map.isEmpty()) { break; } Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next(); if (toEvict == null) { break; } key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= sizeOf(key, value); } } } /** Removes the entry for {@code key} if it exists. */ @Override public final Bitmap remove(String key) { if (key == null) { throw new NullPointerException("key == null"); } synchronized (this) { Bitmap previous = map.remove(key); if (previous != null) { size -= sizeOf(key, previous); } return previous; } } @Override public Collection<String> keys() { synchronized (this) { return new HashSet<String>(map.keySet()); } } @Override public void clear() { trimToSize(-1); // -1 will evict 0-sized elements } /** * Returns the size {@code Bitmap} in bytes. * <p/> * An entry's size must not change while it is in the cache. */ private int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override public synchronized final String toString() { return String.format("LruCache[maxSize=%d]", maxSize); } }
7,设计模式用到哪几种,说下具体使用?
这个当时只说到单例,我当时说的是数据库操作类设置为单例,不用每次都去new个对象,但是问道单例模式体现了什么思想,我当时就蒙了。
观察者模式----定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式最常用在我们熟悉的事件驱动模型里面,像VC、Android界面里面的事件响应,就是基于观察者模式来实现。
比如 按钮的点击事件就是通过观察者设计模式实现的,setOnClickListener()方法就是注册一个观察者,Button对象就是我们要观察的目标对象。而new出来的OnClickListener(),就是我们实际的观察者。
策略模式----定义一系列算法,把他们独立封装起来,并且这些算法之间可以相互替换。策略模式主要是管理一堆有共性的算法,客户端可以根据需要,很快切换这些算法,并且保持可扩展性。
Android中的应用-下面说说在Android里面的应用。在Android里面策略模式的其中一个典型应用就是Adapter,在我们平时使用的时候,一般情况下我们可能继承BaseAdapter,然后实现不同的View返回,GetView里面实现不同的算法。外部使用的时候也可以根据不同的数据源,切换不同的Adapter。
静态工厂设计模式----实例化Fragement的时候使用,具体可以看下 http://www.cnblogs.com/androidsuperman/p/4471336.html。
其他设计模式可以看下我写的设计模式相关博客,以及http://gqdy365.iteye.com/blog/2122794
希望大神能够在后面评论中进行指点,或者相关知识点连接给个,我好学习下,不胜感激