1.Android应用的启动Activity在AndroidManifest.xml配置的时候export不能为false,为false就调用不起来了。

<activity
            android:name=".MainActivity"
            android:label="@string/app_name" 
	    android:configChanges="keyboardHidden|orientation"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>



如果配置属性:android:export="false"则启动不起来。它的意思是不能被其他Activity调用


2.onActivityResult被提前调用

有一次,我发现onActivityResult()函数跳转的时候就已经调用了,而不是返回到该界面的时候调用的。

当时的解决办法:因为你的AndroidMenfinst.xml配置的是singleTask改为stardard,但是在实际工作中,启动模式是不能随便修改的。

原因是这样的A调用B,B在一个新的任务栈中创建的,这个时候相当于A和B在两个不同的任务栈中了,他们之间的连接被断开了,这个时候会在启动过程中就会向A反馈一个RESULT_CANCELED



3.我们在用findViewByid()获得一个View的时候,这个View的尺寸大小还没有被初始化,也就是还没有被绘制,你调用getHeight()的时候获取的大小是0。如果你实在有这个需求要获取这个View大小的话可以按照下面的链接做。



4.在一个Android群里有一个朋友遇到这么一个问题,就是不能在android L上安装app,有的应用可以,有的应用不行。

原因是Android L(android 5.0)系统自身限制,多个应用安装时,如果拥有同一个命名一样的Service权限,会导致权限冲突,只能安装一个带有此权限的应用,其他应用都不能再安装上去。自定义service权限不能同名。

解决办法是自己换另外一个sevices权限名字。


5.static变量不能存本地SharePreference


6.在ListView适配器里面,getView中取颜色值应该用context.getResource().getCorlor(id)去取颜色值,还是别直接setColor(id),否则问题很奇怪。不信你试试看不。setColor()中的参数id有时候它会把这个参数当成颜色值,而不是资源id还是用getResource().getColor()去取颜色吧。


7.生成6位真随机数,谨慎用Random,而应用SecureRandom,Random是伪随机的,SecureRandom才是货真价实的随机数。

private String generateNoiseTamp()
    {
        SecureRandom random = new SecureRandom();
        // 生成6位真随机数
        int radomNumber = (random.nextInt(1000000) + 1000000) % 1000000;
        if(radomNumber < 100000)
        {
            radomNumber += 100000;
        }
        
        return System.currentTimeMillis() + "_" + radomNumber;
    }


8.AlertDialog

dialog.setCanceledOnTouchOutside(false); 点击对话框外部dialog不消失
dialog.setCanceledOnTouchOutside(true);点击对话框外部dialog消失


9.ScrollView只能承载一个子控件


10..int index = pointToPosition(x,y),根据x,y坐标,得到listview或者gradview的该位置下的item索引。


11.Android 写selector的时候先后顺序是有讲究的,需要按照优先级顺序排列如下:

    1.disabled state
    2.pressed state
    3.normal state

举个例子:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
	<item android:drawable="@drawable/switch_bg_disabled_emui" android:state_enabled="false"/>
    <item android:drawable="@drawable/switch_bg_on_emui" android:state_pressed="true"/>
    <item android:drawable="@drawable/switch_bg_on_emui" android:state_focused="true"/>
    <item android:drawable="@drawable/switch_bg_on_emui" android:state_checked="true"/>
    <item android:drawable="@drawable/switch_bg_off_emui"/>
</selector>

如果写成下面的顺序android:state_enabled状态就无效了:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/switch_bg_on_emui" android:state_pressed="true"/>
    <item android:drawable="@drawable/switch_bg_on_emui" android:state_focused="true"/>
    <item android:drawable="@drawable/switch_bg_on_emui" android:state_checked="true"/>
    <item android:drawable="@drawable/switch_bg_disabled_emui" android:state_enabled="false"/>
    <item android:drawable="@drawable/switch_bg_off_emui"/>
</selector>

这个需要你自己手动试了。


12.递归的删除文件夹下的所有内容

