SanfenR的博客


  • 首页

  • 关于

  • 归档

  • 搜索
close
SanfenR的博客

Vim-command

发表于 2016-11-05 |

光标移动

命令 作用
h,j,k,l 左 下 右 上
Ctrl+f 上一页
Ctrl+b 下一页
w,e,W,E 调到单词后面,小写包括标点
O 开启新的一行
^ 一行的开始
gg 文档的结尾
[N]G 文档的第N行或者最后一行

插入模式

命令 作用
i 插入到光标前面
I 插入到行的开始位置
a 插入到光标的后面
A 插入到行的最后位置
o,O 新开一行
Esc 关闭插入模式

编辑

命令 作用
r 在插入模式替换光标所在的一个字符
J 合并下一行到上一行
s 删除光标所在的一个字符,光标还在当行
S 删除光标所在的一行, 光标还在当行,不同于dd
u 撤销上一步操作
ctrl+r 恢复上一步操作
. 重复最后一个命令
~ 变换为大写
[N]>> 一行或N行往右移动一个tab
[N]<< 一行或N行往左移动一个tab

关闭

命令 作用
:q 保存
:wq, :x 保存并关闭
:q 关闭
:q! 强制关闭

搜索

命令 作用
/pattern 搜索(非插入模式)
?pattern 向后搜索
n 光标到达搜索结果的前一个目标
N 光标到达搜索结果的后一个目标

视觉模式

命令 模式
v 选中一个或多个字符
V 选中一行

剪切和复制

命令 作用
dd 删除一行
dw 删除一个单词
x 删除后一个字符
X 删除前一个字符
D 删除一行最后一个字符
[N]yy 复制一行或者N行
yw 复制一个单词
p 粘贴

窗口命令

命令 作用
: split 水平分割出一个窗口
:vsplit 垂直分割出一个窗口
:close 关闭窗口
ctrl+w 切换窗口 h,j,k,l 左下上右
SanfenR的博客

字符串剔除(day5)

发表于 2016-10-24 |

题目

  • 输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.”。

思路

最简单的。设source长n,key长m(n>>m),则使用简单的遍历查找需要n*m次(n个字符,查找m次),且每次删除对应元素需要O(1)时间(元素移动)。时间复杂度为O(n.^2);

以下思路。查找时间复杂度为O(n),删除时间复杂度为O(n)。即O(n)的时间内完成。

  1. 建立长度为256(char元素总数)的hash数组(类似基排序),遍历key。即需要在source中删除的字符在hashtable上不为0。复杂度O(m)。
  2. 设定指针 temp和needDelete,初始化指向source.
  3. temp用来遍历source,任何时候指向不需要删除的字符。needDelete指向当前需要删除的第一个字符。
  4. 使用间接删除法。即将temp的值赋给source。
  5. 任何一轮循环。needDelete–temp-1的字符都可以被删除(即替代)。temp之前不需要删除的字符,都已经挪到needDelete之前。
  6. 以temp为空位结束条件。最后给needDelete赋空。

整体思路,从第一个删除的位置开始,依次把后面不需要删除的字符向前赋值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
char *deleteStr(char *source, const char *key) {
if (!source || !key)
return NULL;
const char *temp = key;
//static int hashTable[256];
int *hashTable = new int[256];
memset(hashTable, 0, 256 * sizeof(int));
while (*temp)
hashTable[*temp++]++;
temp = source;
char *needDelete = source;
while (*temp) {
if (!hashTable[*temp]) {//不需要删除的字符,前移赋值
*needDelete = *temp;
needDelete++;
}
temp++;
}
*needDelete = '\0';
delete[]hashTable;
return source;
}

源码github

SanfenR的博客

Android面试题整理

发表于 2016-10-22 |

