Android Studio 开发笔记

0x00 ArrayAdapter & ArrayList

ArrayAdapter:adapter即适配器,这个数组适配器一般用于列表中,如:ListView、Spinner。
ArrayList:List接口的可调整大小数组实现。实现所有可选的列表操作,并允许所有元素,包括null。除了实现List接口之外,该类还提供了一些方法来控制用于内部存储列表的数组大小。 (这个类大致相当于Vector,除了它是不同步的。)



ArrayList包含了两个重要的对象:elementData 和 size。
(01) elementData 是"Object[]类型的数组",它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数 ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10。elementData数组的大小会根据ArrayList容量的增长而动态的增长,具体的增长方式,请参考源码分析中的ensureCapacity()函数。
(02) size 则是动态数组的实际大小。

0x01 metadata

元数据是用来描述数据的数据(Data that describes other data)。
我再举一个例子。在电影数据库IMDB上可以查到每一部电影的信息。IMDB本身也定义了一套元数据,用来描述每一部电影。下面是它的一级元数据,每一级下面又列出了二级元数据,总共加起来,可以从100多个方面刻画一部电影:

Cast and Crew(演职人员)、Company Credits(相关公司)、Basic Data(基本情况)、Plot & Quotes(情节和引语)、Fun Stuff(趣味信息)、Links to Other Sites(外部链接)、Box Office and Business(票房和商业开发)、Technical Info(技术信息)、Literature(书面内容)、Other Data(其他信息)。

元数据最大的好处是,它使信息的描述和分类可以实现格式化,从而为机器处理创造了可能。

0x02 @param注释

