• 每日一点点java的积攒


    一、Service的启动方式

      1.采用startService的方式开启服务

         生命周期 : onCreate()--->onStartCommand()onStart()方法已过时) ---> onDestory()

              特点 :     一旦服务开启跟调用者(开启者)就没有任何关系了,开启者退出了,开启者挂了,服务再后台长期运行,开启者不能调用服务里面的方法

          如果希望能调用

          2. 采用bindService的方式开启服务

              生命周期 : onCreate() --->onBind()--->onunbind()--->onDestory()

         特点 : bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉,绑定者可以调用服务里面的方法

    二、BroadcastReceiver注册方式

      1.动态注册广播和静态广播的区别

        第一种不是常驻型广播,也就是说广播跟随程序的生命周期

        第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行 

      2.发送广播的方式

       无序广播 、有序广播  、自定广播    

    三、进程保活

      黑色保活 :  不同的app进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒)

      白色保活 :  启动前台Service

      灰色保活 :  利用系统的漏洞启动前台Service

     

      黑色保活的原理 : 就是利用不同的app进程使用广播来进行相互唤醒

      白色保活的原理 : 调用系统api启动一个前台的Service进程,这样会在系统的通知栏生成一个Notification,用来让用户知道有这样一个app在运行着,哪怕当前的app退到了后台

      灰色保活的原理 : 白色保活的基础之上,不会让系统通知栏有一个Notification这样的通知

      同时启动两个id相同的前台Service,然后再将后启动的Service做stop处理

      private final static int GRAY_SERVICE_ID = 1001;

      public static class GrayInnerService extends Service {
    
            @Override
            public int onStartCommand(Intent intent, int flags, int startId) {
                startForeground(GRAY_SERVICE_ID, new Notification());
                stopForeground(true);
                stopSelf();
                return super.onStartCommand(intent, flags, startId);
            }
    }

    四、自定义View
      onMeasure()、onLayout()、onDraw()三种方法
      onMeasure() : 为了测量控件的距离,有三种模式 : 1.自适应 2.全局布局 3.用户已经设置好距离

    五、View的事件分发
      

    六、TCP和UDP的区别 TCP属于传输层,用于数据传输 http属于应用层,用于数据的封装

      1.基于连接与无连接;
      2.对系统资源的要求(TCP较多,UDP少);
      3.UDP程序结构较简单;
      4.流模式与数据报模式 ;

      5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

      TCP UDP (应用场景 IP电话,实时视频会议)
      是否连接 面向连接 面向非连接
      传输可靠性 可靠 不可靠
      应用场合 传输大量数据 少量数据
      速度 慢 快

    七、ANR产生的原因以及解决的办法
      1.产生ANR的限制条件
        a.只有主线程才会发生ANR的问题
        b.主线程执行超过5会发生ANR、 主线程BroadcastReceiver的onCreate的方法超过10、主线程执行Service超过20秒没有执行完毕
      2.产生ANR的案例:
        a.调用Service的join、wait、sleep或者加锁导致主线程等待超时
        b.Service的binder数量达到上限
        c.大量的数据读写
        d.System Servvice 中产生WatchDog的ANR
        e.其他的线程的崩溃或者终止导致主线程一直等待
      3.解决ANR的问题
        a.主线程开启子线程来去执行耗时的操作  
        b.BroadcastReceiver执行耗时的操作去开启一个Service去后台执行

    八、OMM产生的场景:
      1.文件的读写、数据库以及网路启用没有及时关闭
      2.static的对象的生命周期过长
      3.注册广播需要注销广播  
      4.构造Adapter时,没有使用缓存的convertView
      5.非静态内部类默认会持有外部类的引用(非静态内部类和匿名类内部类都会潜在持有它们所属的外部类的引用)
      public class MainActivity extends AppCompatActivity {
      private static TestResource mResource = null;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      if(mResource == null){
      mResource = new TestResource();
      } //...
      }
      class TestResource { //... }
      //修改
      static Class TestResource {......} 或者改为单例模式
      }
      6.静态内部类中使用非静态外部成员变量
      7.AsyncTask和Runnable都使用了匿名内部类,那么它们将持有其所在Activity的隐式引用 解决办法:把他们转换为静态内部类
      public class MainActivity extends AppCompatActivity {
      @Override
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      new Thread(new MyRunnable()).start();
      new MyAsyncTask(this).execute();
      }

      class MyAsyncTask extends AsyncTask<Void, Void, Void> {
      // ...
      public MyAsyncTask(Context context) {
      // ...
      }
      @Override
      protected Void doInBackground(Void... params) {
      // ...
      return null;
      }
      @Override
      protected void onPostExecute(Void aVoid) {
      // ...
      }
    }
      class MyRunnable implements Runnable {
      @Override public void run() {
      // ...
     }
    }
    }

    九、线程池的理解:
      1.总结: Java-五种线程池,四种拒绝策略,三种阻塞队列
      2. 五种线程池
       threadPool = Executors.newCachedThreadPool();//有缓冲的线程池,线程数 JVM 控制
        threadPool = Executors.newFixedThreadPool(3);//固定大小的线程池
        threadPool = Executors.newScheduledThreadPool(2);
        threadPool = Executors.newSingleThreadExecutor();//单线程的线程池,只有一个线程在工作
        threadPool = new ThreadPoolExecutor();//默认线程池,可控制参数比较多    

      3.四种拒绝策略
       RejectedExecutionHandler rejected = null;
        rejected = new ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常
        rejected = new ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常
        rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列
        rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务
      
      4.三种阻塞队列
       BlockingQueue<Runnable> workQueue = null;
        workQueue = new ArrayBlockingQueue<>(5);//基于数组的先进先出队列,有界
        workQueue = new LinkedBlockingQueue<>();//基于链表的先进先出队列,无界
        workQueue = new SynchronousQueue<>();//无缓冲的等待队列,无界
       
      SynchronousQueue——直接提交策略,适用于CachedThreadPool
      LinkedBlockingQueue——无界队列,适用于FixedThreadPool与SingleThreadExcutor
      public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
    
      }
    
    传递参数讲解:
    
    * corePoolSize:线程池的大小
    * maximumPoolSize:最大线程池大小
    * keepAliveTime:线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间
    * unit:keepAliveTime时间单位
    * workQueue:阻塞任务队列
    * threadFactory:新建线程工厂
    * RejectedExecutionHandler:当提交任务数超过maximumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理(保护策略)
    十、wait和sleep的区别
       1.sleep是Thread的静态方法,可以在人和地方调用
       2.wait是Object的成员方法,只有在synchronized代码中被调用,否则会抛出非法监控异常
       3.
    在等待时wait会释放锁;而sleep一直持有锁,不会改变线程持有锁的情况
       4.Wait通常被用于线程间交互,sleep通常被用于暂停执行
     十一、synchronized的底层实现原理
       1.synchronzied 同步代码块底层原理
        同步代码块使用的是monitorenter和monitorexit指令,
        其中monitorenter指向同步代码块的开始位置,monitorexit指向同步代码块的结束位置。
        原理:线程执行到monitorenter指令时,当线程尝试获取锁,即当前线程获得monitor持有权,count计数器+1,获得线程锁,
           如果其他线程已经持有该对象的锁,则该线程被阻塞,直到其他线程执行完毕释放锁。
           线程执行完毕时,执行monitorexit指令,count归零,锁释放。不论这个方法正常结束还是异常结束,最终都会配对执行monitorexit指令。
       
        2.synchronized 的同步方法
         ACC_SYNCHRONIZED的flag标记该方法是否是同步方法,从而执行相应的同步调用
     
    十二、lock、synchronized 和 volatile的区别
        1.synchronized 和 volatile 的区别
         
    volatile只能在线程内存和主内存之间同步一个变量值
         
    synchronized可以再线程内存和主内存之间同步所有的值,并通过锁管理所有的变量,但是synchronized很消耗内存
         volatile只能使用在变量上、synchronized则可以使用在对象、类、方法上面

        volatile的理解:具有可见性、有序性,不具备原子性、禁止指令重排
              特点:用以声明变量的值可能随时会别的线程修改,使用volatile修饰的变量会强制将修改的值立即写入主存,非volatile变量不会直接写入主内存中
        原子性:如果全部执行完成那没毛病,如果只执行了一部分,那对不起,你得撤销已经执行的部分
        有序性:即程序执行时按照代码书写的先后顺序执行。在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性

        2.synchronized 和 lock 的区别
          a.synchronized是Java的关键字,内置特性;Lock是一个接口
    b.synchronized会自动释放锁; Lock需要手动释放锁,所以要写到try catch块中并且在finally中释放锁
    c.synchronized无法中断等待的锁; Lock可以中断,所以它可以提高多线程的读写操作,竞争激烈的时候,lock的性能明显优于synchronized
    十三、多线程基础知识 
       1.线程实现的方式
        implements Runnable 、extends Thread 两种方式
       2.Thread start 和 run 的方法
        start : 开启每一个线程的启动方法,一个线程只能开启一次
        run : 只是执行方法,可以多次执行,不能起到多线程作用
      3.线程同步的方法:
       a. synchronized 的同步方法
       b. synchronized 的同步代码块
       c.
    volatile 来定义变量
       d. lock和unlock的对指定地方加锁
      4.生产者和消费者代码
    public class Person {
        private String name;
        private int age;
        //表示共享资源对象是否为空,如果为 true,表示需要生产,如果为 false,则有数据了,不要生产
        private boolean isEmpty = true;
        public synchronized void push(String name,int age){
            try {
                //不能用 if,因为可能有多个线程
                while(!isEmpty){//进入到while语句内,说明 isEmpty==false,那么表示有数据了,不能生产,必须要等待消费者消费
                    this.wait();//导致当前线程等待,进入等待池中,只能被其他线程唤醒
                }
                 
                //-------生产数据开始-------
                this.name = name;
                //延时代码
                Thread.sleep(10);
                this.age = age;
                //-------生产数据结束-------
                isEmpty = false;//设置 isEmpty 为 false,表示已经有数据了
                this.notifyAll();//生产完毕,唤醒所有消费者
            } catch (Exception e) {
                e.printStackTrace();
            }
             
        }
     
        public synchronized void pop(){
            try {
                //不能用 if,因为可能有多个线程
                while(isEmpty){//进入 while 代码块,表示 isEmpty==true,表示为空,等待生产者生产数据,消费者要进入等待池中
                    this.wait();//消费者线程等待
                }
                //-------消费开始-------
                Thread.sleep(10);
                System.out.println(this.name+"---"+this.age);
                //-------消费结束------
                isEmpty = true;//设置 isEmpty为true,表示需要生产者生产对象
                this.notifyAll();//消费完毕,唤醒所有生产者
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
     
     十四、虚拟机的学习
       1.虚拟机的分类
       a.方法区   :  主要存放静态数据、全局静态数据和常量
       b.栈区             :   方法体内的局部变量,并在方法执行结束时这些局部变量所持有的内存将会自动被释放
       c.堆区              :  指在程序运行时直接new出来的内存,也就是对象或者数组的实例,这部分内存在不使用时将会由Java垃圾回收器来负责回收
       d.本地方法栈   :  专门为native方法服务的
      2.堆和栈的区别
       a.栈:存放局部变量的基本数据类型和引用。生命周期随方法而结束。内存空间有限,存取速度快
       b.堆:存放成员变量(包括基本数据类型,引用和引用的对象实体)、局部变量引用指向的对象。运行时动态分配的内存,由Java垃圾回收器来自动管理,存取速度比栈慢
       c.堆是不连续的内存区域,堆空间比较灵活也特别大;栈是一块连续的内存区域,大小是由操作系统决定的
       d.堆的管理很麻烦,频繁地new/remove会造成大量的内存碎片,这样就会慢慢导致效率低下;栈是一种先进后出的数据结构,进出完全不会产生碎片,运行效率高且稳定。
      3.基本概念
       a.栈溢出(StackOverflow):当方法栈的深度大于JVM最大深度的时候,就会栈溢出。例如写一个没有退出的递归就会导致栈溢出(StackOverflow
       b.内存泄漏:长生命周期的对象持有短生命周期的对象的引用很有可能发生内存泄漏
      4.java四种引用类型
       a. 强引用: JVM宁可抛出OOM,也不会回收具有强引用的对象
       b. 软引用: 只有内存不足时候,才会被回收的对象
       c. 弱引用: 在GC时候,一旦发现具有虚引用的对象,不管当前控件是否足够,都会回收它的内存
       d. 虚引用: 任何时候都可以被GC回收,发现是虚引用,就会在回收对象之前把虚引用加入到关联队列中。这个也可是作为判断GC回收Object的标志
      5.垃圾回收的机制
       对象之间可以理解成树形结构,通过树根(GC)作为起点,从这些树根往下搜索,搜索走过的链叫做引用链,当一个对象到GC Roots没有任何引用链相连时,则证明对象不可用,该对象会被判定为可回收的对象
       
       举例说明:
       虚拟栈中的引用对象、方法区常量对象引用、静态属性引用的对象、活着的线程
      6.java对象的销毁
       GC自动地定期扫描Java对象的动态内存,并将所有的引用对象加上标记,在对象运行结束后(无引用变量对该对象进行关联),清除其标记,并将所有无标记的对象作为垃圾进行回收,释放垃圾对象所占的内存空间,对象运行结束后或生命周期结束时,将成为垃圾对象,但并不意味着就立即会被回收,仅当垃圾收集器空闲或内存不足时,才会回收他们。Java中每个对象都拥有一个finalize()方法,垃圾回收器在回收对象时自动调用对象的finalize()方法来释放系统资源.
        
    十五、开机动画的学习   https://www.cnblogs.com/yc-755909659/p/4290114.html(网址的学习)
      1.补间动画效果
        a. alpha :透明度
        b. scale : 渐变尺寸缩放动画效果
        c. translate : 画面转换位置移动动画效果
        d. rotate  : 画面转移旋转动画效果

      2.属性的动画
        a.ValueAnimator :动画的播放次数、播放模式、以及对动画设置监听器等。
        b.AnimatorSet : 这个类为一组特定的动画指定顺序
        c.ObjectAnimator:

      3.共性的属性
        android:repeatCount="-1"
        android:repeatMode="reverse"
        repeatCount:重复次数,无数循环,可以设置为infinite,表示无限的。
        repeatMode:重复运行的模式,默认为restart,每次重复从头开始。可以设置为reverse,表示结束开始之后向前重复运行。

       //setInterpolator设置动画的插入器的
    // Interpolator interpolator = new LinearInterpolator();//// Interpolator interpolator = new AccelerateInterpolator();//先慢后快// Interpolator interpolator = new AnticipateInterpolator();//开始回弹效果
    //    Interpolator interpolator = new BounceInterpolator();//结束回弹效果
    // Interpolator interpolator = new CycleInterpolator(2);//跳一跳效果
    // Interpolator interpolator = new OvershootInterpolator(1);//动画结束时向前弹一定距离再回到原来位置
    // Interpolator interpolator = new AccelerateDecelerateInterpolator();//系统默认的动画效果,先加速后减速
    // Interpolator interpolator = new AnticipateOvershootInterpolator();//开始之前向前甩,结束的时候向后甩
    // Interpolator interpolator = new DecelerateInterpolator();//开始加速再减速
    
    
    JAVA的观察者模式
    Java中观察者模式中主要是Observerable类(被观察者),和Observer接口(观察者)。下面是个简单的demo
    
    public class MyObserverable extends Observable{
        
        //被观察者调用了这个方法,观察者就会发现
        @Override
        protected synchronized void setChanged() {
            // TODO Auto-generated method stub
            super.setChanged();
        }
    
    //被观察者调用了这个方法,就会向观察者发送改变的信息
        @Override
        public void notifyObservers(Object arg) {
            // TODO Auto-generated method stub
            super.notifyObservers(arg);
        }
        
    }


    public class MyObserver implements Observer{
        private String name;
        public MyObserver(String name) {
            this.name=name;
        }
        //一旦被观察者有改变,就会调用update方法
        @Override
        public void update(Observable o, Object arg) {
            System.out.println(name+"观察到 "+arg.toString());
        }
    
    }

     public static void main(String[] args) {
            MyObserver myObserver_1=new MyObserver("observer_1");
            MyObserver myObserver_2=new MyObserver("observer_2");
            
            MyObserverable myObserverable=new MyObserverable();
            //添加2个观察者
            myObserverable.addObserver(myObserver_1);
            myObserverable.addObserver(myObserver_2);
            
            String msg="msg has changed";
            //设置消息改变点
            myObserverable.setChanged();
            //通知观察者改变的消息
            myObserverable.notifyObservers(msg);
        }

        

     
      
       

      

  • 相关阅读:
    php 建立类POST/GET 的HTTP请求
    上传文件
    golang精选100题带答案
    go面试
    golang反射
    go语言中type的几种使用
    写个版本迭代的方法 例如1.0.9 迭代为1.1.0 到10自动往前进1
    压缩文件和解压文件
    go语言中的文件创建,写入,读取,删除
    go面试题
  • 原文地址:https://www.cnblogs.com/liunx1109/p/10919445.html
Copyright © 2020-2023  润新知