美文网首页
Android Studio 开发笔记

Android Studio 开发笔记

作者: Killshadow | 来源:发表于2019-03-07 22:30 被阅读0次

    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);  
    

    相关文章

      网友评论

          本文标题:Android Studio 开发笔记

          本文链接:https://www.haomeiwen.com/subject/ilbosftx.html