注释格式:
1、单行(single-line)注释:“//……”
2、块(block)注释:“/……/”
3、文档注释:“/*……/”
4、javadoc 注释标签语法

@author 对类的说明 标明开发该类模块的作者
@version 对类的说明 标明该类模块的版本
@see 对类、属性、方法的说明 参考转向,也就是相关主题
@param 对方法的说明 对方法中某参数的说明
@return 对方法的说明 对方法返回值的说明
@exception 对方法的说明 对方法可能抛出的异常进行说明

0x03 intent

Intent是一个消息传递对象,您可以使用它从其他应用组件请求操作。尽管 Intent 可以通过多种方式促进组件之间的通信,但其基本用例主要包括以下三个:

  • 启动 Activity

    Activity表示应用中的一个屏幕。通过将 Intent传递给startActivity(),您可以启动新的 Activity实例。Intent描述了要启动的 Activity,并携带了任何必要的数据。
    如果您希望在 Activity 完成后收到结果,请调用startActivityForResult()。在 Activity 的 onActivityResult()回调中,您的 Activity 将结果作为单独的Intent对象接收。如需了解详细信息,请参阅 Activity 指南。

  • 启动服务

    Service是一个不使用用户界面而在后台执行操作的组件。通过将Intent传递给startService(),您可以启动服务执行一次性操作(例如,下载文件)。Intent描述了要启动的服务,并携带了任何必要的数据。

    如果服务旨在使用客户端-服务器接口,则通过将Intent传递给bindService(),您可以从其他组件绑定到此服务。如需了解详细信息,请参阅服务指南。

  • 传递广播

    广播是任何应用均可接收的消息。系统将针对系统事件(例如:系统启动或设备开始充电时)传递各种广播。通过将Intent传递给sendBroadcast()sendOrderedBroadcast()或 [sendStickyBroadcast()](https://developer.android.com/reference/android/co ntent/Context.html),您可以将广播传递给其他应用。

0x04 单例模式

单例模式的定义是它应该保证一个类仅有一个实例,同时这个类还必须提供一个访问该类的全局访问点。如下图是单例模式的结构图:


实现单例模式有以下几个关键点:
(1)其构造函数不对外开放,一般为private;
(2)通过一个静态方法或者枚举返回单例类对象;
(3)确保单例类的对象有且只有一个,尤其要注意多线程的场景;
(4)确保单例类对象在反序列化时不会重新创建对象;
通过将单例类的构造函数私有化,使得客户端不能通过new的形式手动构造单例类的对象。单例类会主动暴露一个公有的静态方法,客户端调用这个静态的方法获取到单例类的唯一实例。在获取这个单例类的时候需要确保这个过程是线程安全的。
引自:https://blog.csdn.net/happy_horse/article/details/51164262

0x05 Serializable

https://www.jianshu.com/p/fb903a1f8831

0x06 关键字 new

作用:https://blog.csdn.net/ljheee/article/details/52235915
声明一个变量来指向一个对象,即引用;
实例化一个类对象;
初始化一个类对象.

0x07 UUID

UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符。UUID具有以下涵义:来源

经由一定的算法机器生成:为了保证UUID的唯一性,规范定义了包括网卡MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成UUID的算法。UUID的复杂特性在保证了其唯一性的同时,意味着只能由计算机生成。
非人工指定,非人工识别:UUID是不能人工指定的,除非你冒着UUID重复的风险。UUID的复杂性决定了“一般人“不能直接从一个UUID知道哪个对象和它关联。
在特定的范围内重复的可能性极小:UUID的生成规范定义的算法主要目的就是要保证其唯一性。但这个唯一性是有限的,只在特定的范围内才能得到保证,这和UUID的类型有关(参见UUID的版本)。
UUID是16字节128位长的数字,通常以36字节的字符串表示,示例如下:
3F2504E0-4F89-11D3-9A0C-0305E82C3301
其中的字母是16进制表示,大小写无关。

0x08 Fragment 生命周期

1 生命周期两张图

Fragment生命周期图:

image

Fragment与Activity生命周期对比图:

image

2 生命周期分析

1. 当一个fragment被创建的时候,它会经历以下状态.

  • onAttach()
  • onCreate()
  • onCreateView()
  • onActivityCreated()

2. 当这个fragment对用户可见的时候,它会经历以下状态。

  • onStart()
  • onResume()

3. 当这个fragment进入“后台模式”的时候,它会经历以下状态。

  • onPause()
  • onStop()

4. 当这个fragment被销毁了(或者持有它的activity被销毁了),它会经历以下状态。

  • onPause()
  • onStop()
  • onDestroyView()
  • onDestroy() // 本来漏掉类这个回调,感谢xiangxue336提出。
  • onDetach()

5. 就像activitie一样,在以下的状态中,可以使用Bundle对象保存一个fragment的对象。

  • onCreate()
  • onCreateView()
  • onActivityCreated()

6. fragments的大部分状态都和activitie很相似,但fragment有一些新的状态。

  • onAttached() —— 当fragment被加入到activity时调用(在这个方法中可以获得所在的activity)。
  • onCreateView() —— 当activity要得到fragment的layout时,调用此方法,fragment在其中创建自己的layout(界面)。
  • onActivityCreated() —— 当activity的onCreated()方法返回后调用此方法
  • onDestroyView() —— 当fragment中的视图被移除的时候,调用这个方法。
  • onDetach() —— 当fragment和activity分离的时候,调用这个方法。

一旦activity进入resumed状态(也就是running状态),你就可以自由地添加和删除fragment了。因此,只有当activity在resumed状态时,fragment的生命周期才能独立的运转,其它时候是依赖于activity的生命周期变化的。

0x09 inflater.inflate

很多人在网上问LayoutInflater类的用法,以及inflate()方法参数的含义,现解释如下:
inflate()的作用就是将一个用xml定义的布局文件查找出来,注意与findViewById()的区别,inflate是加载一个布局文件,而findViewById则是从布局文件中查找一个控件。

  1. 获取LayoutInflater对象有三种方法
LayoutInflater inflater=LayoutInflater.from(this);
LayoutInflater inflater=getLayoutInflater();
LayoutInflater inflater=(LayoutInflater)this.getSystemService(LAYOUT_INFLATER_SERVICE);
  1. 关于LayoutInflater类inflate(int resource, ViewGroup root, boolean attachToRoot)方法三个参数的含义

resource:需要加载布局文件的id,意思是需要将这个布局文件中加载到Activity中来操作。
root:需要附加到resource资源文件的根控件,什么意思呢,就是inflate()会返回一个View对象,如果第三个参数attachToRoot为true,就将这个root作为根对象返回,否则仅仅将这个root对象的LayoutParams属性附加到resource对象的根布局对象上,也就是布局文件resource的最外层的View上,比如是一个LinearLayout或者其它的Layout对象。
attachToRoot:是否将root附加到布局文件的根视图上

0x0A Builder模式

一、 概述

1.1 定义

将一个复杂对象的构建与表示分离开来,使得同样的构建过程可以创建不同的表示。

1.2 使用场景

  • 相同的方法,不同的执行顺序,产生不同的结果

  • 多中属性都可以装配到一个对象中,但是产生的运行结果不同

  • 复杂的产品类,或者产品类结果会随调用顺序发生改变

  • 初始化一个对象特别复杂,如参数特别多,且很多参数都具有默认值时

1.3 分析

Builder模式将部件和组装过程分离,使得构建过程和部件都可以自由扩展,从而降低两者耦合度。

优点:

  • 良好的封装性,使用Builder模式可以使客户端不必知道产品内部的组成细节
  • Builder独立,易于扩展

缺点:

  • 会产生冗余的Builder对象以及组装对象,消耗内存

二、 实现

2.1 示例

Builder模式非常易于上手,我们通过分析一个简单的demo来感受Builder模式的魅力。

EventBus 框架中的 EventBusBuilder 就采用 Builder 模式实现,我们来分析Builder模式的实现,EventBus 3.0 源码解析见 EventBus3.源码解析

EventBusBuilderEventBus 框架中的个性化配置类,从类名就可以看出这是一个 Builder 模式,通过Builder 对象来组装个性化设置 EventBus 的各项参数配置,包括 是否通过Log输出异常信息logSubscriberExceptions 等。下面看看 EventBusBuilder 的相关源码。

public class EventBusBuilder {
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    boolean logSubscriberExceptions = true;//是否通过Log输出异常信息
    boolean logNoSubscriberMessages = true;//是否通过Log输出发送事件无订阅者信息
    boolean sendSubscriberExceptionEvent = true;//是否将内部异常信息通过SubscriberExceptionEvent发送出去
    boolean sendNoSubscriberEvent = true;//是否将无订阅者的时间通过NoSubscriberEvent发送出去
    boolean throwSubscriberException;//是否将内部异常信息通过EventBusException抛出
    boolean eventInheritance = true;//发送事件是否支持调用所有父类及实现的接口
    boolean ignoreGeneratedIndex;//是否忽略生成被观察者订阅的方法(通过反射)
    boolean strictMethodVerification;//是否开启严格的方法验证,(public,只有一个参数,不为static及abstract),非法则均抛出异常
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;//发送事件的线程池
    List<Class<?>> skipMethodVerificationForClasses;//对类忽略方法校验,目前未实现
    List<SubscriberInfoIndex> subscriberInfoIndexes;//通过annotation preprocessor生成的订阅者方法list

    EventBusBuilder() {
    }

    /**
     * 设置 logSubscriberExceptions,默认为true
     * @param logSubscriberExceptions
     * @return
     */
    public EventBusBuilder logSubscriberExceptions(boolean logSubscriberExceptions) {
        this.logSubscriberExceptions = logSubscriberExceptions;
        return this;
    }

    /**
     * 设置 logNoSubscriberMessages,默认为 true
     * @param logNoSubscriberMessages
     * @return
     */
    public EventBusBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages) {
        this.logNoSubscriberMessages = logNoSubscriberMessages;
        return this;
    }

    /**
     * 设置 sendSubscriberExceptionEvent,默认为 true
     * @param sendSubscriberExceptionEvent
     * @return
     */
    public EventBusBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent) {
        this.sendSubscriberExceptionEvent = sendSubscriberExceptionEvent;
        return this;
    }

    /**
     * 设置 sendNoSubscriberEvent,默认为 true
     * @param sendNoSubscriberEvent
     * @return
     */
    public EventBusBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent) {
        this.sendNoSubscriberEvent = sendNoSubscriberEvent;
        return this;
    }

    /**
     * 设置 throwSubscriberException,默认为 false
     * @param throwSubscriberException
     * @return
     */
    public EventBusBuilder throwSubscriberException(boolean throwSubscriberException) {
        this.throwSubscriberException = throwSubscriberException;
        return this;
    }

    /**
     * 设置 eventInheritance,默认为 true
     * @param eventInheritance
     * @return
     */
    public EventBusBuilder eventInheritance(boolean eventInheritance) {
        this.eventInheritance = eventInheritance;
        return this;
    }

    /**
     * 设置 executorService
     * @param executorService
     * @return
     */
    public EventBusBuilder executorService(ExecutorService executorService) {
        this.executorService = executorService;
        return this;
    }

    /**
     * 设置 skipMethodVerificationForClasses
     * @param clazz
     * @return
     */
    public EventBusBuilder skipMethodVerificationFor(Class<?> clazz) {
        if (skipMethodVerificationForClasses == null) {
            skipMethodVerificationForClasses = new ArrayList<>();
        }
        skipMethodVerificationForClasses.add(clazz);
        return this;
    }

    /**
     * 设置 ignoreGeneratedIndex
     * @param ignoreGeneratedIndex
     * @return
     */
    public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
        this.ignoreGeneratedIndex = ignoreGeneratedIndex;
        return this;
    }

    /**
     * 设置 strictMethodVerification
     * @param strictMethodVerification
     * @return
     */
    public EventBusBuilder strictMethodVerification(boolean strictMethodVerification) {
        this.strictMethodVerification = strictMethodVerification;
        return this;
    }

    /**
     * 设置 subscriberInfoIndexes
     * @param index
     * @return
     */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if(subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

    /**
     * 实现修改 EventBus 默认 EventBusBuilder(EventBus.defaultInstance)
     * @return
     */
    public EventBus installDefaultEventBus() {
        synchronized (EventBus.class) {
            if (EventBus.defaultInstance != null) {
                throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
            }
            EventBus.defaultInstance = build();
            return EventBus.defaultInstance;
        }
    }

    /**
     * 通过 build 方式实现 EventBus 初始化
     * @return
     */
    public EventBus build() {
        return new EventBus(this);
    }

}

