5-25
今天面试了家公司,2个大神,差不多进行了1.5小时。不过最终还是没有录取,可能我的项目经验缺乏,能力不达标。
今天问的问题大致如下,凭记忆写的,反正就那样吧:
1、android service
startservice、bindservice

startservice()—onstartcommond( ){ }
bindservice( ):
在onBind( ){ }方法中返回SimpleBinder 对象。

public class LocalService extends Service {/**
* 在 Local Service 中我们直接继承 Binder 而不是 IBinder,因为 Binder 实现了 IBinder 接口,这样我们可以** 少做很多工作。
*/
public class SimpleBinder extends Binder{/**
* 获取 Service 实例
* @return
*/
public LocalService getService(){
return LocalService.this;
}public int add(int a, int b){
return a + b;
}
}public SimpleBinder sBinder;@Override
public void onCreate() {
super.onCreate();
// 创建 SimpleBinder
sBinder = new SimpleBinder();
}@Override
public IBinder onBind(Intent intent) {
// 返回 SimpleBinder 对象
return sBinder;
}
}

主要SimpleBinder extends Binder 自定义子类,添加的方法逻辑。

activity中:

  sc = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {LocalService.SimpleBinder sBinder = (LocalService.SimpleBinder)service;Log.v(TAG, "3 + 5 = " + sBinder.add(3, 5));Log.v(TAG, sBinder.getService().toString());}};
LocalService.SimpleBinder sBinder = (LocalService.SimpleBinder)service;

调用成员方法。

aidl如何实现
1 定义xxx.aidl
接口定义、方法、变量

package com.cao.android.demos.binder.aidl;
import com.cao.android.demos.binder.aidl.AIDLActivity;
interface AIDLService {     void registerTestCall(AIDLActivity cb);     void invokCallBack();
}  

2 自动生成xxx.java
有一个 Stub extends Binder implements 定义的接口

public static abstract class Stub extends android.os.Binder implements aidl.IMyInterface {..........public static aidl.IMyInterface asInterface(android.os.IBinder obj) {if ((obj == null)) {return null;}//检查Binder是不是在当前进程android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin != null) && (iin instanceof aidl.IMyInterface))) {return ((aidl.IMyInterface) iin);}return new aidl.IMyInterface.Stub.Proxy(obj);
}
}

3 服务器端 自定义的service中的
onBind( ){ }方法中返回AIDLService.Stub对象。

    private final AIDLService.Stub mBinder = new AIDLService.Stub() {  @Override  public void invokCallBack() throws RemoteException {  Log("AIDLService.invokCallBack");  Rect1 rect = new Rect1();  rect.bottom=-1;  rect.left=-1;  rect.right=1;  rect.top=1;  callback.performAction(rect);  }  @Override  public void registerTestCall(AIDLActivity cb) throws RemoteException {  Log("AIDLService.registerTestCall");  callback = cb;  }  };  
Stub翻译成中文是存根的意思,注意Stub对象是在被调用端进程,也就是服务端进程,至此,服务端aidl服务端得编码完成了。

4 activity中连接service服务,拿到binder对象,转换成自定义的接口,回调实现的方法。

    AIDLService mService;  private ServiceConnection mConnection = new ServiceConnection() {  public void onServiceConnected(ComponentName className, IBinder service) {  Log("connect service");  mService = AIDLService.Stub.asInterface(service);  try {  mService.registerTestCall(mCallback);  } catch (RemoteException e) {  }  }  public void onServiceDisconnected(ComponentName className) {  Log("disconnect service");  mService = null;  }  };  
mService就是AIDLService对象,具体可以看我后面提供的示例代码,需要注意在客户端需要存一个服务端实现了的aidl接口描述文件,但是客户端只是使用该aidl接口,不需要实现它的Stub类,获取服务端得aidl对象后mService = AIDLService.Stub.asInterface(service);,就可以在客户端使用它了,对mService对象方法的调用不是在客户端执行,而是在服务端执行。

扩展:接口描述文件如果参数是非基本类型变量,传输时候需要处理。
aidl中使用java类,需要实现Parcelable接口,并且在定义类相同包下面对类进行声明:
Rect1 implements Parcelable
之后你就可以在aidl接口中对该类进行使用了


package com.cao.android.demos.binder.aidl;
import com.cao.android.demos.binder.aidl.Rect1;
interface AIDLActivity {  void performAction(in Rect1 rect);
}

注意in/out的说明,我这里使用了in表示输入参数,out没有试过,为什么使用in/out暂时没有做深入研究
2、做过的项目哪些???
我该bug比较多,那你印象比较深刻的可以说1-2个吧。
3、android fragment
fragment删除有哪些方法,需要重写哪些方法?经常用到的有哪些???
fragment+viewpager模式
adapter绑定数据源

viewpager.notifyDatachanged( );

通过fragmentmanager: remove、replace

 //删  FragmentTransaction fts= fm.beginTransaction();  Fragment fratemp=fm.findFragmentById(R.id.ly1); //通过查找容器的id来找到该fratemp  fts.remove(fratemp);  fts.commit();  
fragmentTransaction.replace(R.id.fragment, new NewFragment());//其实替换就是先调用remove()方法,之后再掉用add();

4、有用到哪些框架吗?图片处理的知道哪些?
picasso、imageloader、glide、Fresco
问了区别,不知道,反正就是用imageloader多一点

Gif的支持
Fresco 支持

Glide 支持

Picasso 不支持

ImageLoader 不支持