Java

  1. GC是什么?为什么要有GC?

    GC是垃圾收集的意思(Garbage Collection), 内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动的检测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。

  2. XML包括哪些解析技术,区别是什么?

    DOM和SAX DOM将文档解析成一颗文档树,可在节点上进行遍历、增加、修改和删除。一次性读入内存,对内存消耗大。 SAX至上而下解析文档,以事件进行驱动。不会一次性读入内存,对内存消耗小,不能任意读取节点,并且不能对节点进行增加、修改和删除。

  3. switch语句能否作用在byte上,能否作用在long上,能否作用在String上?

    switch 能作用在byte, short. char,int, 在JDK1.7以后可以作用在String上。

  4. “==”和equals方法究竟有什么区别?

    ==和equals都可以比较地址, ==是运算符,equals是方法,方法可以通过重写改变其行为,如String的equals就是比较字符串内容。

  5. 构造方法能否被重写和重载?

    不能被重写,但能被重载。

  6. 面向对象的特征有哪些?

    封装,继承,多态,抽象

  7. 抽象类和接口的区别?

    1. 抽象类是abstract class 修饰符,接口是interface修饰符。
    2. 抽象类可以有任意属性, 接口只能有静态常量修饰的属性。
    3. 抽象类可以有普通方法和抽象方法,接口只能有抽象方法。
    4. 抽象类和接口都不能实例化,但是抽象类有构造方法,接口没有。5. 抽象类只能单继承,接口可以多继承。
  8. 内部类可以引用它的包含类的成员吗?有没有什么限制?

    可以引用, 如果需要制定当前类时要用到外部类.this。如果引用局部变量,需要将局部变量指定为final。

  9. String s = new String(“xyz”);创建了几个String Object? 二者之间有什么区别?

    创建了2个对象, “xyz” 创建在常量池中, new String() 创建在堆中

  10. try {}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?

    会执行,在return之前

  11. Integer与int的区别

    Integer为包装类, int 是基本数据类型。包装类拥有方法和属性,基本数据类型不具备。包装类可以通过intValue来转换基本数据类型,也可以通过new Integer()将基本数据类型转换为包装类。在JDK1.5后,包装类和基本数据类型可以实现自动转换。

  12. sleep()和wait()有什么区别?

    sleep是Thread类的方法,wait是Object类的方法。
    sleep是自动唤醒,wait需要其他线程来唤醒。
    sleep不会释放同步锁,wait会释放同步锁。
    sleep可以用在任意方法中,wait只能在同步方法或同步块中。
    sleep()不会释放对象锁到时自动恢复,wait()会释放对象锁进入等待此对象的锁定池发出notify()方法后才进入锁定池。

  13. 同步和异步有何异同,在什么情况下分别使用他们?

    同步指同一时间只能一个线程执行该方法,其他线程需要等待。异步指多个线程可以同时执行某个方法,并共享同一资源。
    同步可以让访问的资源具有安全性,同一时间只能一个线程对其访问。但效率不高。异步对访问的资源会造成不稳定性,比如多个线程同时访问一个资源,一个在修改,一个在删除,一个在读取,这样可能会造成资源的混乱。但是效率提高。

  14. 启动一个线程是用run()还是start()?

    statr()启动线程, run()方法是线程执行的主方法。

  15. java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?

    java中有三种流,分别是字节流(InputStream, OutputStream), 字符流(Reader,Writer), 对象流(ObjectInputStream, ObjectOutputStream)

  16. 字节流和字符流的区别?

    字节流用于读取或写出二进制数据,比如图片,影响等数据。
    字符流用于读取或写出字符数据,比如传输字符串。
    所有的数据都可以通过字节流来处理,如果是字符数据,用字节流还需要进行转换后传输,如果使用字符流可以方便数据的转换。

  17. error和exception有什么区别?

    error 是系统错误,代码不能处理的错误,比如内存溢出,堆栈溢出等。
    exception是程序异常,可以通过try-cache进行处理,如空指针,数组越界等。

  18. 谈谈final,fianlly, finalize的区别?

    final 是修饰符,可以修饰类(不能被继承),属性(常量)和方法(不能被重写)
    finally是异常处理块的代码块,表示无论如何都会执行的代码块。
    finalize是Object类方法,该方法在对象被垃圾回收之前执行的方法。

  19. 当一个线程进入一个对象的synchronized方法后,其他线程是否可以进入此方法的其他方法?

    如果其他方法没有设置synchronized是可以进入的。

  20. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

    java中只有值传递,如果传递的对象,实际也是传递该对象的地址。

  21. 作用域public,private,protected,以及不写时的区别

    public公共修饰符,所有的类都可以访问
    protected为受保护的修饰符,表示同类、同包以及不同包但是父子关系的是可以访问。
    不写表示默认修饰符,或者称为package修饰符,该修饰符表示只有同类huo或同包下的类可以访问,出了这个包就不能访问。
    private为私有修饰符,表示只有在同类中可以访问,chu’l出了这个类就不能访问。

  22. 用最有效率的方法算出2*8

    将2左移3位, 2 << 3

  23. heap和stack有什么区别。

    heap表示堆, stack表示栈, 堆中存放对象,栈中存放引用变量
    堆是无序的空间, 栈是先进后出的结构。

  24. 运行时异常与一般异常有何异

    运行时异常指继承于RuntimeException的异常,这些异常在编译时可以不进行处理,当运行时如果出现问题才会抛出。如NullPointException, ArrayIndexOutBoundsExceptions
    一般异常也称为编译时异常,这些异常是继承Exception但又不属于RuntiomException的子类,如果程序出现这些异常,在编译时必须进行捕获或抛出,否则编译无法通过,如IOException, FileNotException

  25. 垃圾回收的优点和原理。并考虑2中回收机制。

    Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存 管理。由于有个垃圾回收机制,Java中的对象不再有”作用域”的概念,只有对象的引用才有”作用域”。垃圾回收可以有效的防止内存泄露,有效的使用可以使用 的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能 实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。

  26. 描述一下JVM加载class原理机制?

    JVM中类的装载是由ClassLoader和他的子类来实现的,Java ClassLoader是一个重要的Java运行时系统组件。他负责在运行时查找和装入类文件的类。

  27. 是否可以从一个static方法内部发出非static方法的调用?

    不能,除非先创建非static方法所在类的对象。

  28. 什么是java序列化,如何实现java序列化?

    序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序 列化是为了解决在对对象流进行读写操作时所引发的问题。
    序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化 的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的 writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

  29. Anonymous Inner Class(匿名内部类)是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?

    匿名内部类可以继承类或实现接口,但不是显示的使用extends或implements来继承或实现。

  30. ArrayList和Vector的区别,HashMap和Hashtable的区别?

    ArrayList是JDK1.2的集合类型线程不安全,Vector是1.0的集合并且线程安全,二者用法相似。
    HashMap线程不安全且能放空键或空值,HashTable线程安全且不能放空键或空值。

  31. String 和StringBuffer有什么差别?在什么情况下使用它们?

    String 是字符串的基本类,该字符串是不可变的。StringBuffer是利用堆来存储字符串,并且可以对字符串的内容进行改变。

  32. new一个类对象和使用类名创建一个对象有什么区别?二者使用时应该注意什么?

    new对象是最常见的创建对象的方式。利用模板通过反射来创建对象。虽然new对象时在底层也会通过类模板来创建对象,但是new对象的效率要比直接通过类模板创建对象的方式要高。但是使用类模板的方式可以让程序的灵活性提高。

  33. LinkedList和ArrayList的区别?

    LinkedList是链表结构的集合,ArrayList是数组结构的集合。
    LinkedList在中间或前面增加或删除数据时效率要比ArrayList高。
    LinkedList在最后添加或删除数据时比ArrayList低
    遍历数据时ArrayList效率高于LinkedList

  34. 介绍JAVA开发中常用的Collection FrameWork(集合框架)?

    Java中集合框架分为Collection和Map接口,Collection接口下的集合每个元素都是由一个值组成,Map接口下的集合类每个元素都是由键值对组成。
    Collection接口下面有List和Set接口,List接口下常见的类有ArrayList, LinkerList,Vector。 他们中的元素可以重复,并且是有序的。Set接口常见的类HashSet, TreeSet。他们中的元素不能重复,并且是无序的。

  35. 在异常当中 throw和throws 有什么区别和联系?

    throw是在代码中抛出一个异常,后面跟的是异常对象,虚拟机运行到这里时会立即引发一个异常。
    throws是写在方法声明上的,表示声明该方法可能会抛出异常,后面跟的是异常类型。调用该方法的时候可以选择处理它或继续往外抛。

  36. 重载和重写的区别

    重载是指一个类中,两个或两个以上的方法具有相同的方法名和不同的参数列表,则表示这些方法为重载方法。
    重写是指父类和子类中,子类方法和父类方法具有相同的方法名,相同参数,相同返回类型,子类的访问修饰符范围不小于父类的访问修饰符范围,异常的类型个个数不大于或多于父类的异常类型和个数,则表示该方法为重写方法。换句话说重载方法是区分同一个类中相同方法名的方法,重写方法是找到父类相同方法名的方法并重写改变方法的行为。

  37. Java中try catch finally的执行顺序

    try -> 发生异常执行catch -> 最后一定会执行finall

  38. 内存泄露的原因:

    1. 资源对象没关闭。 如Cursor, File等资源。他们会在finalize中关闭,但这样效率太低。容易造成内存泄露。SQLiteCursor,当数据量大的时候容易泄露。
    2. 使用Adapetr时, 没有使用系统缓存的converView.
    3. 即时调用recycle()释放不再使用的Bitmap。 适当降低Bitmap的采样率,如:
      1
      2
      3
      4
      5
      BitmapFactory.Option option = new BitmapFactory.Options();
      options.inSampleSize = 2;
      //图片宽高都为原来的二分之一,即图片为原来的四分之一。
      Bimap bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri), null, options);
      preview.setImageBitmap(bitmap);
    1. 使用application的context来代替activity相关的context。
    2. 注册没取消造成内存泄露。 如:广播 集合中的对象没清理造成的内存泄露我们通常把一些对象的引用加入到了集合中,当我们不需要gai该对象时,并没有把它的应用从集合中清理掉,这样这个集合就会越来越大。如果这个集合static的话,那情况就更加严重。
    3. Handle应当声明为静态对象,并在内部类中保存一个对外部类的弱引用。如:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      static class MyHandler extends Handler {
      WeakRefrence<Activity> mActivityRefrence;
      MyHandler(Activity activity) {
      mActivityRefrence = new WeakRefrence<Activity>(activity);
      }
      @Override
      public void handlerMessage(Message msg) {
      final Activity activity = mActivityRefrence.get();
      if(activity != null){
      mImageView.setImageBitmap((Bitmap)(msg.getObj1()));
      }
      }
      }
  39. Iterator和Enumeration的不同

    • 函数接口不同
      Enumeration只有2个函数接口。通过Enumeration,我盟只能读取集合的数据,而不能对数据进行修改。Iterator只有3个函数接口。Iterator除了能读取集合的数据之外,也能数据进行删除操作。
    • Iterator支持fail-fast机制,而Enumeration不支持。 Enumeration 是JDK 1.0添加的接口。使用到它的函数包括Vector、Hashtable等类,这些类 都是JDK 1.0中加入的,Enumeration存在的目的就是为它们提供遍历接口。Enumeration本身并没有支持同步,而在Vector、Hashtable实现 Enumeration时,添加了同步。而Iterator 是JDK 1.2才添加的接口,它也是为了HashMap、ArrayList等集合提供遍历接口。
      Iterator是支持fail-fast 机制的:当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。
      ail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线 程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异 常,产生fail-fast事件。
  40. 接口的注意点

    1. 接口的字段全部默认为public static 类型。
    2. 接口中的方法全部默认为public类型。
    3. 接口中可以声明内部类,而默认为public static,正因为是static,只是命名空间属于接口,代码逻辑不属于接口。所有不违反接口定义。
    4. 接口本省可以声明为pullic 或者缺省。
    5. 抽象类继承某接口。如果在抽象类中实习了父类(接口)中的方法,在其子类可以不用实现,否则在子类必须实现。
  41. final方法

    将方法声明为final那有两个原因,第一就是说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。第二就是允许编译器将所有对此方法的调用转化为inline调用的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。