上述代码中,EventBusBuilder 类可以设置 EventBus 中的 * logSubscriberExceptions、logNoSubscriberMessages、sendSubscriberExceptionEvent* 等参数,这些参数统一存储在 EventBusBuilder 中。在调用 EventBusBuilder 类的 build() 函数时会创建 EventBus,并且将各项配置用于到 EventBus 中去。

EventBusBuilder 采用 Builder 模式主要是初始化 EventBus 配置项参数复杂,并且很多参数具有默认值,在使用时可能只需要对部分参数进行修改,故采用 Builder 模式方便修改初始化。

2.2 小结

通过 2.1节 可以看出 Builder 模式使用非常方便,并且对于多参数属性初始化来说,极大的简化了工作。

在项目中合理的加入 Builder 模式吧~

三、小结

Builder 模式在 Android 开发中较为常用,通常作为配置类的构造器将配置的构建和表示分离开来,同时也实现了将配置类从目标类中抽离出来,避免了过多的 setter 方法。

Builder 模式比较常见的实现方式是通过调用链实现,这样使得代码简单易懂。

0x0B 单例模式

一、 概述

1.1 定义

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

1.2 使用场景

确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源;或者某种类型的对象应该有且只有一个。

eg:创建一个对象需要消耗的资源过多,如访问IO和数据库资源。

