Android原理入门

  1. Java
    1. 静态内部类和非静态内部类的区别
    2. final protected private修饰方法的区别
    3. 匿名内部类
  2. Android
    1. AsyncTask
    2. 崩溃
      1. 编译时异常
      2. 运行时异常

Java

Java是一门基于JVM(Java Virtual Machine)编译的强类型语言,主要应用到Android和服务端的开发。

静态内部类和非静态内部类的区别

在Java中我们可以有静态实例变量、静态方法、静态块。类也可以是静态的。Java允许我们在一个类里面定义静态类。比如内部类(nested class)。把nested class封闭起来的类叫外部类。在Java中,我们不能用static修饰顶级类(top level class),只有内部类可以为static。

  1. 内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。
  2. 非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。
  3. 一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。

final protected private修饰方法的区别

  1. final是任何人都不能修改方法,包括子类的重写,但可以使用;
  2. protected是只有自己和子类可以使用,子类可重写,而外部其它类不知道该方法的存在;
  3. private是只有自己可以使用,子类以及外部其它类都不知道该方法的存在。

匿名内部类

使用匿名内部类进行初始化:在new一个对象的时候,小括号前就是要实现的接口或要继承的父类,小括号后边跟一个大括号,大括号内就是该内部类的实现。

Person person = new Person("张三") {
    @Override
    public String getName() {
        return super.getName()+"123";
    }
};
class Person{
    String name;
    public Person(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
}

tv1.setOnClickListener(new OnClickListener() {  
   @Override  
   public void onClick(View v) {   
   }  
}); 
public interface OnClickListener {   
   void onClick(View v);  
}

接口是不可以实例化的,上面的OnClickListener可以new,是因为得益于匿名内部类。new OnClickListener(){}其实并没有真正地实例化该接口,而是new了一个实现该接口的匿名内部类。当然匿名内部类还可以选择继承父类而不是实现接口,那new该内部类时从外观上看也同样不要以为是在new父类的实例了。

Android

AsyncTask

AsyncTask是一个系统轻量级的异步任务机制工具。

在Android中实现异步任务机制有两种方式,Handler和AsyncTask。

Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。

为了简化操作,Android1.5提供了工具类android.os.AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。AsyncTask中的三种泛型类型分别代表“启动任务执行的输入参数”、“后台任务执行的进度”、“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用java.lang.Void类型代替。

执行步骤:

  1. execute(Params… params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
  2. onPreExecute(),在execute(Params… params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。
  3. doInBackground(Params… params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息。
  4. onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。
  5. onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。

注意点:
有几点需要格外注意:

  1. 异步任务的实例必须在UI线程中创建。
  2. execute(Params… params)方法必须在UI线程中调用。
  3. 不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法。
  4. 不能在doInBackground(Params… params)中更改UI组件的信息。
  5. 一个任务实例只能执行一次,如果执行第二次将会抛出异常。

概括来说,当我们调用execute(Params… params)方法后,execute方法会调用onPreExecute()方法,然后由ThreadPoolExecutor实例sExecutor执行一个FutureTask任务,这个过程中doInBackground(Params… params)将被调用,如果被开发者覆写的doInBackground(Params… params)方法中调用了publishProgress(Progress… values)方法,则通过InternalHandler实例sHandler发送一条MESSAGE_POST_PROGRESS消息,更新进度,sHandler处理消息时onProgressUpdate(Progress… values)方法将被调用;如果遇到异常,则发送一条MESSAGE_POST_CANCEL的消息,取消任务,sHandler处理消息时onCancelled()方法将被调用;如果执行成功,则发送一条MESSAGE_POST_RESULT的消息,显示结果,sHandler处理消息时onPostExecute(Result result)方法被调用。

延伸:
理论上通过execute启动AsyncTask任务这种方式可以创建无数个task,并且所有的task是串行执行的。

AsyncTask.THREAD_POOL_EXECUTOR是AsyncTask默认帮我们配置的Executor,它的配置是核心线程数为CPU核个数+1,最大线程数是2倍的CPU核个数+1,任务排队队列大小为128,假设手机CPU核的个数为8,在核心线程数为9,最大线程数为17,则最大的任务数为128+17,超过这个数量就会抛出RejectedExecutionException。在排队队列未满之前,最多有9个线程在运行,当排队队列满了之后,最多有17个线程在运行。

崩溃

Android 崩溃分两类

  • Java Exception
  • Native Signal 异常

Java Exception 分两类

  • Checked Exception(编译时异常)
  • UnChecked Exception(运行时异常,所有 RuntimeException 类及其子类的实例)

编译时异常

即在编译阶段被处理的异常。编译器会强制程序处理所有的Checked异常,也就是用try…catch显式的捕获并处理,因为Java认为这类异常都是可以被处理(修复)的。在Java API 文档中声明方法时,都会添加是否 throw 某个 exception,这个 exception 就是Checked 异常。如果没有 try…catch 这个异常,则编译出错,错误提示类似于“Unhandled exception type xxxxx”

执行try块中的代码出现异常,系统会自动生成一个异常对象,并将该异常对象提交给Java运行环境,这个就是异常抛出(throw)阶段;
当Java运行环境收到异常对象时,会寻找最近的能够处理该异常对象的catch块,找到之后把该异常对象交给catch块处理,这个就是异常捕获(catch)阶段。

对于 Checked Exception,虽然我们在程序里面已经捕获并处理了,但是如果能同时将该异常收集并发送到后台,将有助于提升 App 的健壮性。

运行时异常

最常见的莫过于 NullPointerException。

由于没有相应的try…catch处理该异常对象,所以Java运行环境将会终止,程序将退出,也就是 Crash。但不能把这些异常也 try…catch ,有两点会导致这种方案不可行:

  • 无法将所有的代码都加上try…catch,这样对代码的效率和可读性将是毁灭性的;
  • UnChecked异常通常都是较为严重的异常,或者说已经破坏了运行环境的。比如内存地址,即使 try…catch 住了,也不能明确知道如何处理该异常,才能保证程序接下来的运行是正确的。

重点:
这些没有被 try…catch 住的异常,也叫 Uncaught 异常,都会导致应用程序崩溃。Java 提供了一个接口,可以让我们实现比如程序退出前,弹出个性化对话框,而不是默认的强制关闭对话框,或者弹出一个提示框安慰一下用户,甚至重启应用程序等,该接口为 UncaughtExceptionHandler,里面有一个虚函数 uncaughtException。Uncaught 异常发生时会终止线程,此时系统便会通知 UncaughtExceptionHandler,告诉它被终止的线程以及对应的异常,然后便会调用 uncaughtException 函数。如果该 handler 没有被显式设置,则会调用对应线程组的默认handler。如果我们要捕获该异常,必须实现我们自己的handler,并通过函数 setDefaultUncaughtExceptionHandler 进行设置注册监听.在任何线程中,都可以通过 setDefaultUncaughtExceptionHandler 来设置 handler,但在Android应用程序中,全局的 Application 和 Activity、Service 都同属于UI主线程,线程名称默认为“main”。所以,在Application中应该为UI主线程添加UncaughtExceptionHandler,这样整个程序中的 Activity、Service 中出现的UncaughtException 事件都可以被处理 (即 app 里一个自定义的 UncaughtExceptionHandler 就搞定了)。

参考:
Android异常崩溃捕获 - 简书


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 mingfungliu@gmail.com

文章标题:Android原理入门

文章字数:2.3k

本文作者:Mingfung

发布时间:2019-08-14, 00:22:11

最后更新:2021-06-24, 16:36:01

原始链接:http://blog.ifungfay.com/Android/Android原理入门/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏

宝贝回家