Android

  1. Activity, Service, BroadcastReceiver的作用

    • Activity: Activity 是Android程序与用户交互接窗口,是Android构造块中最基本的一种,他需要为保持各界面的状态,做很多持久化的事情,妥善管理生命周期以及一些跳转逻辑。
    • Service: 后台服务于Activity, 封装有一个完整的功能逻辑实现,接受上层命令,完成相关的指令,定义好需要接受Intent提供同步和异步的接口
    • BroadcastReceiver: 接受一种或者多种Intent做触发事件,接受相关消息,做一些简单处理,转换成一条Notification,统一了Android的事件广播模型。
  2. Activity 生命周期

    onCreate(), onStart(), onResume(), onPause(), onReStart(), onStop(), onDestory()

  3. 显示Intent和隐式Intent的区别是什么?

    Intent定义: Intent是一种在不同组件之间传递的请求消息,是程序发出的请求和意图,作为一个完整的消息传递机制,Intent不仅需要发送端,还需要接收端。
    显示Intent定义: 对明确指出了目标组件名称Intent,我们称之为显示Intent。
    隐式Intent定义: 对于没有明确指出目标组件名称Intent,则称之为隐式Intent.
    说明: Android系统使用IntentFilter 来寻找与隐式Intent相关的对象。

  4. Android 线程同步的方法

    线程同步的方法可以采用同步方法和同步块。

  5. 怎么讲一个Activity封装成对话框的样子?怎样将Activity封装成按Menu菜单的样子。

    简单你只需要设置一下Activity的主题在Android Manifest.xml中定义Activity的地方一句话:

    1
    2
    3
    4
    //设置为DialogActivity
    android:theme="@android:style/Theme.Dialog"
    //设置背景为半透明
    android:theme="@android:style/Theme.Translucent"

    重写OnCreateOptionMenu方法来处理按下menu后的行为,然后再该方法中弹出对话框形式的Activity.
    也可以利用时间监听来监听menu按键,并在该按钮按下后弹出对话框形式的Activity.

  6. 介绍Android体系结构

    Android分为4层
    应用层: Android的应用程序与的用户交互界面。
    应用框架层: UI组件, 管理器, 工具类。
    函数库层:系统C库,媒体库,Webkit, SQLite等。
    Linux核心库: linux系统运行的组件。

  7. 描述下横竖屏切换时候 activity 的生命周期

    1
    2
    3
    4
    5
    6
    //不设置, 切屏会重新调用生命周期,横屏时会执行一次,切竖屏会执行两次。
    android:configChanges
    //切屏还是会重新调用各个生命周期,切横,竖屏时只会执行一次。
    android:configChanges="orientation"
    //切屏不会重新调用各个生命周期,只会执行onConfiguraationChanged方法
    android:configChanges="orientation|keyboardHidden"
  8. android 中的动画有哪几种,它们的特点和区别是什么 ?

    帧动画(Frame)和补间动画(Tween),
    Tween动画,这种实现方式可以是试图组件移动,放大,缩小以及产生透明度的变化;
    另一种Frame动画,传统的动画方法,通过顺序的播放排列好的图片实现,类似电影。

  9. 一条短信多少个byte?

    140byte, 70个汉字

  10. handle机制

    Handle的作用,发送消息到消息队列,接受Looper传递的消息。
    主线程启动时会调用Looper.prepare()方法,初始化一个Looper,放入TreadLocal中,接着调用Looper.loop()不断遍历Message Queue. Handler的创建依赖与当期线程中的Looper,如果当前线程没有Looper则必须调用Looper.perpare()。
    Handler的创建依赖与当前线程中的Looper,如果当前线程没有Looper则必须调用Looper.prepare()。Handler , sendMessage到MessageQueue,Looper不断
    从MessageQueue中取出消息,回调handleMessage方法。

  11. 如何将SQLite数据库(dictionary.db文件)与apk文件一起发布 ?

    可以将dictionary.db文件复制到Eclipse Android工程中的res\raw目录中。所有在res\raw目录中的文件不会被压缩,这样可以直接提取该目录中的文件。使用openDatabase方法来打开数据库文件,如果该文件不存在,系统会自动创建/sdcard/dictionary目录,并将res\raw目录中的 dictionary.db文件复制到/sdcard/dictionary目录中

  12. 说说 android 中 mvc 的具体体现

    mvc 是model,view,controller的缩写

    • 模型(model)对象:是应用程序的主体部分,所有的业务逻辑都应该写在该层。
    • 视图(view)对象:是应用程序中负责生成用户界面的部分。也是在整个mvc架构中用户唯一可以看到的一层,接收用户的输入,显示处理结果。
    • 控制器(control)对象:是根据用户的输入,控制用户界面数据显示及更新model对象状态的部分,控制器更重要的一种导航功能,响应用户出发的相关事件,交给m层处理。
      Android鼓励弱耦合和组件的重用,在android中mvc的具体体现如下:
    1. view: 一般采用xml文件进行界面的描述。
    2. controller: Android的控制层通常落在Activity中。
    3. model: 数据库操作,网络请求都应该在model中处理。
  13. 请介绍下 Android 中常用的五种布局

    1. FrameLayout
    2. RelativeLayout
    3. LinearLayout
    4. TableLayout
    5. AbsoluteLayout
  14. 如何启用 Service ,如何停用 Service

    1. StartService() 启动服务, StopService();
    2. bindService, unBindService
  15. 如何优化ListView

    1. contentView的复用
    2. 如果item过多时,考虑分页加载
  16. 描述4种 activity 的启动模式

    1. standard: 系统的默认模式, 一次跳转即会生成一个新的实例
      2,singTop: 如果要启动的Activity已经在回退栈的顶部时, 不会生成新的实例。
    2. singTask: 如果要启动的Activity在回退栈中的时候,此Activity之上的所有Activity释放,直到栈顶是要启动的Activity.
    3. singInstance: 启动Activity时同时创建一个新的栈并在新栈中创建这个Activity实例。
  17. 什么是Intent,如何使用?

    Android设计理念是鼓励减少组件之间的耦合,因此Android提供了Intent(意图), Intent提供一种通用的消息系统,他允许在你的应用程序与其他的应用程序间传递Intent来执行动作和产生事件。使用Intent可以激活Android应用的三个核心组件: 活动,服务和广播接受器。通过startActivity() or startActivityForResult()启动一个Activity;
    startService()启动一个服务,或者通过bindService()
    广播(sendBroadcast(), sendOrderedBroadcast(), sendStickyBroadcast())发给broadcastReceivers

  18. Android用的数据库是什么样的?它和Sql有什么区别?为什么要用ContentProvide? 它和SQL的实现有什么差别?

    android用的是SQLite数据库。它和其他网络数据库类似,也是通过SQL对数据进行管理。SQLite的操作非常简单,包括数据类型在建表时也可以不指定。
    使用ContentProvider 可以将数据共享给其他应用,让除本应用之外的应用也可以访问本应用的数据。它的底层是用SQLite 数据库实现的,所以其对数据做的各种操作都是以Sql实现,只是在上层提供的是Uri。

  19. 通过Intent传递一些二进制数据的方法有哪些?

    1. Serializable序列化
    2. Parcelable接口,Android的部分类比如Bitmap类就已经实现,同时Parcelable在Android AIDL中交换数据也很常见。
  20. 对一些资源以及状态的操作保存,最好是保存在生命周期的哪个函数中进行?

    onResume()中恢复数据, onPause()保存数据。

  21. 如何一次性退出所有打开的Activity

    编写一个Activity作为入口,当需要关闭程序时,可以利用Activity的singTask模式跳转该Activity,它上面所有的Activity都会被销毁,
    或者在Intent设置Flag

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //A B C D ----> D start B -----> A B
    Intent intent = new Intent(this, B.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
    startActivity(intent);
    //A B C D ----> D start B ------> A C D B
    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    startActivity(intent);
  22. Service生命周期?

    启动Service的方式有两种,各自的生命周期也有不同。

    • 通过statrService启动Service: onCreate, onStartCommand, onDestory
    • 通过bindServcie启动Service: onCreate, onBind, onUnBind, onDestory
  23. 什么是AIDL?AIDL是如何工作的?

    AIDL(Android Interface definition language), 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的,如果需要在一个Activity中,访问另一个Service中的某个对象,需要先将对象转化成AIDL可识别的参数(可能是多个参数),然后使用AIDL来传递这些参数,在消息的接受端,使用这些参数组装成浙江需要的对象, AIDL是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值。

  24. Android如何把文件存放在SDCard上?

    在AndroidManifest.xml中添加权限

    1
    2
    3
    4
    <!- 在SDCard中创建与删除文件权限 ->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <!- 往SDCard中写入的权限 ->
    <uses-permission Android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    要往SDCard存放文件,程序必须先判断手机是否装有SDCard,并且可以进行读写。
    注意:访问SDCard必须在AndroidManifest.xml中加入访问SDCard的权限。
    Environment.getExternalStorageState()方法用于获取SDCard的状态,如果手机装有SDCard,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED。
    Environment.getExternalStorageDirectory()方法用于获取SDCard的目录。

  25. 注册广播有几种方式,这些方式有何优缺点?

    两种。 一种是通过代码注册,这种方式注册的广播会跟随程序的生命周期。第二是在AndroidManifest.xml中注册,这种常驻型广播当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

  26. 什么是ANR 如何避免它?

    在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR)对话框。用户可以选择让程序继续运行,但是他们在使用你的应用程序并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。要避免它,应该尽量少在主线程做耗时太长的操作,应该将这些操作放在线程当中去做。

  27. Android本身的api并未声明会抛出异常,则其在运行时有无可能抛出runtime异常,你遇到过吗?诺有的话会导致什么问题?如何解决?

    有可能,比如空指针异常、数组下表越界等异常,这些异常抛出后可能会导致程序FC。在编写代码时应该做好检测,多考虑可能会发生错误的情况,从代码层次解决这些问题。

  28. 为什么要用 ContentProvider?它和 sql 的实现上有什么差别?

    使用ContentProvider 可以将数据共享给其他应用,让除本应用之外的应用也可以访问本应用的数据。它的底层是用SQLite 数据库实现的,所以其对数据做的各种操作都是以Sql实现,只是在上层提供的是Uri。

  29. 谈谈 UI 中, Padding 和 Margin 有什么区别?

    padding指内边距,表示组件内部元素距离组件边框的距离。
    marin指外边距,表示组件与组件之间的距离。

  30. 请介绍下 Android 的数据存储方式。

    1. 使用SharedPreferences存储数据;
    2. 文件存储数据;
    3. SQLite数据库存储数据;
    4. 使用ContentProvider存储数据;
    5. 网络存储数据;
  31. Android的LPC机制
    四大组件都可以设置为多进程模式,设置process属性,多进程会导致单例失效,存储失效,有效的多进程之间的访问可以使用AILD, sockct, ContentProvider等。