static void deleteContents(File dir) throws IOException 
	{
		File[] files = dir.listFiles();
		if (files == null) 
		{
			throw new IOException("not a readable directory: " + dir);
		}
		for (File file : files) 
		{
			if (file.isDirectory()) 
			{
				deleteContents(file);
			}
			if (!file.delete()) 
			{
				throw new IOException("failed to delete file: " + file);
			}
		}
	}


13.public static 修饰的函数和 static修饰的函数的区别 。public static 修饰的函数基本上可以在任何地方使用,但static修饰的函数只能在本包的所有类中使用。


14.bundle只能传递0.25兆的数据大小


15.自定义View要自己处理wrap_content情况,可以参考TextView 、ImageView实现,因为从源代码可以看出,测量的时候如果父容器是EXACTLY或者AT_MOST,那么match_parent和wrap_content效果是一样的。所以自定义View需要自己处理wrap_content的情况


16.每个应用都有一个apk的SD卡缓存目录/sdcard/Android/data/package_name/cache ,如果改应用被卸载,此目录下的文件会随之删除。开发的时候做本地缓存,如果你想应用删除后清除数据可以缓存到这个里面。


17.数组的类型是在运行期间检查的, 但集合的类型检查只会发生在编译期间


18.dp/sp dp和sp的一个区别就是,sp会随着个系统设置的修改而改变,而dp不会,看一下源代码

public static float applyDimension(int unit, float value,  
                                       DisplayMetrics metrics)  
    {  
        switch (unit) {  
        case COMPLEX_UNIT_PX:  
            return value;  
        case COMPLEX_UNIT_DIP:  
            return value * metrics.density;  
        case COMPLEX_UNIT_SP:  
            return value * metrics.scaledDensity;  
        case COMPLEX_UNIT_PT:  
            return value * metrics.xdpi * (1.0f/72);  
        case COMPLEX_UNIT_IN:  
            return value * metrics.xdpi;  
        case COMPLEX_UNIT_MM:  
            return value * metrics.xdpi * (1.0f/25.4f);  
        }  
        return 0;  
    }



如上,如果是sp会乘以scaledDensity,这个是随系统设置字体大小的改变和改变,而Density不会随着系统设置字体大小的改变而改变。


18.多屏幕下适配总是被dp、sp、px、dpi弄得头晕,到头来还是不知道怎么写values限定符,values限定符的计算如下:

连上你的手机跑如下代码:

DisplayMetrics metric = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metric);
        int width = metric.widthPixels;  // 屏幕宽度(像素)
        int height = metric.heightPixels;  // 屏幕高度(像素)
        float density = metric.density;  // 屏幕密度(0.75 / 1.0 / 1.5)
        int densityDpi = metric.densityDpi;  // 屏幕密度DPI(120 / 160 / 240)
        
        System.out.println("===========>>>>>>>>>>>>width: " + width);
        System.out.println("===========>>>>>>>>>>>>height: " + height);
        System.out.println("===========>>>>>>>>>>>>density: " + density);
        System.out.println("===========>>>>>>>>>>>>densityDpi: " + densityDpi);

在华为的在M2-801 8寸平板上的打印如下:

03-24 10:50:08.950: I/System.out(28477): ===========>>>>>>>>>>>>width: 1200
03-24 10:50:08.950: I/System.out(28477): ===========>>>>>>>>>>>>height: 1824
03-24 10:50:08.950: I/System.out(28477): ===========>>>>>>>>>>>>density: 2.0
03-24 10:50:08.950: I/System.out(28477): ===========>>>>>>>>>>>>densityDpi: 320

适配文件夹values的适配方式为: sw + width/density +dp


所以我们编写适配该平板的适配文件夹为:sw + 1200/2.0 +dp = sw600dp


在res目录添加values-sw600dp文件夹适配该机型


19.Android的/data/data目录 cache与files的差别在于,如果手机的内部存储空间不够了,会自行选择cache目录进行删除,因此,不要把重要的文件放在cache文件里面,可以放置在files里面,因为这个文件只有在APP被卸载的时候才会被删除。还有要注意的一点是,如果应用程序是更新操作,内部存储不会被删除,区别于被用户手动卸载。