Picasso是Square公司开源的一个Android平台上的图片加载框架,简单易用,一句话搞定项目中的图片加载,好用到令人发指。相比而言,这个也算是一个出来时间比较长的框架了。
使用示例:Picasso.with(this).load("url").placeholder(R.mipmap.ic_default).into(imageView);添加依赖compile 'com.squareup.picasso:picasso:2.5.2'A powerful image downloading and caching library for Android优点:图片质量高
缺点:加载速度一般
特点:只缓存一个全尺寸的图片,根据需求的大小在压缩转换
Fresco 是 Facebook 出品的新一代的图片加载库,我们知道 Android 应用程序可用的内存有限,经常会因为图片加载导致 OOM,虽然我们有各种手段去优化,尽量减少出现 OOM 的可能性,但是永远没法避免,尤其某些低端手机 OOM 更是严重。而 Facebook 就另辟蹊径,既然没法在 Java 层处理,我们就在更底层的 Native 堆做手脚。于是 Fresco 将图片放到一个特别的内存区域叫 Ashmem 区,就是属于 Native 堆,图片将不再占用 App 的内存,Java 层对此无能为力,这里是属于 C++ 的地盘,所以能大大的减少 OOM。添加依赖//添加依赖compile 'com.facebook.fresco:fresco:1.2.0'//**************下面的依赖需要根据需求添加******************//// 在 API < 14 上的机器支持 WebP 时,需要添加compile 'com.facebook.fresco:animated-base-support:1.2.0'// 支持 GIF 动图,需要添加compile 'com.facebook.fresco:animated-gif:1.2.0'// 支持 WebP (静态图+动图),需要添加compile 'com.facebook.fresco:animated-webp:1.2.0'compile 'com.facebook.fresco:webpsupport:1.2.0'// 仅支持 WebP 静态图,需要添加compile 'com.facebook.fresco:webpsupport:1.2.0'Fresco 支持许多URI格式,但 Fresco 不支持 相对路径的URI。所有的 URI 都必须是绝对路径,并且带上该 URI 的 scheme。如下:
类型                          SCHEME      示例
远程图片                    http://     HttpURLConnection 或者参考 使用其他网络加载方案
本地文件                    file://     FileInputStream
ContentProvider content://    ContentResolver
asset目录下的资源 asset://        AssetManager
res目录下的资源   res://      Resources.openRawResource
Uri中指定图片数据  data:mime/type;base64       数据类型必须符合 rfc2397规定 (仅支持 UTF-8)总结优点:支持图像渐进式呈现,大公司出品,后期维护有保障缺点:框架体积较大,3M左右会增大apk的大小;操作方式不是特别简单,有一定学习成本特点:有两级内存一级文件的缓存机制,并且有自己特别的内存区域来处理缓存,避免oom
Glide 是 Google 一位员工的大作,他完全是基于 Picasso 的,沿袭了 Picasso 的简洁风格,但是在此做了大量优化与改进。Glide 默认的 Bitmap 格式是 RGB_565 格式,而 Picasso 默认的是 ARGB_8888 格式,相比而言,这个内存开销要小一半。在磁盘缓存方面,Picasso 只会缓存原始尺寸的图片,而 Glide 缓存的是多种规格,也就意味着 Glide 会根据你 ImageView 的大小来缓存相应大小的图片尺寸,比如你 ImageView 大小是200*200,原图是 400*400 ,而使用 Glide 就会缓存 200*200 规格的图,而 Picasso 只会缓存 400*400 规格的。这个改进就会导致 Glide 比 Picasso 加载的速度要快,毕竟少了每次裁剪重新渲染的过程。最重要的一个特性是 Glide 支持加载 Gif 动态图,而 Picasso 不支持该特性。除此之外,还有很多其他配置选项的增加。总体来说,Glide 是在 Picasso 基础之上进行的二次开发,各个方面做了不少改进,不过这也导致他的包比 Picasso 大不少,不过也就不到 500k,Picasso 是100多k,方法数也比 Picasso 多不少,不过毕竟级别还是蛮小的,影响不是很大。添加依赖repositories {mavenCentral() // jcenter() works as well because it pulls from Maven Central}dependencies {compile 'com.github.bumptech.glide:glide:3.7.0'compile 'com.android.support:support-v4:19.1.0'}
Universal-Imager-Loadersergey Tarasevice出品,优点:(1)丰富的配置选项缺点:(1)最近一次维护在15年底,后期有不维护的趋势,可能被当前图片框架替代特点:三级缓存的策略

总结:
网友四个库都使用了一遍,对比后发现Fresco确实强大,加载大图Fresco最屌,有的图Glide( 是Picasso 基础)和Picasso加载不出来,换上Fresco妥妥的,不过Fresco比较庞大,推荐在主要都是图片的app中使用,一般的app使用Glide和Picasso就够了!
一句话总结就是:推荐Glide,其次推荐Fresco,其次是老牌的Image-Loader和Picasso。
推荐:http://blog.csdn.net/u013347784/article/details/52858203
http://www.cnblogs.com/baiqiantao/p/4de1411f10de3e687d619aa9d7b2a792.html

rxjava+rxandroid
这个“rx”是什么意思???为什么用这个框架,优点?
ReactiveX是Reactive Extensions的缩写,一般简写为Rx。微软给的定义是,Rx是一个函数库,让开发者可以利用可观察序列和LINQ风格查询操作符来编写异步和基于事件的程序,使用Rx,开发者可以用Observables表示异步数据流,用LINQ操作符查询异步数据流, 用Schedulers参数化异步数据流的并发处理,Rx可以这样定义:Rx = Observables + LINQ + Schedulers。

问到了eventbus:事务总线,没有用过,不过觉得和rxjava差不多,瞎扯扯。
优点吧,代码一目了然、量少、效率高、耦合度小。
5、问到了jni,android中的如何调用c/c++代码。
1.新建android工程
2.新建java上层方法
3.创建jni头文件
4.新建jni实现
5、生成jni so库
在jni目录下新建Android.mk文件用于编译生成jni库
6、包含jni库到工程中
在工程libs目录下新建armeabi目录和armeabi-v7a目录,将生成的jni库放到该目录下。 xxx.so库
7、调用
参考:
http://blog.csdn.net/smilefyx/article/details/52416539

6、java中的private 、protected、public、默认的
这四个修饰方法、类、变量访问权限。
同一个包下的子类、其他类、
不同包的子类、其他类,到底能否访问到????

类中的数据成员和成员函数据具有的访问权限包括:public、private、protect、friendly(包访问权限)

、、、、、、、、、、、、、、、、、、、、、、、、、、
priavte 本类可见
public 所有类可见
protected 本包和所有子类都可见(本包中的子类非子类均可访问,不同包中的子类可以访问,不是子类不能访问)
默认什么都没有 本包可见(即默认的形式,同包访问)(本包中的子类非子类均可访问,不同包中的类及子类均不能访问)
、、、、、、、、、、、、、、、、、、、、、、、、、、、

类权限:只有2个 public、默认
默认修改类 比如

 class Test1 {
...
}

在其他包下的代码中

new Test1();

报错,不可见!!!
默认修饰的类,不同包下无法导出!!!

public修饰类:可以在任何一个类中被调用,不管同包或不同包,是权限最大的一个修饰符。

总结如下:
私有权限 private
private可以修饰数据成员,构造方法,方法成员,不能修饰类(此处指外部 类,不考虑内部类)。被private修饰的成员,只能在定义它们的类中使用,在 其他类中不能调用。

默认权限 (default)
类,数据成员,构造方法,方法成员,都能够使用默认权限,即不写任何关 键字。默认权限即同包权限,同包权限的元素只能在定义它们的类中,以及同包 的类中被调用。

受保护权限protected
protected可以修饰数据成员,构造方法,方法成员,不能修饰类(此处指外 部类,不考虑内部类)。被protected修饰的成员,能在定义它们的类中,同包 的类中被调用。如果有不同包的类想调用它们,那么这个类必须是定义它们的类 的子类。

公共权限 public
public可以修饰类,数据成员,构造方法,方法成员。被public修饰的成员 ,可以在任何一个类中被调用,不管同包或不同包,是权限最大的一个修饰符。

7、java中的final可以修饰类、方法么???
如果可以,子类能不能使用???
final可以修改类,但是子类tmd是不能继承的!!!
final可以修饰方法,但是子类无法重写!!!

8、java的继承、实现的区别???
单继承
多实现
接口和抽象类显著的共同点是接口和抽象类都可以有抽象方法。
接口和抽象类的不同点有:
(1)抽象类可以有实例变量,而接口不能拥有实例变量,接口中的变量都是静态(static)的常量(final)。
(2)抽象类可以有非抽象方法,而接口只能有抽象方法。
(3)Java中接口方法不管是否加了修饰符都是public。因此在实现的时候修饰范围不能缩小,只能是public。
“interface”(接口)可将其想象为一个“纯”抽象类。它允许创建者规定一个类的基本形式:方法名、自变量列表以及返回类型,但不实现方法主体。接口也可包含基本数据类型的数据成员,但它们都默认为public、static 和final。接口中定义的方法默认为public、abstract。
抽象类可以有自己实现的方法,也可以有抽象类方法,但是如果是抽象类方法那么必须是:

public abstract 修饰

接口继承接口 。。。

public   interface  InterfaceSub  extends  InterfaceA, interfaceB {            }   

9、java中的匿名对象使用方法??

            tv.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {Intent intent = new Intent(mContext, ValidCodeLoginActivity.class);startActivityForResult(intent, 0);//requestCode}});

匿名对象使用方法一:当对对象的方法只调用一次时,可以用匿名对象来完成,这样写比较简化。
如果对一个对象进行多个成员的调用,就必须给这个对象起个名字。
匿名对象使用方法二:可以将匿名对象作为实际参数进行传递。

定义在另外一个类中的类,叫内部类。
匿名内部类:
没有名字的类,创建类的同时,也会创建一个对象。
只需要用到一次的类,就可以使用匿名内部类

只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现。
最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口。

public class Demo {public static void main(String[] args) {Thread t = new Thread() {public void run() {for (int i = 1; i <= 5; i++) {System.out.print(i + " ");}}};t.start();}
}

静态内部类

1.静态内部类只能访问外部类静态的方法和变量,不能访问非静态。

2.静态内部类可以不需要创建外部类的引用,而直接创建。

我说了一点:Java匿名内部类只能访问final参数或者final的局部变量?不知道原因。
final从语法上约束了实际上两个不同变量的一致性(表现为同一变量)
首先,这关系到java对象中的生命周期的问题。

基础数据类型和引用变量(不是被引用的对象)做局部变量时(这里是和做为变量成员变量区别,它们作为成员变量后就作为对象的一部分和对象的生命周期相同了);它们的生命中周期是有作用域的,它没有受生命周期影响这一说,但是同样在这一作用域创建的对象的生命周期并不受作用域的限制。
局部变量的生命周期与局部内部类的对象的生命周期的不一致。
内部类里面使用外部类的局部变量时,其实就是内部类的对象在使用它,内部类对象生命周期中都可能调用它,而内部类试图访问外部方法中的局部变量时,外部方法的局部变量很可能已经不存在了,那么就得延续其生命,拷贝到内部类中,而拷贝会带来不一致性,从而需要使用final声明保证一致性。复制保证生命周期延续,final保证引用一致。

10、Binder的机制是什么???
感觉就是一个中间者,连接aidl和java代码,可以互相调用。
aidl中使用了binder

        AIDL支持Java原始数据类型AIDL支持String和CharSequenceAIDL支持传递其他AIDL接口,但你引用的每个AIDL接口都需要一个import语句,即使位于同一个包中AIDL支持传递实现了android.os.Parcelable接口的复杂类型,同样在引用这些类型时也需要import语句AIDL支持java.util.List和java.util.Map,但是有一些限制。集合中项的允许数据类型包括Java原始类型、String、CharSequence或是android.os.Parcelable。无需为List和Map提供import语句,但需要为Parcelable提供import语句非原始类型中,除了String和CharSequence以外,其余均需要一个方向指示符。方向指示符包括in、out、和inout。in表示由客户端设置,out表示由服务端设置,inout表示客户端和服务端都设置了该值http://blog.csdn.net/sugar_z_/article/details/49384153

http://blog.csdn.net/huachao1001/article/details/51504469

11、v4、v7包的区别,为什么要使用这些包???
兼容低版本

Android Support v4: 这个包是为了照顾Android 1.6及以上版本而设计的,在开发中,默认都会使用到这个包Android Support v7: 这个包是为了照顾Android 2.1及以上版本而设计的,但是不能兼容低版本 Android 系统,如果开发中不考虑 1.6 ,可以采用这个包。另外要注意的是,v7 包是依赖 v4 包的,即引入 v7 包的话要同时引入 v4 包Android Support v13: 这个包是为了照顾Android 3.2及以上版本而设计的,一般开发中不会用到,平板开发可能会用到
http://www.jianshu.com/p/695c02084532

12、问到Android Material Design 有了解么????
有了解,是和主题style相关的。具体使用没有。。。
ANDROID L 5.0- Material Design详解(主题和布局)
http://www.open-open.com/lib/view/open1416664325648.html
Material Design是Google推出的一个全新的设计语言,它的特点就是拟物扁平化。

Material Design包含了很多内容,我大致把它分为四部分:

主题和布局——ANDROID L——Material Design详解(主题和布局)

视图和阴影——ANDROID L——Material Design详解(视图和阴影)

UI控件——ANDROID L——Material Design详解(UI控件)

动画——ANDROID L——Material Design详解(动画篇)

http://mobile.51cto.com/design-446201.htm
http://www.uisdc.com/comprehensive-material-design-note
http://www.jianshu.com/p/1e6eed09d48b
http://design.1sters.com/#
13、JNI传递参数怎么实现的???
android代码定义native方法—加载so库,通过java代码来调用c/c++写的方法。

14、service在主线程还是子线程中执行的???
4大组件都是在主线程执行,都不可以做耗时操作!!!

15、播放一个系统音乐如何实现,大致流程???
mediaplayer 加载
url 资源文件地址
prepare
监听预加载完成后 start ,开始播放
播放结束监听,做操作。

mediaplayer内部使用了handler+looper+线程机制,
放在service中播放,如果没有界面显示,播放时不需要放在线程中的,因为本身就支持线程了,通常不会anr!!!

16、activity启动模式
launchMode在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否要和其他Activity实例共用一个task???
这里简单介绍一下task的概念,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。

task只针对activity的。
一个应用可以有多个activity,每个activity的task可以不一样!!!

设置方法:

    <activity  android:name=".A1"  android:launchMode="standard" />  

Activity启动方式有四种,分别是:
1 standard
若我有一个Activity名为A1, 上面有一个按钮可跳转到A1。那么如果我点击按钮,便会新启一个Activity A1叠在刚才的A1之上,再点击,又会再新启一个在它之上……
点back键会依照栈顺序依次退出。

   Intent intent = new Intent(FirstActivity.this, FirstActivity.class);startActivity(intent);
      activity实例:有N个对象。

2 singleTop
可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。
例如:
若我有两个Activity名为B1,B2,两个Activity内容功能完全相同,都有两个按钮可以跳到B1或者B2,唯一不同的是B1为standard,B2为singleTop。
若我意图打开的顺序为B1->B2->B2,则实际打开的顺序为B1->B2(后一次意图打开B2,实际只调用了前一个的onNewIntent方法)
activity实例:2个
若我意图打开的顺序为B1->B2->B1->B2,则实际打开的顺序与意图的一致,为B1->B2->B1->B2。
activity实例:4个

3 singleTask
例如:
若我的应用程序中有三个Activity,C1,C2,C3,三个Activity可互相启动,其中C2为singleTask模式,那么,无论我在这个程序中如何点击启动,如:C1->C2->C3->C2->C3->C1-C2,C1,C3可能存在多个实例,但是C2只会存在一个,并且这三个Activity都在同一个task里面。
但是C1->C2->C3->C2->C3->C1-C2,这样的操作过程实际应该是如下这样的,因为singleTask会把task中在其之上的其它Activity destory掉。
操作:C1->C2
C1->C2->C3
C1->C2->C3->C2
C1->C2->C3->C2->C3->C1
C1->C2->C3->C2->C3->C1-C2
实际:C1->C2
C1->C2->C3
C1->C2
C1->C2->C3->C1
C1->C2

若是别的应用程序打开C2,则会新启一个task。
如别的应用Other中有一个activity,taskId为200,从它打开C2,则C2的taskIdI不会为200,例如C2的taskId为201,那么再从C2打开C1、C3,则C2、C3的taskId仍为201。
注意:如果此时你点击home,然后再打开Other,发现这时显示的肯定会是Other应用中的内容,而不会是我们应用中的C1 C2 C3中的其中一个。
activitya模式是singletask
那么栈中始终只有一个activityA实例;
activityA调转到其他activity,再返回来,其他的activity会被销毁,
activityA只要显示在界面上,那么它就是栈顶元素。
还有就是显示它,那它上面的activity都是被销毁调用destroy方法。

4 singleInstance
只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。
一个栈中只有一个activity。
例如:3个activity都是singleInstance
activity1跳—activity2跳—activity3
task1只有activity1
task2只有activity2
task3只有activity3

例如:
程序有三个ActivityD1,D2,D3,三个Activity可互相启动,其中D2为singleInstance模式。那么程序从D1开始运行,假设D1的taskId为200,那么从D1启动D2时,D2会新启动一个task,即D2与D1不在一个task中运行。假设D2的taskId为201,再从D2启动D3时,D3的taskId为200,也就是说它被压到了D1启动的任务栈中。

若是在别的应用程序打开D2,假设Other的taskId为200,打开D2,D2会新建一个task运行,假设它的taskId为201,那么如果这时再从D2启动D1或者D3,则又会再创建一个task,因此,若操作步骤为other->D2->D1,这过程就涉及到了3个task了。

好了,大概就是这些吧,泪啊
任重而道远!!!

6-1
栈内存
在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。
栈内存主要存放的是基本类型类型的数据 如( int, short, long, byte, float, double, boolean, char) 和对象句柄。对象句柄 就是一个对象变量。
注意:并没有String基本类型、在栈内存的数据的大小及生存周期是必须确定的、其优点是寄存速度快、栈数据可以共享、缺点是数据固定、不够灵活。
String是一个特殊的包装类数据,可以

String str = new String(“abc”);

String str = “abc”;//只在栈内存分配形式来创建

第一种是用new()来创建对象的,它会存放在堆中,每调用一次就会创建一个新的对象;而第二种是先在栈中创建一个对String类的对象引用变量str ,然后查找栈中有没有存放”abc”,如果没有,则将”abc”存放进栈,并令str 指向”abc”,如果已经有”abc”,则直接令str 指向”abc”。

堆内存
堆内存用来存放所有new 创建的对象和 数组的数据

String str1 = new String ("myString");String str2 = "myString";System.out.println(str1 ==str2 ); //FalseString str1 = new String ("myString");String str2 = new String ("myString");System.out.println(a==b); //False 

创建了两个引用,创建了两个对象。两个引用分别指向不同的两个对象。以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。

还有:
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。-程序结束后有系统释放
4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

android内存溢出:
一、单例造成的内存泄漏
Android的单例模式非常受开发者的喜爱,不过使用的不恰当的话也会造成内存泄漏。因为单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。

public class AppManager {private static AppManager instance;private Context context;private AppManager(Context context) {this.context = context;}public static AppManager getInstance(Context context) {if (instance != null) {instance = new AppManager(context);}return instance;}}

这是一个普通的单例模式,当创建这个单例的时候,由于需要传入一个Context,所以这个Context的生命周期的长短至关重要:

1、传入的是Application的Context:这将没有任何问题,因为单例的生命周期和Application的一样长 ;

2、传入的是Activity的Context:当这个Context所对应的Activity退出时,由于该Context和Activity的生命周期一样长(Activity间接继承于Context),所以当前Activity退出时它的内存并不会被回收,因为单例对象持有该Activity的引用。

所以正确的单例应该修改为下面这种方式:public class AppManager {private static AppManager instance;private Context context;private AppManager(Context context) {this.context = context.getApplicationContext();}public static AppManager getInstance(Context context) {if (instance != null) {instance = new AppManager(context);}return instance;}}

这样不管传入什么Context最终将使用Application的Context,而单例的生命周期和应用的一样长,这样就防止了内存泄漏。

二、非静态内部类创建静态实例造成的内存泄漏
三、Handler造成的内存泄漏
四、线程造成的内存泄漏
五、资源未关闭造成的内存泄漏
对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。

Android 的 Context 内存泄露,其实就是因为 Activity 是有生命周期的,所以在 Activity 销毁后,必须释放掉所有对其的强引用,否则 GC 将不会及时回收已经不再使用的 Activity,导致内存泄露。所以,我们在使用 Activity Context 的时候,应该注意判断下在 Activity 销毁时此变量是否依然引用 Activity。

简单说,生命周期长的中持有周期短的引用,当短的activity销毁后,由于引用被其他地方持有,GC不会及时回收,导致内存泄漏。

解决方法:1.去掉 static 关键字,使用别的方法来实现想要的功能。任何时候不建议 static 修饰 Activity,如果这样做了,Android Studio 也会给出警告提示。2.在 onDestroy 方法中置空 Activity 静态引用@Override
public void onDestroy() {super.onDestroy();if (activity != null) {activity = null;}
}3.也可以使用到软引用解决,确保在 Activity 销毁时,垃圾回收机制可以将其回收。像下面这样做:private static WeakReference<MainActivity> activityReference;private void setStaticActivity() {activityReference = new WeakReference<MainActivity>(this);
}
// 注意在使用时,必须判空
private void useActivityReference(){MainActivity activity = activityReference.get();if (activity != null) {// ...}
}

其他造成内存泄漏以及解决方法参考:
http://www.tuicool.com/articles/vqE7NbM

6-2
刚刚去了一家面试,这次问的比较细,完全答不上来啊。
1、问了android体系架构
每层功能简要介绍如下:

  一 应用程序层该层提供一些核心应用程序包,例如电子邮件、短信、日历、地图、浏览器和联系人管理等。同时,开发者可以利用Java语言设计和编写属于自己的应用程序,而这些程序与那些核心应用程序彼此平等、友好共处。二 应用程序框架层该层是Android应用开发的基础,开发人员大部分情况是在和她打交道。应用程序框架层包括活动管理器、窗口管理器、内容提供者、视图系统、包管理器、电话管理器、资源管理器、位置管理器、通知管理器和XMPP服务十个部分。在Android平台上,开发人员可以完全访问核心应用程序所使用的API框架。并且,任何一个应用程序都可以发布自身的功能模块,而其他应用程序则可以使用这些已发布的功能模块。基于这样的重用机制,用户就可以方便地替换平台本身的各种应用程序组件。三 系统库和Android运行时系统库包括九个子系统,分别是图层管理、媒体库、SQLite、OpenGLEState、FreeType、WebKit、SGL、SSL和libc。Android运行时包括核心库和Dalvik虚拟机,前者既兼容了大多数Java语言所需要调用的功能函数,又包括了Android的核心库,比如android.os、android.NET、android.media等等。后者是一种基于寄存器的虚拟机,Dalvik虚拟机主要是完成对生命周期的管理、堆栈的管理、线程的管理、安全和异常的管理以及垃圾回收等重要功能。

Dalvik虚拟机和一般Java虚拟机(Java VM)不同,它执行的不是Java标准的字节码(bytecode )而是Dalvik可执行格式(.dex)中执行文件。在执行的过程中,每一个应用程序即一个进程(Linux的一个Process)。 二者最大的区别在于Java VM是以基于栈的虚拟机(Stack-based),而Dalvik是基于寄存器的虚拟机(Register-based)。显然,后者最大的好处在于可以根据硬件实现更大的优化,这更适合移动设备的特点。

 四 Linux内核Android核心系统服务依赖于Linux2.6内核,如安全性、内存管理、进程管理、网络协议栈和驱动模型。Linux内核也是作为硬件与软件栈的抽象层。驱动:显示驱动、摄像头驱动、键盘驱动、WiFi驱动、Audio驱动、flash内存驱动、Binder(IPC)驱动、电源管理等。

2、数据存储方式。重点问了sharedpreference怎么存储object对象???
存储方式:
http://www.cnblogs.com/ITtangtang/p/3920916.html#type1

我认为通常sharedpreference存的基本数据类型、string这一类。
object我猜测是把对象序列化再进行存储,其实也差不多了,但是我没有敢深一层说,把对象转化成二进制数据string存储起来,哎。。。
sp存储复杂对象:
http://www.360doc.com/content/13/0412/22/11869283_277896078.shtml

 /** * 序列化对象 *  * @param person * @return * @throws IOException */  private String serialize(Person person) throws IOException {  startTime = System.currentTimeMillis();  ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();  ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);  objectOutputStream.writeObject(person);  String serStr = byteArrayOutputStream.toString("ISO-8859-1");  serStr = java.net.URLEncoder.encode(serStr, "UTF-8");  objectOutputStream.close();  byteArrayOutputStream.close();  Log.d("serial", "serialize str =" + serStr);  endTime = System.currentTimeMillis();  Log.d("serial", "序列化耗时为:" + (endTime - startTime));  return serStr;  }  /** * 反序列化对象 *  * @param str * @return * @throws IOException * @throws ClassNotFoundException */  private Person deSerialization(String str) throws IOException,  ClassNotFoundException {  startTime = System.currentTimeMillis();  String redStr = java.net.URLDecoder.decode(str, "UTF-8");  ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(  redStr.getBytes("ISO-8859-1"));  ObjectInputStream objectInputStream = new ObjectInputStream(  byteArrayInputStream);  Person person = (Person) objectInputStream.readObject();  objectInputStream.close();  byteArrayInputStream.close();  endTime = System.currentTimeMillis();  Log.d("serial", "反序列化耗时为:" + (endTime - startTime));  return person;  }  void saveObject(String strObject) {  SharedPreferences sp = getSharedPreferences("person", 0);  Editor edit = sp.edit();  edit.putString("person", strObject);  edit.commit();  }  String getObject() {  SharedPreferences sp = getSharedPreferences("person", 0);  return sp.getString("person", null);  }  

保存流转化成二进制,说白了,最终就是转换成了二进制数据,:

   ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();  ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);  objectOutputStream.writeObject(person);  String serStr = byteArrayOutputStream.toString("ISO-8859-1");  serStr = java.net.URLEncoder.encode(serStr, "UTF-8");  

3、自定义view,在哪里设置控件添加的属性???
xml中怎么调用????

1 自定义属性的声明文件,编写values/attrs.xml,在其中编写styleable和item等标签元素

    <?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="test"><attr name="text" format="string" /><attr name="testAttr" format="integer" /></declare-styleable></resources>

2 自定义一个MyTextView(extends View )类
,在MyTextView的构造方法中通过TypedArray获取

  public MyTextView(Context context, AttributeSet attrs) {super(context, attrs);TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.test);String text = ta.getString(R.styleable.test_testAttr);int textAttr = ta.getInteger(R.styleable.test_text, -1);Log.e(TAG, "text = " + text + " , textAttr = " + textAttr);ta.recycle();}