1.3 关键点

构造函数不对外开放,一般为 private ;
通过一个静态方法或者枚举返回单例类对象;
确保单例类的对象有且只有一个,尤其是在 多线程 环境下;
确保单例类对象在反序列化时不会重新构建对象。

二、实现方式

2.1 懒汉模式

声明一个静态对象,并且在用户第一次调用 getInstance 时进行初始化。

2.1.1 分析
synchronized 关键字用于在多线程情况下保证单例对象唯一性

优点:单例只有在使用时才会被实例化,在一定程度上节约了资源

缺点:
    每一次加载时需要及时进行实例化,响应速度稍慢
    每次调用 getInstance() 都进行同步,造成不必要的同步开销

一般不建议使用
2.1.2 源码

public class Singleton {
private static Singleton instance;

private Singleton() {

}

public static synchronized Singleton getInstance() {
    if (null == instance) {
        instance = new Singleton();//加载时进行实例化
    }
    return instance;
}

}

2.2 饿汉模式

声明静态对象时就已经初始化。

2.2.1 分析
静态对象在声明的时候就已经初始化,从而保证了单例对象唯一性

优点: 每次调用 getInstance() 直接取出静态对象,不需要同步锁,响应速度快

缺点:初始化声明对象造成了一定资源的闲置浪费