20.SharedPreference在使用过程中有什么注意点?
commit()和apply()的区别

1)apply()没有返回值,而commit()返回boolean表明修改是否提交成功。

2)apply()是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘,。
而commit()是同步的提交到硬件磁盘。
因此,在多并发commit()的时候,会等待正在处理的commit保存到磁盘后再操作,从而降低了效率。
而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,从一定程度上提高了效率。


21.在父布局加上 android:animateLayoutChanges="true" 后,如果触发了layout方法(比如它的子View设置为GONE),系统就会自动帮你加上布局改变时的动画特效。一个属性就可以大大增加用户体验,何乐而不为之。


22.Transient修饰的变量可以保证此变量不被序列化.


23.当ScrollView嵌套Listview使用的时候发现Listview不能完全显示,只能显示第一个item项,这种情况下要重写Listview

package com.zxing;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;

/**
 * Created by rander on 16-4-10.
 */
public class ScrollviewNestedListview extends ListView{
    public ScrollviewNestedListview(Context context) {
        super(context);
    }

    public ScrollviewNestedListview(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ScrollviewNestedListview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    //给其足够的可扩展空间,使其能够完全显示
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }


}




24.一句话介绍AMS

      AMS是通过ActivityStack(和其他数据结构)来记录、管理系统中的Activity(和其他组件)状态,并提供查询功能的一个系统服务。


25.Android NDK(Native Development Kit),使得应用程序可以不依赖Dalvik虚拟机进行开发,当然说的是Jni部分的代码。


26.保证Service不被Kill掉的几个方法

 1)onStartCommand方法,返回START_STICKY

   2)提升service优先级

startForeground 

 Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
   1.前台进程( FOREGROUND_APP)
   2.可视进程(VISIBLE_APP )
   3. 次要服务进程(SECONDARY_SERVER )
   4.后台进程 (HIDDEN_APP)
   5.内容供应节点(CONTENT_PROVIDER)
   6.空进程(EMPTY_APP)

   

 当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground 将service放到前台状态。这样在低内存时被kill的几率会低一些。

 4)onDestroy方法里重启service

   5)Application加上Persistent属性

   6)监听系统广播判断Service状态

   7)将APK安装到/system/app,变身系统级应用


27.在JVM中,一个类用其全限定类名和其类加载器作为唯一标识,
如果在pg包下,有一个Person类,classloade k1 、 classloade k2分别加载Person类
则 Person类在JVM中对应的Class对象为 ( Person,pg,k1 )与 ( Person,pg,k2 )
是不同的





28.try catch finally的执行顺序,先执行try{}中的代码,如果抛出异常会执行catch中代码,但是如果try中有return,那么finally也会执行,如果try中有其他异常,finally还是会执行

29.如果面试官问你,Object有哪些方法,你能倒背如流吗?getClass() equals(Object obj) hashCode() toString() notify() notifyAll() wait() wait(int timeout) wait(int timeout,int nanos)


30.关于HashMap的大小

Map<String,String> map = new HashMap<>();

此时,map的大小是0,

如果执行下面这句话

map.put("1","2");

map的大小并不是1,而是指定的默认值,因为hashMap的空间扩展起来要费很多资源,最好预先知道大小。



31.standard模式的Activity默认会进入启动它的Activity所属的任务栈中,但是由于非Activity类型的Context(如ApplicationContext)并没有所谓的任务栈,会报Runtime异常。


32.每一次重启都会重新安装一下手机上的应用。


33.每一个Activity组件,在ActivityManagerService服务内部都有一个对应的ActivityRecord对象,并且在WindowManagerService服务内部关联有一个AppWindowToken对象。


34.每一个应用程序进程在WindowManagerService服务内部都有一个类型为Session的Binder本地对象,用来它与WindowManagerService服务之间的连接,而有了这个连接之后,应用进程就可以WindowManagerService配合管理系统中的应用程序窗口了。