3 在布局文件中CustomView使用自定义的属性(注意namespace)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:zhy="http://schemas.android.com/apk/res/com.example.test"android:layout_width="match_parent"android:layout_height="match_parent" ><com.example.test.MyTextViewandroid:layout_width="100dp"android:layout_height="200dp"zhy:testAttr="520"zhy:text="helloworld" /></RelativeLayout>

4、NDK中配置so库调用,配置文件怎么设置的???
http://blog.csdn.net/zjh1002492540/article/details/50312801

一、编译一个简单的APK LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)# Build all java files in the java subdirectoryLOCAL_SRC_FILES := $(call all-subdir-java-files)# Name of the APK to buildLOCAL_PACKAGE_NAME := LocalPackage# Tell it to build an APKinclude $(BUILD_PACKAGE)
二、编译一个依赖静态.jar文件的APK LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)# List of static libraries to include in the packageLOCAL_STATIC_JAVA_LIBRARIES := static-library# Build all java files in the java subdirectoryLOCAL_SRC_FILES := $(call all-subdir-java-files)# Name of the APK to buildLOCAL_PACKAGE_NAME := LocalPackage# Tell it to build an APKinclude $(BUILD_PACKAGE)注:LOCAL_STATIC_JAVA_LIBRARIES 后面应是你的APK程序所需要的JAVA库的JAR文件名。