2.2.2 源码

public class Singleton {
private static Singleton instance = new Singleton();

private Singleton() {

}

public static Singleton getInstance() {
    return instance;
}

}

2.3 Double Check Lock (DCL) 模式

2.3.1 分析
优点:
    资源利用率高
    既能够在需要时才初始化单例,又能够保证线程安全,且单例对象初始化后调用 getInstance() 不进行同步锁

缺点:
    第一次加载时响应稍慢
    由于Java内存模型的原因偶尔会失败
        instance = new Singleton(); 这句代码并不是一个原子操作,由于 Java 编译器允许处理器乱序执行汇编指令以及 JDK1.5 之前的 JVM (Java Memory Model, Java 内存模型) 中Cache、寄存器到主内存回写顺序的规定,该语句转换的汇编指令无法确保顺序执行
        在 JDK1.5 之后,具体化了 volatile 关键字,因此可以直接定义成 private volatile static Singleton instance = null; ,就可以保证 instance 对象每次都是从主内存中读取
2.3.2 源码

public class Singleton {
private volatile static Singleton instance = null;

private Singleton() {

}

public static Singleton getInstance() {
    if (null == instance) {
        synchronized (Singleton.class) {
            if (null == instance) {
                instance = new Singleton();
            }
        }
    }
    return instance;
}

}

2.4 静态内部类单例模式

2.4.1 分析

强烈推荐使用

优点:
    第一次加载 Singleton 类时并不会初始化 instance ,只有在第一次调用 getInstance() 时才会初始化
    既能保证线程安全,也能保证单例对象的唯一性,同时也延迟了单例的实例化
2.4.2 源码

public class Singleton {
private Singleton() {

}

public static Singleton getInstance() {
    return SingletonHolder.instance;
}

/**
 * 静态内部类
 */
private static class SingletonHolder {
    private static final Singleton instance = new Singleton();
}

}

2.5 枚举单例

2.5.1 分析

枚举单例模式最大的优点是写法简单,枚举在 Java 中与普通类是一样的,不仅能够有字段,还能够有自己的方法。最重要的是默认枚举实例的创建时线程安全的,并且在任何情况下它都是一个单例。

在上述的几种单例模式中,反序列化 的时候会出现重新创建对象的情况。**

上述示例中如果要杜绝单利对象在被反序列化时重新生成对象,则必须加入如下方法:

private Object readResolve() throws ObjectStreamException {
return instance;
}

2.5.2 源码

public enum Singleton {

INSTANCE;

public void doSomething() {
    // ... do something
}

}

2.6 使用容器实现单例模式

2.6.1 分析

在程序初始化的时候,将多种单例类型注入到一个统一的管理类中,在使用时根据 key 获取对象对应类型的对象。

这种方式使得我们可以管理多种类型的单例,并且在使用时候可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。

2.6.2 源码

public class SingletonManager {
private static Map<String, Object> data = new HashMap<>();

public SingletonManager() {
}

public static void register(String key, Object instance) {
    if (!data.containsKey(key)) {
        data.put(key, instance);
    }
}

public static Object get(String key) {
    return data.get(key);
}

}

三、小结

所有的单例模式核心原理都是将构造函数私有化,并且通过静态方法获取一个唯一的实例。

需要注意的是在获取实例的过程中保证线程安全、防止反序列化导致重新生成实例对象等问题。

具体选择哪种方式实现单例模式还需要结合项目业务逻辑。

0X0C AndroidManifest之activity