SanfenR的博客

GreenDao使用详解

发表于 2016-10-20 |

介绍

官网地址

GreenDao github

GreenDao 优点

  1. 性能高,号称Android最快的关系型数据库
  2. 内存占用小
  3. 库文件比较小,小于100K,编译时间低,而且可以避免65K方法限制
  4. 支持数据库加密 greendao支持SQLCipher进行数据库加密 有关SQLCipher可以参考这篇博客Android数据存储之Sqlite采用SQLCipher数据库加密实战
  5. 简洁易用的API

GreenDao 3.0基本使用

在.gradle添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1'
}
}
apply plugin: 'org.greenrobot.greendao'
dependencies {
compile 'org.greenrobot:greendao:3.2.0'
}

需要配置数据库的基本属性

1
2
3
4
greendao {
schemaVersion 1
targetGenDir 'src/main/java'
}
  • schemaVersion:数据库版本号
  • daoPackage:设置DaoMaster, DaoSession, Dao包名
  • targetGenDir: 设置DaoMaster, DaoSession, Dao目录
  • targetGenDirTest: 设置生成单元测试目录
  • generateTests 设置自动生成单元测试用例

创建实体

1
2
3
4
5
6
7
8
9
@Entity()
public class User {
@Id
private Long id;
private String name;
private int age;
//省去了get/set方法
}