http://huaonline.iteye.com/blog/1988026
将.c文件通过配置,生成.so库。

5、tcp属于哪一层协议???socket怎么指定使用tcp、udp协议????
tcp 、udp传输层。

建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

TCP(传输控制协议)和UDP(用户数据报协议是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议。
TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流,TCP套接口是字节流套接口(stream socket)的一种。
UDP:用户数据报协议。UDP是一种无连接协议。UDP套接口是数据报套接口(datagram socket)的一种。
TCP Socket通信学习
http://blog.csdn.net/segen_jaa/article/details/7552842
UDP Socket通信学习
http://blog.csdn.net/segen_jaa/article/details/7565689

使用socket()来建立一个UDP socket,第二个参数为SOCK_DGRAM。SOCK_STREAM是基于TCP的,数据传输比较有保障。SOCK_DGRAM是基于UDP的,专门用于局域网,基于广播

http://blog.csdn.net/sinat_28494049/article/details/46006233

6、sql语句怎么写,
比如查询班级所有人里面名字包含“红”这个字的人。
尼玛,我忘记了。。。
select * from table where 列名 like ‘a%’
具体学习参考:
http://blog.csdn.net/jason0539/article/details/10248457
结束。。。

6-7
今天去面了2家。
问的问题也差不多吧
1、activity 启动模式,区别

2、内存优化,哪些方面

3、自定义view

4、imageloader 缓存机制怎么实现,一级缓存、二级缓存,
源码实现。
listview中checkbox选中,滑动导致错乱问题。。。

5、viewpager 嵌套viewpager 会不会导致滑动出错

6、点击事件捕捉机制,顺序

7、内存泄漏,说到
匿名内部类、内部类。。。
8、handler机制
handler loop messagequeue message
http://blog.csdn.net/u010032372/article/details/49739799
http://droidyue.com/blog/2014/10/02/the-private-modifier-in-java/
非静态的内部类和匿名内部类都会隐式地持有其外部类的引用!!!!

9、retrofit2.0 中实现原理,基于okhttp,注解实现

10、imageloder的图片缓存,好像是类似 Linkedhashmap~~~
说到内存缓存LRU
http://blog.csdn.net/t12x3456/article/details/7788149

开发中大部分情况下我们需要缓存图片,用imageLoader两步实现加载网络图片后,缓存到内存以及sd卡.再次读取该图片时先从内存找,有则直接加载,没有则从sd卡找,再没有则读网络,这样实现了三级缓存.
http://blog.csdn.net/bigboysunshine/article/details/53487653
其中cacheInMemory(true) 和cacheOnDisk(true)必须设置,目的是加载网络图片后进行缓存.
ImageLoader的缓存策略内存缓存优先于硬盘缓存
清除缓存.如果需要清除缓存的话调用clearMemoryCache()和clearDiskCache()即可.

RAM:断电不保存
ROM:相当于硬盘 u盘

    ImageLoader.getInstance().clearMemoryCache();  ImageLoader.getInstance().clearDiskCache();  

大概就这样。。。

2017/6/8
今天上午面试3家。
主要问了
http 协议原理 三次握手 ack syn
请求格式
1 请求行
2 请求头
3 请求包体

响应格式
1 状态行
2 响应头
3 响应体

http的请求方法有哪些?
我说了post、get,然后忘记了其他的。。。悲剧
好像还有put、delete。。。
问了 数据可以放在哪些地方。
我说了请求正文中,然后问了能不能放其他地方。。。
最多放多大。。。尼玛,无语

tcp、udp区别
socket通信原理

activity和fragment 使用

NDK开发

反正就是大的公司,就会问具体协议原理,
邮件协议、http、tcp、udp、ip
感觉很装逼的样子,擦。。。

重点:
android中mvc的设计:
http://www.2cto.com/kf/201506/405766.html

在Android项目中,
业务逻辑,数据处理(涉及代码)等担任了Model(模型)角色,XML界面显示等担任了View(视图)角色

Activity担任了Contronller(控制器)角色,
contronller(控制器)是一个中间桥梁的作用,通过接口通信来协同 View(视图)和Model(模型)工作,起到了两者之间的通信作用。
参考:
http://blog.csdn.net/u011494050/article/details/24556051
Android中界面部分也采用了当前比较流行的MVC框架,在android中:

  1) 视图层(View):一般采用XML文件进行界面的描述,使用的时候可以非常方便的引入。当然,如何你对Android了解的比较的多了话,就一定可以想到在Android中也可以使用JavaScript+HTML等的方式作为View层,当然这里需要进行Java和javascript之间的通信,幸运的是,Android提供了它们之间非常方便的通信实现。

  2) 控制层(Controller):Android的控制层的重任通常落在了众多的Acitvity的肩上,这句话也就暗含了不要在Acitivity中写代码,要通过Activity交割Model业务逻辑层处理,这样做的另外一个原因是Android中的Acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。

  3) 模型层(Model):对数据库的操作、对网络等的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层的。就是应用程序中二进制的数据。

2017-6-13
今天去苏宁面试,问的也比较基础吧,比较细致,感觉自己很多只了解片面,内部细致的不清楚。
有问道一些
实现启动activity,做个补充。