35.Array.asList() 能够将一个数组转成List但是这个数组不能是基本数据类型,下面举一个例子。

public static void main(String[] args) {
        int[] ints = {1,2,3,4,5};
        List list = Arrays.asList(ints);
        System.out.println("list'size:" + list.size());
    }

输出结果为:

list'size:1

为什么会这样?我们先看源码

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

asList接受的参数是一个泛型的变长参数,我们知道基本数据类型是无法发型化的,也就是说8个基本类型是无法作为asList的参数的, 要想作为泛型参数就必须使用其所对应的包装类型。但是这个这个实例中为什么没有出错呢?因为该实例是将int 类型的数组当做其参数,而在Java中数组是一个对象,它是可以泛型化的。所以该例子是不会产生错误的。既然例子是将整个int 类型的数组当做泛型参数,那么经过asList转换就只有一个int 的列表了。

public static void main(String[] args) {
    int[] ints = {1,2,3,4,5};
    List list = Arrays.asList(ints);
    System.out.println("list 的类型:" + list.get(0).getClass());
    System.out.println("list.get(0) == ints:" + list.get(0).equals(ints));
}



输出结果:

list 的类型:class [I
list.get(0) == ints:true



从这个运行结果我们可以充分证明list里面的元素就是int数组。弄清楚这点了,那么修改方法也就一目了然了:将int 改变为Integer。

public static void main(String[] args) {
        Integer[] ints = {1,2,3,4,5};
        List list = Arrays.asList(ints);
        System.out.println("list'size:" + list.size());
        System.out.println("list.get(0) 的类型:" + list.get(0).getClass());
        System.out.println("list.get(0) == ints[0]:" + list.get(0).equals(ints[0]));
    }
    ----------------------------------------
    outPut:
    list'size:5
    list.get(0) 的类型:class java.lang.Integer
    list.get(0) == ints[0]:true



还有一点需要注意的是此ArrayList不是java.util.ArrayList,所以通过这些代码可以看出asList返回的列表只不过是一个披着list的外衣,它并没有list的基本特性(变长)。该list是一个长度不可变的列表,传入参数的数组有多长,其返回的列表就只能是多长。


35.刚刚看到一个图对AMS管理Activity总结的太棒了,一定要记下来

ActivityManagerService 业务的整个逻辑关系被各种复杂的数据结构包裹着,因此对ActivityManagerService 的分析主要就是对各种数据结构的分析,明白了这些数据结构,理解ActivityManagerService的业务内容就水到渠成了。AMS提供了一个ArrayList mHistory来管理所有的activity,activity在AMS中的形式是ActivityRecord,task在AMS中的形式为TaskRecord,进程在AMS中的管理形式为ProcessRecord。如下图所示

android冷知识nas 安卓手机冷知识_System

从图中我们可以看出如下几点规则:
1. 所有的ActivityRecord会被存储在mHistory管理;
2. 每个ActivityRecord会对应到一个TaskRecord,并且有着相同TaskRecord的ActivityRecord在mHistory中会处在连续的位置;
3. 同一个TaskRecord的Activity可能分别处于不同的进程中,每个Activity所处的进程跟task没有关系;


37.自签名只能验证完整性


38.Activity A 启动 Activity B , 如果Activity B 设置了透明主题,则Activity A的onStop()方法不会被调用。


39.在工作中遇到一个问题就是,出口ip变化的时候我们需要将连接更新到就近服务器,比如连接vpn和断开vpn出口ip都会变化,但是要断开vpn必须将应用切换到后台,然后再在设置里面将vpn断开,无法模拟自然断开。想要模拟自然断开vpn,可以进入手机的shell下,把vpn对应的网卡disable掉,如下:

android冷知识nas 安卓手机冷知识_System_02

我们想自然断开vpn,可以进入手机的命令行,将该网络disable掉

android冷知识nas 安卓手机冷知识_Android_03

这样就是自然断开了,不过手机要root