实体@Entity注解:

  • schema:表示GreenDao当前实体属于哪个schema
  • active: 标记一个实体处于活动状态,活动实体有更新,删除和刷新方法
  • nameInDb: 在数据中使用的别名,默认使用的是实名的类别
  • indexes: 定义索引,可以跨越多个列
  • createInDb: 标记创建数据库表

基础属性注解:

  • @Id: 主键 Long型,可以通过@Id(autoincrement = true)设置自增长
  • @Property: 设置一个非默认关系映射所对应的列名,默认是的使用字段名 举例:@Property (nameInDb=”name”)
  • @NotNul:设置数据库表当前列不能为空
  • @Transient :添加次标记之后不会生成数据库表的列

索引注解:

  • @Index:使用@Index作为一个属性来创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束
  • @Unique:向数据库列添加了一个唯一的约束

关系注解:

  • @ToOne:定义与另一个实体(一个实体对象)的关系
  • @ToMany:定义与多个实体对象的关系

编译生成DaoMaster, DaoSession, Dao

image

  • 创建一个数据库管理者单例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class DBManager {
    private final static String dbName = "test_db";
    private static DBManager mInstance;
    private DaoMaster.DevOpenHelper openHelper;
    private Context context;
    public DBManager(Context context) {
    this.context = context;
    openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
    }
    /**
    * 获取单例引用
    *
    * @param context
    * @return
    */
    public static DBManager getInstance(Context context) {
    if (mInstance == null) {
    synchronized (DBManager.class) {
    if (mInstance == null) {
    mInstance = new DBManager(context);
    }
    }
    }
    return mInstance;
    }
    }
  • 获取可读可写数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