显式:
Intent intent = new Intent(MyActivity.this, MyOtherActivity.class);
startActivity(intent);
隐式:
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(“tel:555-2368”));
startActivity(intent);
声明
<activity android:name=".xxx.xxxActivity" android:launchMode="xxx" >
1、activity启动模式这个我把singletop 和singleinstance弄混乱了。。。
standard
activityA 是standard 模式,那么它里面按钮点击startactivity(activitya),每次点击都会在栈中创建一个相同的实例,
多个重复堆叠
singtask 栈内复用模式
栈内已经存在一个a实例,再次回到这个a实例时候,会调用onNewIntent方法,
同时,把a上面的activity全部销毁。
栈中a的实例只有一个,会有一个destroy的操作。
b---standard
a-b-a
这个时候栈中只有一个实例a,会把b给destroy掉。
b-a-b-a
这个时候栈中有b a2个实例,因为第四层的a已经存在 了,会把bdestroy掉。
扩展:
这里面有个栈的概念,默认没有指定,只有一个栈taskid,这个栈的名字就是包名。
如果taskAffinity属性不是包名,那么启动的activity会重新创建一个栈,对应一个新的taskid当MainActivity启动时创建的Task的名字就是包名,因为MainActivity也没有指定taskAffinity,而当我们启动SingleTaskActivity ,首先会寻找需要的任务栈是否存在,也就是taskAffinity指定的值,这里就是包名,发现存在,就不再创建新的task,而是直接使用。如果ActivitySingleTask 指定了一个taskAffinity,不再是默认的包名了。
<activity android:name=".ActivitySingleTask" android:launchMode="singleTask" android:taskAffinity="com.castiel.demo.singletask"/>
所属的任务栈的TaskId发生了变换,也就是说开启了一个新的Task,并且之后的OtherActivity也运行在了该Task上。
singtop 栈顶复用模式
栈中a可以有相同的实例,前提是这些实例不能够相邻。
a 是standard
b是singtopa-b-b  栈中有2个实例 a -b,第二个b会调用 onNewIntenta-b-a-b 栈中有4个实例 a b a b,因为2个b 不相邻。
singleinstance 全局唯一模式
一个栈中有且只有一个activitya的实例。
应用a启动 activitya,由于activitya没有创建过,会做一次oncreate操作,home键返回。
应用b中启动activityb,activitya已经存在系统一个栈中,不会重新创建,以及使用原来的栈中activity,会调用onNewIntent(),activitya 所属应用,如果有个按钮点击,startactivity(activitya),不会创建,会调用onNewIntent()

参考:
http://blog.csdn.net/mynameishuangshuai/article/details/51491074

苏宁易购首页非常长,每一块,理解成楼层,会动态变化,怎么实现。
listview控件,每一层模块可以是一个fragment;
动态变化,通过重写
代码很简单,主要就是在adapter里面重写

getViewTypeCount()

getItemViewType(int position)
这两个方法。
http://blog.csdn.net/qinzhen308/article/details/52212261
核心代码

public class MultiStyleListAdapter extends AbstractListAdapter<Object> {  private Class[] dataClasses;  @Override  public View getView(int position, View view, ViewGroup parent) {  int viewType=getItemViewType(position);  if (viewType==0) {  view = getStyle1View(position, view, parent);  }else if (viewType==1) {  view = getStyle2View(position, view, parent);  } else if(viewType==2){  view = getStyle3View(position, view, parent);  }else if(viewType==3){  view=getStyle4View(position, view, parent);  }  return view;  }  public MultiStyleListAdapter(Context context) {  // TODO Auto-generated constructor stub  super(context);  dataClasses=new Class[]{Data1.class,Data2.class,Data3.class,Data4.class};  }  /** * 注意返回的类型: * 如果只有1种布局类型,那么返回的type是0; * 如果2种类型,必须是0,1 * 如果3种类型,必须是0,1,2 * 。。。。 * 依次类推 * @param position 根据position返回对应位置的视图类型 * @return */  @Override  public int getItemViewType(int position) {  // TODO Auto-generated method stub  Object object=getItem(position);  for(int i=0,size=dataClasses.length;i<size;i++){  if(object.getClass()== dataClasses[i]){  return i;  }  }  return 0;  }  /** * @return 返回值是,布局种类总数 */  @Override  public int getViewTypeCount() {  // TODO Auto-generated method stub  return dataClasses.length;  }  private View getStyle1View(final int position, View convertView,  ViewGroup parent) {  final Styly1ViewHolder holder;  if (convertView == null) {  convertView = mInflater.inflate(R.layout.item_style_1, null);  holder = new Styly1ViewHolder(convertView);  convertView.setTag(holder);  } else {  holder = (Styly1ViewHolder) convertView.getTag();  }  final Data1 item=(Data1)mList.get(position);  holder.tvIndex.setText("index="+position);  holder.content.setText(item.content);  return convertView;  }  private View getStyle2View(final int position, View convertView,  ViewGroup parent) {  final Styly2ViewHolder holder;  if (convertView == null) {  convertView = mInflater.inflate(R.layout.item_style_2, null);  holder = new Styly2ViewHolder(convertView);  convertView.setTag(holder);  } else {  holder = (Styly2ViewHolder) convertView.getTag();  }  final Data2 item=(Data2)mList.get(position);  holder.tvIndex.setText("index="+position);  holder.pic.setImageResource(item.img);  return convertView;  }  private View getStyle3View(final int position, View convertView,  ViewGroup parent) {  final Styly3ViewHolder holder;  if (convertView == null) {  convertView = mInflater.inflate(R.layout.item_style_3, null);  holder = new Styly3ViewHolder(convertView);  convertView.setTag(holder);  } else {  holder = (Styly3ViewHolder) convertView.getTag();  }  final Data3 item=(Data3)mList.get(position);  holder.tvIndex.setText("index="+position);  holder.pic1.setImageResource(item.img1);  holder.pic2.setImageResource(item.img2);  holder.pic3.setImageResource(item.img3);  return convertView;  }  private View getStyle4View(final int position, View convertView,  ViewGroup parent) {  final Styly4ViewHolder holder;  if (convertView == null) {  convertView = mInflater.inflate(R.layout.item_style_4, null);  holder = new Styly4ViewHolder(convertView);  convertView.setTag(holder);  } else {  holder = (Styly4ViewHolder) convertView.getTag();  }  final Data4 item=(Data4)mList.get(position);  holder.tvIndex.setText("index="+position);  holder.checkBox.setText(item.content);  holder.checkBox.setChecked(item.isChecked);  return convertView;  }  class Styly1ViewHolder {  TextView tvIndex;  TextView content;  public Styly1ViewHolder(View root){  content=(TextView)root.findViewById(R.id.content);  tvIndex=(TextView)root.findViewById(R.id.index);  }  }  class Styly2ViewHolder {  TextView tvIndex;  ImageView pic;  public Styly2ViewHolder(View root){  pic=(ImageView)root.findViewById(R.id.content);  tvIndex=(TextView)root.findViewById(R.id.index);  }  }  class Styly3ViewHolder {  TextView tvIndex;  ImageView pic1;  ImageView pic2;  ImageView pic3;  public Styly3ViewHolder(View root){  pic1=(ImageView)root.findViewById(R.id.img1);  pic2=(ImageView)root.findViewById(R.id.img2);  pic3=(ImageView)root.findViewById(R.id.img3);  tvIndex=(TextView)root.findViewById(R.id.index);  }  }  class Styly4ViewHolder {  TextView tvIndex;  CheckBox checkBox;  public Styly4ViewHolder(View root){  checkBox=(CheckBox)root.findViewById(R.id.checkbox);  tvIndex=(TextView)root.findViewById(R.id.index);  } }
}  

ListView的观察者模式的应用,以及调用notifyDataSetChanged()方法时,刷新ListView。
有时候初始化listview的时候,发现没有走getview方法,而导致什么都不显示是因为适配器会先执行getcount方法,如果返回0则不会执行getview方法。

listview滚动时,判定哪些view超出屏幕,超出就被放入回收站里,等又需要view的时候,listview根据viewtype类型从回收站里取出来复用,并回调到adapter的getview方法里面,从而达到多类型复用的效果。

ListView绘制的过程如下:首先,系统在绘制ListView之前,将会先调用getCount方法来获取Item的个数。之后每绘制一个Item就会调用一次getView方法,在此方法内就可以引用事先定义好的xml来确定显示的效果并返回一个View对象作为一个Item显示出来。也正是在这个过程中完成了适配器的主要转换功能,把数据和资源以开发者想要的效果显示出来。也正是getView的重复调用,使得ListView的使用更为简单和灵活。这两个方法是自定ListView显示效果中最为重要的,同时只要重写好了就两个方法,ListView就能完全按开发者的要求显示。而getItem和getItemId方法将会在调用ListView的响应方法的时候被调用到。所以要保证ListView的各个方法有效的话,这两个方法也得重写。比如:没有完成getItemId方法的功能实现的话,当调用ListView的getItemIdAtPosition方法时将会得不到想要的结果,因为该方法就是调用了对应的适配器的getItemId方法。

listview首次加载:
和listview的属性有关系

  在布局,我们只有一个listview的时候。那好。我们把高设置成wrap_content的时候。在listview里加载几行看看。日志在getview里打印一下。是不是重复调用了?那这个办法就好弄了。把高设置成fill_parent就成了。这个时候发现日志还是重复调用?那就要看一下Listview的上一级布局的高是不是也是设置也fill_parent的,如果不是。请改动吧。如果是。那我还真没碰到重复调用的!因为测试好几次了!

getcount 执行次数,看当前界面最多显示几条item;
我的首页最多显示3条数据:

可以看出先调用
getcount—共有4条数据
getitemid
getview —最多显示几条,初始化调用几次getview。
注意:一页最多显示3条,会new 4个,从5个开始复用convertview。
n —> n+1 —> n+2
button点击添加一条数据:
会重绘当前可视的界面:

  button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubmList.add("position:" + i++);adapter.notifyDataSetChanged();}});

页面显示0-1-2,点击添加

把第一、二行滑出去,页面显示position 2-3-4,点击添加

可以看出首选重绘getview了当前可见的部分,不可见的部分当你滑动到那个位置,重新调用getview方法。

至于源码观察者模式,还不太懂。。。

java基础
hashmap 单线程
hashtable 多线程 ,同步线程安全

stringbuffer 线程安全
stringbuilder 单线程

内存优化和内存泄漏

自定义布局控件:
onmeasure
onlayout
ondraw

自定义属性:

在实际的使用自定义Viewgroup时,经常会用到自定义控件的属性。在res/values文件夹下建立attr.xml文件1、书写xml文件,定义<attr>中的自定义属性,在<declare-stableable>中声明已经定义的属性
<resources><attr name="rightPadding" format="dimension"></attr>  //定义布局属性<declare-styleable name="SlidingMenu"> //定义布局,其中name后必须跟着view的类名<attr name="rightPadding"></attr>   //声明属性</declare-styleable>
</resources>

控件代码:

在使用自定义属性时,需要覆写ViewGroup中有2个参数的构造方法,然后通过含有2个参数的构造方法,调用含有3个参数的构造方法。含有3个参数的构造方法负责接收自定义属性。
public SlidingMenu(Context context, AttributeSet attrs, int defStyle)
{super(context, attrs, defStyle);TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.SlidingMenu, defStyle, 0);int n = a.getIndexCount();for (int i = 0; i < n; i++){int attr = a.getIndex(i);switch (attr){case R.styleable.SlidingMenu_rightPadding:mMenuRightPadding = a.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()));break;}} a.recycle();  //需要对TypeArray进行回收
}

layout.xml使用

使用自定义的属性,在使用时添加命名空间,xmlns:ren="http://schemas.android.com/apk/res/bupt.ren.slidingmenu",然后即可以使用该属性<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:ren="http://schemas.android.com/apk/res/bupt.ren.slidingmenu"android:layout_width="match_parent"android:layout_height="match_parent" ><bupt.ren.slidingmenu.view.SlidingMenuandroid:id="@+id/id_menu"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/img_frame_background"ren:rightPadding="80dp" ></bupt.ren.slidingmenu.view.SlidingMenu></RelativeLayout>

rxjava是什么东西。

android屏幕点击事件机制
ontounch—onclick

外部容器获取
—>是否拦截?
拦截了—>容器的touch事件
未拦截—>传递给button,button 有touch—click事件,消费结束。
http://www.cnblogs.com/tgyf/p/4821301.html
http://blog.csdn.net/guolin_blog/article/details/9097463/

点击事件的一般响应流程为
button控件点击click事件:下面是一个onClick被触发的基本时序的Log:04-05 05:57:47.123: DEBUG/TSActivity(209): onTouch ACTION_DOWN04-05 05:57:47.263: DEBUG/TSActivity(209): onTouch ACTION_UP04-05 05:57:47.323: DEBUG/TSActivity(209): onClick可以看出是按ACTION_DOWN -> ACTION_UP -> onClick的次序发生的。
button长按事件:04-05 06:00:04.133: DEBUG/TSActivity(248): onTouch ACTION_DOWN04-05 06:00:04.642: DEBUG/TSActivity(248): onLongClick 04-05 06:00:05.083: DEBUG/TSActivity(248): onTouch ACTION_UP可以看到,在保持按下的状态一定时间后会触发onLongClick,之后抬起手才会发生ACTION_UP。

问题来了?onclick和onlongclick可以同时执行?
答案可以,但是这是不符合常理 的。

要弄清楚这个问题只要理解Android对事件处理的所谓消费(consume)概念即可,一个用户的操作会被传递到不同的View控件和同一个控件的不同监听方法处理,任何一个接收并处理了该次事件的方法如果在处理完后返回了true,那么该次event就算被完全处理了,其他的View或者监听方法就不会再有机会处理该event了。onLongClick的发生是由单独的线程完成的,并且在ACTION_UP之前,而onClick的发生是在ACTION_UP后,因此同一次用户touch操作就有可能既发生onLongClick又发生onClick。这样是不是不可思议?所以及时向系统表示“我已经完全处理(消费)了用户的此次操作”,是很重要的事情。例如,我们如果在onLongClick()方法的最后return true,那么onClick事件就没有机会被触发了。下面的Log是在onLongClick()方法return false的情况下,一次触碰操作的基本时序:04-05 06:00:53.023: DEBUG/TSActivity(277): onTouch ACTION_DOWN04-05 06:00:53.533: DEBUG/TSActivity(277): onLongClick 04-05 06:00:55.603: DEBUG/TSActivity(277): onTouch ACTION_UP04-05 06:00:55.663: DEBUG/TSActivity(277): onClick可以看到,在ACTION_UP后仍然触发了onClick()方法。
和方法返回值true、false有关系!!!
true---拦截点击传递
false---不拦截点击传递

容器和子控件谁先获得点击事件???
顾名思义,ViewGroup就是一组View的集合,它包含很多的子View和子VewGroup,是android中所有布局的父类或间接父类,像LinearLayout、RelativeLayout等都是继承自ViewGroup的。但ViewGroup实际上也是一个View,只不过比起View,它多了可以包含子View和定义布局参数的功能。
可以看到,我们平时项目里经常用到的各种布局,全都属于ViewGroup的子类。

你会发现,当点击按钮的时候,MyLayout注册的onTouch方法并不会执行,只有点击空白区域的时候才会执行该方法。你可以先理解成Button的onClick方法将事件消费掉了,因此事件不会再继续向下传递。

    public class MyLayout extends LinearLayout {  public MyLayout(Context context, AttributeSet attrs) {  super(context, attrs);  }  @Override  public boolean onInterceptTouchEvent(MotionEvent ev) {  return true;  }  }  

你会发现,不管你点击哪里,永远都只会触发MyLayout的touch事件了,按钮的点击事件完全被屏蔽掉了!
当你点击了某个控件,首先会去调用该控件所在布局的dispatchTouchEvent方法,然后在布局的dispatchTouchEvent方法中找到被点击的相应控件,再去调用该控件的dispatchTouchEvent方法。如果我们点击了MyLayout中的按钮,会先去调用MyLayout的dispatchTouchEvent方法,可是你会发现MyLayout中并没有这个方法。那就再到它的父类LinearLayout中找一找,发现也没有这个方法。那只好继续再找LinearLayout的父类ViewGroup,你终于在ViewGroup中看到了这个方法,按钮的dispatchTouchEvent方法就是在这里调用的。

源码
public boolean dispatchTouchEvent(MotionEvent ev) {
if (disallowIntercept || !onInterceptTouchEvent(ev)) {
ev.setAction(MotionEvent.ACTION_DOWN);
final int scrolledXInt = (int) scrolledXFloat;
final int scrolledYInt = (int) scrolledYFloat;
final View[] children = mChildren;
final int count = mChildrenCount;
for (int i = count - 1; i >= 0; i–) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
|| child.getAnimation() != null) {
child.getHitRect(frame);
if (frame.contains(scrolledXInt, scrolledYInt)) {
final float xc = scrolledXFloat - child.mLeft;
final float yc = scrolledYFloat - child.mTop;
ev.setLocation(xc, yc);
child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
if (child.dispatchTouchEvent(ev)) {
mMotionTarget = child;
return true;
}
}
}
}
}
}
。。。
}
如果disallowIntercept和!onInterceptTouchEvent(ev)两者有一个为true,就会进入到这个条件判断中。disallowIntercept是指是否禁用掉事件拦截的功能,默认是false,也可以通过调用requestDisallowInterceptTouchEvent方法对这个值进行修改。那么当第一个值为false的时候就会完全依赖第二个值来决定是否可以进入到条件判断的内部,第二个值是什么呢?竟然就是对onInterceptTouchEvent方法的返回值取反!也就是说如果我们在onInterceptTouchEvent方法中返回false,就会让第二个值为true,从而进入到条件判断的内部,如果我们在onInterceptTouchEvent方法中返回true,就会让第二个值为false,从而跳出了这个条件判断。

1. Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。2. 在ViewGroup中先执行dispatchTouchEvent()方法,之后可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。3. 子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件。

从源码中可以看出,这两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。
另外需要注意的是,onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。
参考:
http://blog.csdn.net/guolin_blog/article/details/9153747
好了。

2017/6/16
IO流分类

类:
File
InputStream 子类 字节输入流
OutputStream 子类 字节输出流
Reader 子类 字符输入流
Writer子类 字符输出流
随机存取文件类
public class RandomAccessFile implements DataOutput, DataInput, Closeable {。。。}
IO流的分类

根据处理数据类型的不同分为:字符流和字节流
根据数据流向不同分为:输入流和输出流

字节流与字符流的区别

字节流和字符流使用是非常相似的,那么除了操作代码的不同之外,还有哪些不同呢?

字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的

字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

那开发中究竟用字节流好还是用字符流好呢?

在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。
http://blog.csdn.net/zxman660/article/details/7875799
程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。

选择:
字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点。
原因:
视频文件用字符流去复制时,是先将文件中的数据按照字节读取出来,再去查编码表将字节传化为字符,因为是音频文件所以字节的组成范围比较广,而编码表的字符是有限的,有的字节组成是在编码表里找不到的,这些在编码表里找不到的字节就会被丢弃掉,所以复制完的文件比源文件小。建议复制音频图片等文件用字节流。

如果要java程序实现一个拷贝功能,应该选用字节流进行操作(可能拷贝的是图片),并且采用边读边写的方式(节省内存)。

集合分类
hashtable hashmap
vector list

数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用。集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数情况下使用。

下图分类:

源码:
public interface Collection<E> extends Iterable<E> {。。。
}public interface Map<K, V> {。。。}

http://www.cnblogs.com/leeplogs/p/5891861.html
注意:
HashSet(),调用对象的hashCode()方法,获得哈希码,然后在集合中计算存放对象的位置。通过比较哈希码与equals()方法来判别是否重复。所以,重载了equals()方法同时也要重载hashCode()方法。

http协议
请求:

GET请求例子:
GET /search?hl=zh-CN&source=hp&q=domety&aq=f&oq= HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint,
application/msword, application/x-silverlight, application/x-shockwave-flash, */*
Referer: <a href="http://www.google.cn/">http://www.google.cn/</a>
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)
Host: <a href="http://www.google.cn">www.google.cn</a>
Connection: Keep-Alive
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g;
NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-
FxlRugatx63JLv7CWMD6UB_O_r地址中”?”之后的部分就是通过GET发送的请求数据,我们可以在地址栏中清楚的看到,各个数据之间用”&”符号隔开。显然,这种方式不适合传送私密数据。另外,由于不同的浏览器对地址的字符限制也有所不同,一般最多只能识别1024个字符,所以如果需要传送大量数据的时候,也不适合使用GET方式。post请求:
POST /search HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint,
application/msword, application/x-silverlight, application/x-shockwave-flash, */*
Referer: <a href="http://www.google.cn/">http://www.google.cn/</a>
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)
Host: <a href="http://www.google.cn">www.google.cn</a>
Connection: Keep-Alive
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g;
NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-
FxlRugatx63JLv7CWMD6UB_O_r  hl=zh-CN&source=hp&q=domety  对于上面提到的不适合使用GET方式的情况,可以考虑使用POST方式,因为使用POST方法可以允许客户端给服务器提供信息较多。POST方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现,可以传输大量数据,这样POST方式对传送的数据大小没有限制,而且也不会显示在URL中。可以看到,POST方式请求行中不包含数据字符串,这些数据保存在”请求内容”部分,各数据之间也是使用”&”符号隔开。POST方式大多用于页面的表单中。因为POST也能完成GET的功能,因此多数人在设计表单的时候一律都使用POST方式,其实这是一个误区。GET方式也有自己的特点和优势,我们应该根据不同的情况来选择是使用GET还是使用POST。响应:
HTTP/1.1 200 OK
Date: Sat, 31 Dec 2005 23:59:59 GMT
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 122<html>
<head>
<title>Wrox Homepage</title>
</head>
<body>
<!-- body goes here -->
</body>
</html>

详细参考:
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/28/2612910.html

equals()

package java.lang;
Object源码:public boolean equals(Object o) {return this == o;}1.值类型比较
针对基本数据类型,
int float double byte char boolean long short
这8个是不能调用equals()方法的!!!
int i=0;
//Cannot invoke equals(int) on the primitive type int提示报错   if (i.equals(i) {System.out.println("3----" + p3.equals(p3_2));}String类型
String s1=“1”;
String s2=“1”;
即内容相同,我们就认为是相等的。比如:int i=5;int j =5;此时我们说i和j相等,其实指的是i和j的内容相同。2.引用类型比较    但在Java中,除了值类型,另外还有一种引用类型,而不同的对象,其引用值其实并不相等,即在内存中的不同的地 址单元中。比如我们定义了学生类,分别有两个学生对象实例 :   Student stu= new Student();   Student stu1= new Student();此时我们无论是使用stu==stu1符号(死的,比较内存单元地址),或者stu.equals(stu1)方法,把两个对象进行比较,得到的结果都是不相等的,因为对于引用类型来说,默认是比较两个对象引用的地址,显示,每个对象的引用有自己唯一的地址,所以,是不相等。stu.equals(stu1)这个前提是student没有重写equals方法,比较内存单元地址!!!!有时,我们比较两个对象时,如果他们的内容一样,那么我们就认为这两个对象是相等的,如上面的两个学生对象。这时,我们该怎么办呢?其实,非常简单,只要在类里面重写equals()方法,进行对象里面的内容比较就可以了。如上面,我们只需要在Student类中重写equals()方法即可。public boolean equals(Object obj) {  if (this == obj)      //传入的对象就是它自己,如s.equals(s);肯定是相等的;  return true;   if (obj == null)     //如果传入的对象是空,肯定不相等  return false;  if (getClass() != obj.getClass())  //如果不是同一个类型的,如Studnet类和Animal类,  //也不用比较了,肯定是不相等的  return false;  Student other = (Student) obj;       if (name == null) {  if (other.name != null)  return false;  } else if (!name.equals(other.name)) { //如果name属性相等,则相等  return false;  }return true;  }  重写equals()方法后,得到s和s1相等。==对引用类型的只能进行地址比较,故还是不相等的。    

http://blog.csdn.net/bluesky_usc/article/details/51849125

hashcode()

identityHashCode是根据对象的地址计算得到的,所以任何两个不同的对象的
identityHashCode值总是不相等,这个是死的。不管该对象的类是否重写了hashCode()方法!!!!
2个不同的对象,identityHashCode一定不同,但是hashCode可能相同,一定重写了hashCode()方法。
hashCode()方法是Object类下面的一个方法,供继承类重写,根据对象内存地址计算哈希值,
String类重写了hashCode方法,并改为根据字符序列来计算哈希值
http://www.2cto.com/kf/201409/332998.html源码:public int hashCode() {int lockWord = shadow$_monitor_;final int lockWordStateMask = 0xC0000000;  // Top 2 bits.final int lockWordStateHash = 0x80000000;  // Top 2 bits are value 2 (kStateHash).final int lockWordHashMask = 0x0FFFFFFF;  // Low 28 bits.if ((lockWord & lockWordStateMask) == lockWordStateHash) {return lockWord & lockWordHashMask;}return System.identityHashCode(this);}hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。
hashCode 的常规协定是:
在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)   当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。   hashcode来定位实例的散列桶位置然后再通过 equals判断该桶里面的元素是否逻辑相等。

所以二者的用途一定要区分:equals是用来判断是否逻辑相等。hashCode是与hashset,hashtable,hashmap之类的数据结构使用时,用来快速定位散列桶。 

toString

源码:public String toString() {return getClass().getName() + '@' + Integer.toHexString(hashCode());}toString
public String toString()返回该对象的字符串表示。通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂。建议所有子类都重写此方法。
Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:
getClass().getName() + '@' + Integer.toHexString(hashCode())test2.Person@35ccd5bf

总结:

1、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;2、如果两个对象相同,就是适用于equals(Java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;3、如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;4、两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。5、我们写代码的时候,在封装实体类,比如Student、Teacher等类似model
,重写equals()方法,一定要重写hashcode,保证2个对象
equals相等,那么hashcode一定要相等,比如
HashSet的hashcode方法引起的内存泄漏问题
http://blog.csdn.net/shixing_11/article/details/5652935因为重写了Person 的
hashcode方法造成的,注释掉就没有问题了!!!
原因:
当hashset第一次add数据,hashset是基于hashmap实现的,hashmap主键就是person对象的hashcode值,第一次add,记录了主键,不可以再改变了。
由于重写了hashcode()计算方法,重新给对象set属性之后,对象的hashcode和之前的不同了(你重写的hashcode方法),导致hashset无法移除第一次添加的对象,因为这个时候map中找不到对应的主键。
此时如果调用
集合的remove(),contains()方法,将不会得到正确的结果。remove()方法并不能正确remove掉对应的元素,造成内存泄漏。总结:
HashSet中
在对应元素添加进set集合后,最好不要再去修改元素的值,否则对应元素的hashcode值发生变化,修改后无法正常移除;
或者,不重写hashcode方法,用object默认的方法,即使改变了对象属性值,hashcode也不会改变,默认使用内存单元的hashcode,这个可以看源码!!!!!

http://blog.csdn.net/fenglibing/article/details/8905007

hashmap机制:
http://blog.csdn.net/zx582727090/article/details/51099190

http://blog.csdn.net/bravejiezai/article/details/51725023

map输出:
http://www.2cto.com/kf/201506/404428.html
3中循环方式方式,都是用Iterator

keySet.iterator;
map.entrySet().iterator();
Collection c = map.values();
Iterator iterator = c.iterator();

2017/6/23

1、异步任务内部实现原理
AsyncTask的本质是一个线程池,所有提交的异步任务都会在这个线程池中的工作线程内执行,当工作线程需要跟UI线程交互时,工作线程会通过向在UI线程创建的Handler(原理见:《Handler+Looper+MessageQueue深入详解》)传递消息的方式,调用相关的回调函数,从而实现UI界面的更新。

http://blog.csdn.net/jwzhangjie/article/details/11644163
2、viewpager 和上部导航栏联动实现
PagerTabStrip与PagerTitleStrip添加标题栏
http://blog.csdn.net/harvic880925/article/details/38521865

当然,可以自定义导航栏~~~
viewpager滑动监听,做处理。。。

3、冒泡算法实现
冒泡
http://www.cnblogs.com/shen-hua/p/5422676.html

其他:
http://www.cnblogs.com/0201zcr/p/4763806.html
4、单例模式,写几种方式
http://blog.csdn.net/jason0539/article/details/23297037/
http://www.cnblogs.com/hupp/p/4487521.html
5、滑动、点击事件冲突处理
http://blog.csdn.net/spt110/article/details/7919870

2017/6/27
1、mvp mvc
mvp:
http://blog.csdn.net/knxw0001/article/details/39637273/
http://blog.csdn.net/u013347784/article/details/52620918
MVP模式(Model-View-Presenter)是MVC模式的一个衍生。主要目的是为了解耦,使项目易于维护。

Model 依然是业务逻辑和实体模型
View 经常由Activity实现,包含Presenter的引用。所要做的就是当有交互时,调用Presenter里的对应方法。
Presenter 负责完成View于Model间的交互,从Model里取数据,返回给View处理好的数据。

与MVC重大区别:在MVP中View并不直接使用Model,它们通信是通过Presenter来进行的,而MVC中View可以从Model中直接读取数据而不是Controller。

mvc
Model 是应用程序中用于处理应用程序数据逻辑的部分。
View 是应用程序中处理数据显示的部分。
Controller是应用程序中处理用户交互的部分。
从而使同一个程序可以使用不同的表现形式。
比如一批统计数据可以分别用柱状图、饼图来表示。
C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。

比较
MVP模式:
View不直接与Model交互 ,而是通过与Presenter交互来与Model间接交互
Presenter与View的交互是通过接口来进行的,更有利于添加单元测试
通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑

MVC模式:
View可以与Model直接交互
Controller是基于行为的,并且可以被多个View共享
可以负责决定显示哪个View

———–重点——————-
MVC缺点:
在MVC里,View可以直接访问Model,从而View里会包含Model信息,不可避免的还要包括一些业务逻辑。所以当交互比较复杂,view又比较多变的情况下,更改view比较困难,view中的业务逻辑是无法复用的。

与MVC重大区别:在MVP中View并不直接使用Model,它们通信是通过Presenter来进行的,而MVC中View会从Model中直接读取数据而不是Controller。

MVP优缺点:
Presenter把M和V完全分离开,交互逻辑都在Presenter里
实现,而且P与V没有直接关联,是通过定义好的接口进行交互,
从而使变更View时可以保持P不变,即重用!该模式下
开发起来结构清晰易懂,耦合度低,但是代码量文件数量会变大。

举例:
在MVC模式下,Activity给人的感觉是View + Controller,
有view还有交互逻辑,因此一个Activity有可能会变得很庞大!!!!!!!!!!!

但是在MVP模式下,Activity约等于View这一层,然后有
专门的Presenter来负责交互逻辑,大体可以这样理解吧。

2、baseactivity写一些什么东西
http://www.cnblogs.com/wangfeng520/p/6228164.html
http://blog.csdn.net/black_dreamer/article/details/69666961
比如:BaseActivity的生命周期,
点击事件,
异常控制,
控件初始化,
网络初始化,
请求回调从开始到结束需要显示的动画公用之类的可以抽象,
很多要findviewbyid也可以抽象

调试 log

toast

一般的Activity里都会用到很多的findViewById这个方法,
而且每次都要强制类型转换,这样会显得很繁琐,如果在BaseActivity里封装好,就能省事:protected <T extends View> T findView(int id) {return (T) findViewById(id);
}这样只要是继承了BaseActivity就能轻松使用LinearLayout llContent = findView(R.id.ll_content);,免去了诸多类型转换的麻烦。

视图相关
用户模块(业务相关【可选】)
界面间跳转传参
调试和吐司
软键盘
防止快速点击
是否允许全屏
设置沉浸式状态栏 旋转屏幕

fragment间相互通信方法
http://www.jianshu.com/p/d774e4b25240

1、通过宿主activity,getActivity()强转直接调用方法

2、接口回调

3、安卓的广播机制来实现的

4.EventBus
EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,
线程之间传递消息.优点是开销小,代码更优雅。以及将发送者
和接收者解耦。

概念:EventBus是一个Android端优化的publish/subscribe
消息总线,简化了应用程序内各组件间、组件与后台线程间的通信。
比如请求网络,等网络返回时通过Handler或Broadcast通知UI,
两个Fragment之间需要通过Listener通信,
这些需求都可以通过EventBus实现。

EventBus比较适合仅仅当做组件间的通讯工具使用,
主要用来传递消息。
使用EventBus可以避免搞出一大推的interface

概念:”a library for composing asynchronous and event-based programs using observable sequences for the Java VM”
(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库),
简单的用中文概括也就是两个字:异步。
RxJava 的优势即是简洁,但它的简洁的与众不同之处在于,
随着程序逻辑变得越来越复杂,它依然能够保持简洁。

简单来讲:
使用RxJava,
你可以使用subscribeOn()指定被观察者代码运行的线程(后台耗时操作的东西…..thread),
使用observerOn()指定订阅者运行的线程,通常主线程

myObservableServices.retrieveImage(url).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(bitmap -> myImageView.setImageBitmap(bitmap));

上述代码表示,在Subscriber前面执行的代码都是在I/O线程中运行。
最后,操作view的代码在主线程中运行.

PS:AndroidSchedulers.mainThread()是在Android中才有.

Rxjava内置了几个 Scheduler:

Schedulers.immediate() 默认的,直接在当前线程运行。
Schedulers.newThread() 启用新线程,在新线程工作。
Schedulers.io() I/O操作(读写文件,读写数据库,网络信息交互等)、和newThread()最大的区别是:io()内部实现是一个无数量上限的线程池,可以重用空闲的线程。
Schedulers.computation():计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
AndroidSchedulers.mainThread() Android专用的,指定的操作在Android的主线程运行。

Rxjava常用的操作符

create
create操作符是所有创建型操作符的“根”,也就是说其他创建型操作符最后都是通过create操作符来创建Observable的.
from
from操作符是把其他类型的对象和数据类型转化成Observable,接收一个集合作为输入。
just
just操作符也是把其他类型的对象和数据类型转化成Observable,它和from操作符很像,只是方法的参数有所差别。接收一个可变参数作为输入。
defer
defer操作符是直到有订阅者订阅时,才通过Observable的工厂方法创建Observable并执行,defer操作符能够保证Observable的状态是最新的
timer
隔一段时间产生一个数字,然后就结束,也就是延迟时间接受到数据。timer操作符默认情况下是运行在一个新线程上的,当然你可以通过传入参数来修改其运行的线程。
interval
interval操作符是每隔一段时间就产生一个数字,这些数字从0开始,一次递增1直至无穷大。
range
range操作符是创建一组在从n开始,个数为m的连续数字,比如range(3,10),就是创建3、4、5…12的一组数字
map
map函数只有一个参数,参数一般是Func1,Func1的

综合来看rxjava,也就是以下四点:
作用 - 异步
模式 - 观察者模式
结构 - 响应式编程
优势 - 逻辑简洁

Rxjava和eventbus使用对比:
如果一个订阅者需要注册多个事件的时候,
Rxjava需要一个个单独的注册,而EventBus则可以
实现一个订阅者订阅多个事件,和一个事件对应多个订阅者。
所以在Rxjava的基础上有了Rxbus来作为事件总线的库。
这里不做Rxbus的解释。

面试android开发工程师小结相关推荐

  1. 面试Android开发工程师 3年工作经验 自我介绍

    非常荣幸能参加这次面试,我叫隋睿,来自宁夏,是16级计算机专业的本科生. 毕业四年一共任职过两家公司,接手的公司项目有5个. 第一个项目是:<**乐>App,是一个活动社交平台. 该项目中 ...

  2. Android 开发工程师面试指南

    原文链接:https://github.com/GeniusVJR/LearningNotes <Android 开发工程师面试指南 LearningNotes >,作者是知乎Androi ...

  3. Android开发工程师面试指南

     Android开发工程师面试指南 功能介绍     给Android开发工程师的一份面试指南,包含面试题集与简历模板. 面试题集 面试题集里的答案大部分来源于我的博客,因此这个题集也相当于是我的博客 ...

  4. 《Android 开发工程师面试指南》

    <Android 开发工程师面试指南> <Android 开发工程师面试指南 LearningNotes >,作者是知乎Android开发工程师陶程,由梁观全贡献部分.大家可以 ...

  5. android用户界面组件都是放置在,Android开发工程师第十章 节 用户界面高级组件.ppt...

    Android开发工程师第十章 节 用户界面高级组件.ppt 电子相册的设计与实现 4.图片放大与缩小显示的实现 在触摸ImageSwitcher中显示的图片后,全屏显示该图片,要全屏显示该图片,只要 ...

  6. 途牛android源码,途牛,Android 开发工程师,一面,攒人品

    途牛,Android 开发工程师,一面 时间:33min 约的是微信视频 面试官态度非常好,比较年轻 很帅~~~ 昨天面的,没时间写,今天补上吧 首先:自我介绍 应用上线细节(说要搜我上线的应用) r ...

  7. 一个高薪的Android开发工程师需要具备什么能力?

    前言 任何工作,任何行业想要拿到高薪都需要这几点条件,时间,技术,关系. 时间,无非就是在这个行业摸爬滚打很久有自己一套赚钱的方法: 关系,说白了就是家中有人帮忙铺路: 技术,在一个行业技术专精就能受 ...

  8. 如何成为android开发工程师,android开发工程师薪资 如何成为一名合格的android开发工程师?...

    行业薪酬的影响因素包括行业内.外部因素及员工个人的因素,同样,在IT行业中,要想了解android开发工程师的薪资待遇情况如何,我们也可以从这几个因素入手,加以了解.android开发工程师薪资,如何 ...

  9. 2012年全国最新Android开发工程师薪资水平调查分析

    为什么80%的码农都做不了架构师?>>>    2012年全国最新Android开发工程师薪资水平调查分析 最近几年,随着Android的飞速发展,伴随着巨大的产业需求,国内Andr ...

最新文章

  1. systemback-----做你折腾的后盾
  2. selenium 基于浏览器驱动测试
  3. OLAP引擎:基于Druid组件进行数据统计分析
  4. chstr php,PHPWind与Discuz截取字符函数substrs与cutstr性能比较
  5. php中%3c w() %3e,DedeCMS V5.7 SP2后台存在代码执行漏洞
  6. 适合android平板的浏览器,推荐5款安卓平板Pad版应用浏览器
  7. android屏幕截图代码,android中实现整个屏幕截图的代码
  8. 中文乱码解决办法(java)
  9. cad画直角命令_CAD直线怎么画?直线命令快捷键是什么
  10. 智能家居Series
  11. TMS570快速上手指南(0)--概述
  12. Windows资源管理器未响应解决方案
  13. [从头读历史] 第241节 根据天时定历法
  14. java.lang.RuntimeException: A TaskDescription‘s primary color should be opaque
  15. 微信商户平台结算周期T+1是什么意思
  16. 程序减肥,strip,eu-strip 及其符号表
  17. ARM及ZigBee技术实现智能家居控制器的设计
  18. 被网红时代毁掉的“小马云”
  19. 2023年英文科技论文写作与学术报告-期末考试
  20. iphone如何最快已读全量未读短信

热门文章

  1. 小程序之 一个方法中的值怎么传递到另一个方法中
  2. C++ 时间函数整理详解
  3. apt安装特定版本软件
  4. miui修改Android,无法修改小米MIUI设备中的系统设置
  5. 软件测试周刊(第36期):为什么你要当程序员?
  6. 解决电脑无法进入休眠/睡眠状态,而仅关闭屏幕的问题
  7. 基于AOP的优惠券发送异常哨兵监控
  8. 神经网络neural network
  9. 基于MATLAB的图像压缩感知 算法的实现
  10. 实测!Ubuntu18.04解决Teamview检测为商用问题