<activity android:allowEmbedded=["true" | "false"]
          android:allowTaskReparenting=["true" | "false"]
          android:alwaysRetainTaskState=["true" | "false"]
          android:autoRemoveFromRecents=["true" | "false"]
          android:banner="drawable resource"
          android:clearTaskOnLaunch=["true" | "false"]
          android:configChanges=["mcc", "mnc", "locale",
                                 "touchscreen", "keyboard", "keyboardHidden",
                                 "navigation", "screenLayout", "fontScale",
                                 "uiMode", "orientation", "screenSize",
                                 "smallestScreenSize"]
          android:documentLaunchMode=["intoExisting" | "always" |
                                  "none" | "never"]
          android:enabled=["true" | "false"]
          android:excludeFromRecents=["true" | "false"]
          android:exported=["true" | "false"]
          android:finishOnTaskLaunch=["true" | "false"]
          android:hardwareAccelerated=["true" | "false"]
          android:icon="drawable resource"
          android:label="string resource"
          android:launchMode=["multiple" | "singleTop" |
                              "singleTask" | "singleInstance"]
          android:maxRecents="integer"
          android:multiprocess=["true" | "false"]
          android:name="string"
          android:noHistory=["true" | "false"]  
          android:parentActivityName="string" 
          android:permission="string"
          android:process="string"
          android:relinquishTaskIdentity=["true" | "false"]
          android:screenOrientation=["unspecified" | "behind" |
                                     "landscape" | "portrait" |
                                     "reverseLandscape" | "reversePortrait" |
                                     "sensorLandscape" | "sensorPortrait" |
                                     "userLandscape" | "userPortrait" |
                                     "sensor" | "fullSensor" | "nosensor" |
                                     "user" | "fullUser" | "locked"]
          android:stateNotNeeded=["true" | "false"]
          android:taskAffinity="string"
          android:theme="resource or theme"
          android:uiOptions=["none" | "splitActionBarWhenNarrow"]
          android:windowSoftInputMode=["stateUnspecified",
                                       "stateUnchanged", "stateHidden",
                                       "stateAlwaysHidden", "stateVisible",
                                       "stateAlwaysVisible", "adjustUnspecified",
                                       "adjustResize", "adjustPan"] >   
    . . .
</activity>

0x0D 使TextView中的文本滑动

首先在textView组件中设置scrollbars属性为vertical:

<TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_weight="2.89"
        android:scrollbars="vertical"
        android:textColor="#ffffffff"
        android:text=" "/>

然后在java里实例化TextView的时候:

// obj表示实例化的TextView组件
obj.setMovementMethod(ScrollingMovementMethod.getInstance());

0x0E 圆角按钮

res/drawable/目录下添加一个这样的xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">

    <item android:state_pressed="true">
        <shape>
            <solid android:color="@color/light_goldenrod_yellow"/>
            <corners android:radius="8dp"/>
        </shape>
    </item>
    <!--<item android:state_pressed="false">-->
        <!--<shape>-->
            <!--<solid android:color="@android:color/holo_blue_dark"/>-->
            <!--<corners android:radius="5dp"/>-->
        <!--</shape>-->
    <!--</item>-->

    <item>
        <shape android:shape="rectangle">
            <corners android:radius="8dp"/>
            <solid android:color="@android:color/transparent"/>
            <stroke android:color="@color/dark_slate_gray"
                android:width="2dp"/>
        </shape>
    </item>
</selector>

一些Tips

  1. layout_gravity 和 gravity的区别

android:gravity sets the gravity of the contents (i.e. its subviews) of the View it's used on.
android:layout_gravity sets the gravity of the View or Layout relative to its parent.

  1. scrollview

放在根视图, 可以使整个activity滚动.

  1. TimePicker DatePicker可以弹出时间/日期选择器.

  2. edittext添加输入字数限制:
    xml中:

<EditText  android:layout_width = "fill_parent"  
    android:layout_height = "wrap_content"  
    android:id = "@+id/mEdit"  
    android:maxLength = "10"/>  

代码中:

view plain
EditText mEdit = (EditText)findViewById(R.id.mEdit);  
InputFilter[] filters = {new LengthFilter(10)};  
mEdit.setFilters(filters);  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,192评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,186评论 1 303
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,844评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,471评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,876评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,891评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,068评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,791评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,539评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,772评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,250评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,577评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,244评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,146评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,949评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,995评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,812评论 2 276

推荐阅读更多精彩内容