* 获取可读数据库
*/
private SQLiteDatabase getReadableDatabase() {
if (openHelper == null) {
openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
return openHelper.getReadableDatabase();
}
/**
* 获取可写数据库
*/
private SQLiteDatabase getWritableDatabase() {
if (openHelper == null) {
openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
return openHelper.getWritableDatabase();
}
/**
* 插入一条记录
*
* @param user
*/
public void insertUser(User user) {
DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.insert(user);
}
/**
* 插入用户集合
*
* @param users
*/
public void insertUserList(List<User> users) {
if (users == null || users.isEmpty()) {
return;
}
DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.insertInTx(users);
}
/**
* 删除一条记录
*
* @param user
*/
public void deleteUser(User user) {
DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.delete(user);
}
/**
* 更新一条记录
*
* @param user
*/
public void updateUser(User user) {
DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.update(user);
}
/**
* 查询用户列表
*/
public List<User> queryUserList() {
DaoMaster daoMaster = new DaoMaster(getReadableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
QueryBuilder<User> qb = userDao.queryBuilder();
return qb.list();
}
/**
* 查询用户列表
*/
public List<User> queryUserList(int age) {
DaoMaster daoMaster = new DaoMaster(getReadableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
QueryBuilder<User> qb = userDao.queryBuilder();
qb.where(UserDao.Properties.Age.gt(age)).orderAsc(UserDao.Properties.Age);
return qb.list();
}

外键使用(@ToOne, @ToMany)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Entity
public class User {
@Id(autoincrement = true)
private Long id;
@NotNull
private String name;
private int age;
private Long blogId;
@ToOne(joinProperty = "blogId")
private Blog blog;
}
  • joinProperties这个参数是referencedJoinProperty 参数的升级版。在referencedJoinProperty参数中我们发现俩个实体关联的外键是CustomerId与id,但是如果我们的需求是外键不能通过id来定义,需要用自己自定义属性来定义,第一种方法就没法用了,而joinProperties就是为了解决这个需求的。

github源码

参考资料

GreenDao 3.0使用

Android数据存储之GreenDao 3.0 详解

GreenDao3.0新特性解析(配置、注解、加密

史上最高效的ORM方案——GreenDao3.0高级用法

SanfenR的博客

移位查找(day4)

发表于 2016-10-18 |

题目

  • 一个整型数组里除了两个数字之外,其他的数字都出现了两次。
    请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

思路

  1. 全部元素异或,结果一定不为0,且结果为只出现1次的元素的异或。
  2. 以第结果的第一个非0位(假设第N位)来看,所有元素在该位置的0,1都出现了奇数次。
  3. 以N为基准,为0的分为一组,为1的分为一组。则这两个数分别分到2组。
  4. 这两组分别异或,结果即为所求。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//函数功能 : 找出数组中两个只出现一次的数字
//函数参数 : arr为源数组,len为数组元素个数,result用来存放结果
void function1(int *arr, int len, int *result) {
int i, all = 0, flag = 1;
for (int i = 0; i < len; ++i) { //所有数异或
all ^= arr[i];
}
while (!all & flag) {
flag <<= 1;
}
result[0] = result[1] = 0;
//利用过滤位区分
for (i = 0; i < len; i++) {
if (flag & arr[i])
result[0] ^= arr[i];
else
result[1] ^= arr[i];
}
}

源码github

SanfenR的博客

链表删除(day3)

发表于 2016-10-06 |

假设链表……—A–B–C–D….,要删除B。一般的做法是遍历链表并记录前驱节点,修改指针,时间为O(n)。删除节点的实质为更改后驱指针指向。 这里,复制C的内容至B(此时B,C同时指向D),删除节点C,即达到间接删除节点B的目的。 倘若B是链尾节点。则需要线性遍历寻找前驱节点。以上思路,时间复杂度为O(1)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
struct ListNode {
int m_nKey;
ListNode *m_pNext;
};
void deleteNode(ListNode* pListHead, ListNode* pToBeDeleted) {
if (!pListHead || !pToBeDeleted) {
return;
}
if (pListHead == pToBeDeleted){
delete pListHead;
pListHead = NULL;
pToBeDeleted = NULL;
} else if (pToBeDeleted->m_pNext != NULL) {
ListNode *pNext = pToBeDeleted->m_pNext;
pToBeDeleted->m_nKey = pNext->m_nKey;
pToBeDeleted->m_pNext = pNext->m_pNext;
delete pNext;
pNext = NULL;
} else {
ListNode* pNode = pListHead;
while(pNode->m_pNext != pToBeDeleted) {
pNode = pNode->m_pNext;
}
pNode->m_pNext = NULL;
delete pToBeDeleted;
pToBeDeleted = NULL;
}
}

源码github

SanfenR的博客

位运算计数(day2)

发表于 2016-09-20 |

题目: 求整数的2进制表示中1的个数

整数 右移 相与

1
2
3
4
5
6
7
8
9
int function1(int i) {
int count = 0;
while(i) {
if(i & 1)
count ++;
i = i >> 1;
}
return count;
}

flag 左移 相与

1
2
3
4
5
6
7
8
9
10
11
int function2(int i) {
int count = 0;
unsigned int flag = 1;
while(flag){
if(i & flag){
count ++;
}
flag = flag << 1;
}
return count;
}

减一相与

1
2
3
4
5
6
7
8
int function3(int i) {
int count = 0;
while (i) {
++ count;
i = (i - 1) & i;
}
return count;
}

源码github

SanfenR的博客

递归加法(day1)

发表于 2016-08-06 |

题目:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C).

使用函数指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//----->fun1 start
//使用函数指针 递归加法
typedef int (*fun)(int);
int func1(int n) {
return 0;
}
int func2(int n) {
fun f[2] = {func1, func2};
return n + f[(n != 0)](n - 1);
}
void function1() {
cout << func2(10) << endl;
}
//----->fun2 end

使用静态变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//----->fun2 start
//使用静态变量
class test {
static int N;
static int sum;
public :
test() {
sum += ++N;
}
static void reset() {
N = sum = 0;
}
static int getSum() {
return sum;
}
};
int test::N = 0;
int test::sum = 0;
void function2() {
test::reset();
test *p = new test[10];
cout << test::getSum() << endl;
delete[]p;
}
//--->fun2 end

使用虚函数的编译多态性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//----->fun3 start
//使用虚函数的编译多态性
class A {
public:
virtual int sum(int n) { return 0; };
};
class B : public A {
public:
int sum(int n) {
A a;
B b;
A *p[2] = {&a, &b};
return n + p[(n - 1 != 0)]->sum(n - 1);
}
};
void function3() {
B b;
cout << b.sum(10) << endl;
}
//----->fun3 end

源码github

SanfenR的博客

GitHub不允许上传大于100M文件问题

发表于 2016-05-20 |

问题

1
2
3
4
5
6
自己的项目的版本控制用的是Git,代码仓库在github托管。项目里用到了百度导航SDK,由于百度导航SDK有了新版本,于是就更新到了新版本,更新好了之后想把代码push到github上,结果出错了,被拒绝,具体信息是:Total 3007 (delta 664), reused 0 (delta 0)
remote: error: GH001: Large files detected.
remote: error: Trace: 7b7de6b9372ee392e0f3961b05ea6f33
remote: error: See http://git.io/iEPt8g for more information.
remote: error: File XXX/XXX/BaiduNaviSDK/libbaiduNaviSDK.a is 102.68 MB; this exceeds GitHub's file size limit of 100.00 MB
To https://github.com/XXX/XXXX.git。意思是有大文件,更多信息可到http://git.io/iEPt8g查看,文件libbaiduNaviSDK.a的大小超过了GitHub限制的100M大小。想要push,必须把这个文件移除,可是要怎么移除呢?

解决方案

第一种解决方案
1
2
3
4
5
6
如果这个文件是最近一次commit的,并且你还没有push到github,那么
第一步输入命令 cd /Users/Dora/Desktop/XXX
(cd后面的这个路径要换成你自己项目的路径),
然后第二步输入命令 git rm --cached /Users/Dora/Desktop/XXX/XXX/libbaiduNaviSDK.a(加下划线部分是你自己的要移除的文件的路径),
第三步输入命令 git commit --amend -CHEAD,
执行完这步后,这个大文件将会从你的commit记录里移除,并且以后commit都将不会再把它commit了,这时候就可以git push把本地代码push到github上了。

第二种解决方案

用到一个叫BFG的工具。我们要到[https://rtyley.github.io/bfg-repo-cleaner/#download]这个网站去下载并学习如何使用这个工具
1
2
3
4
5
6
7
8
9
我们要cd进BFG文件所在目录,第一步输入命令
java -jar bfg.jar --no-blob-protection --strip-blobs-bigger-than 50M my-repo.git
(红色部分是你下载下来的文件的名字,蓝色部分是你需要移除的文件大小,橙色部分是你自己.git文件的路径),
第二步cd my-repo.git ,
第三步 git reflog expire --expire=now --all && git gc --prune=now --aggressive,
第四步 git push,
到此大功告成。你的commit历史里所有大于50M的文件的commit全部被清除,这样你就可以push到github上了。这里只是记录了怎么处理遇到的问题,
如果想要知道原理,则需要好好好去学习学习。
123
SanfenR

SanfenR

大成若缺, 大直若屈, 大巧若拙, 大智若愚。

29 日志
8 标签
GitHub
© 2017 SanfenR
由 Hexo 强力驱动
主题 - NexT.Muse

本站总访问量 次, 访客数 人次, 本文总阅读量 次