android开发问题总结

加载图片过大超出内存

解决办法:
	缩放图片,在进行加载(将图片缩放至屏幕大小)
	计算缩放比例
		获取图片宽高
		获取屏幕宽高
		图片宽比宽获取宽的缩放比例
		图片高比高获取高的缩放比例
		宽高的缩放比例采用统一个值, 使用大的那个
	缩放方法
	//使用Bitmapfactory.Options
	OPtions opts = new Options ();
	opts.inJustDecodeBounds = true ;
	BitmapFactory.decodeFile("图片",opts);
	//设置为true时,BitmapFactory的decodeFile(String path,Options opt)并不会返回一个Bitmap对象,但是会返回图片的小 (宽、高)
	//拿到图片的宽高
	int width = opts.outWidth;
	int height = opts.outHeight;

	//设置缩放比例
	opts.inSampleSize = scale;
	opts.inJustDecodeBounds = false;
	Bitmap bm = BitmapFactory.decodeFile("sdcard/Download/hello.png", opts);

线程池

  • 线程池的优点:
    1、可复用线程,避免了线程的频繁创建与消亡,带来的性能上的开销
    2、能够让线程得到统一的管理
    3、能够避免创建过多的线程,线程间抢占资源,内存不足造成卡顿
    4、可控制最大的并发线程数,提高系统的资源的利用率
  • 常见的线程池
    • ThreadPoolExecutor:最基础的线程池,下面几种都是通过ThreadPoolExecutor变种而来。
      • 创建线程池
        	/**
             * 参数介绍
             *
             * @param corePoolSize 核心线程数 (核心线程会一直在线程池中存活,一旦有任务时,会立即处理任务)
             * @param maximumPoolSize 线程池中最大的线程数(核心线程数 + 非核心线程数(非核心线程:当任务队列满载状态,才会创建一个非核心线程去处理任务,当再次满载再创建一个非核心线程...))
             * @param keepAliveTime 非核心线程的存活时长 (是非核心线程执行完任务后等待下一个任务到来的空闲时长)
             * @param unit 非核心线程存活的时长单位
             * @param workQueue 线程池中存放的任务队列 
             * @param threadFactory 对线程池中的线程进行一些设定 (线程名...可有可无)
             * @param handler 拒绝策略(当任务队列满载,且已达最大线程数时,再有任务加入会执行拒绝策略)
             */
        	ThreadPoolExecutor threadPool = 
        	new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, 
        long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
        
        	//执行任务,当调用完extcute之后,才会进入runnable执行任务
        	threadPool.extcute(Runnable runnable);
        
    • FixedThreadPool:只有核心线程,并且任务队列无满载状态。适用于执行长期任务
      • 创建线程池:
        	ExecutorService fixedThreadPool = Executor.newFixedThreadPool(核心线程数);
        	//其实内部是通过ThreadPoolExecutor(corePoolSize,corePoolSize,0,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()),
        
        	//执行任务
        	fixedThreadPool.execute(Runnable runnable);
        
    • CachedThreadPool:该线程池没有核心线程,只有非核心线程,并且非核心线程的存活时长为60s,以及无最大线程数(Integer.MAX_VALUE)。适用于执行为数较多的耗时短的任务
      • 创建线程池:
        	ExecutorService cachedThreadPool = Executors.newCachedThreadPool()
        	//其实内部是通过ThreadPoolExecutor(0,Integer.MAX_VALUE,0,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>()),
        
            //执行任务
            cachedThreadPool.execute(Runnable runnable)
        
    • SingleThreadPool:该线程池中只有1核心线程,无非核心线程,当多个任务同时添加时,无空闲线程则会将任务放到任务队列中排队等待执行。适用于一个一个的任务场景
      • 创建线程池:
        	ExecutorService singleThreadPool = Executors.newSingleThreadPool()
        	//其实内部是通过ThreadPoolExecutor(1,1,0,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()),
        
          	//执行任务
          	singleThreadPool.execute(Runnable runnable)
        
    • ScheduledThreadPool:该线程池可设置核心线程数,无最大线程数(Integer.MAX_VALUE),线程存活时长为0,非核心线程空闲立马被回收。适用于周期性执行任务,延迟执行任务
      • 创建线程池:
        	ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(核心线程数)
        	//其实内部是通过ThreadPoolExecutor(corePoolSize,Integer.MAX_VALUE,0,TimeUnit.MILLISECONDS,new DelayedWorkQueue<Runnable>()),
        
          	//延迟执行一次任务
          	scheduledThreadPool.schedule(runnable,延迟执行任务时长,时长单位)
          	//首次执行任务延迟一定时长,后面每间隔一定时长触发任务
            scheduledThreadPool.scheduleAtFixedRate(runnable,首次执行任务延迟时长,后面循环任务每间隔时长执行任务,时长单位)
            //首次执行任务延迟一定时长,后面每次会延迟一定时长后再执行任务
            scheduledThreadPool.scheduleWithFixedDelay(runnable,首次执行任务延迟时长,后面循环任务会每次延迟时长执行任务,时长单位)
        
  • 执行任务的submit()和execture()的两个方法的区别:submit首先会将执行的任务Runnable打包成RunnableFuture,然后在调用execture并把RunnableFuture传到execture中,最后,submit会把打包好的RunnableFuture返回,而execture是无返回值的
  • 关闭线程池:shutDown、shutDownNow两种方法
    • shutDown:关闭线程池,可能线程池中还存有正在执行的任务,不会去中断,只是关闭后无法在往此线程池中添加任务了
    • shutDownNow:关闭线程池,同时会中断线程池中正在执行的任务
  • 四种拒绝策略:
    • AbortPolicy:会拒绝任务加入,并且抛出RejectedExecutionException异常
    • DiscardPolicy:会拒绝任务加入,不抛异常
    • DiscardOldestPolicy:会抛弃队列最前的任务,然后将此任务放到队列中
    • CallerRunsPolicy:该任务被线程池拒绝,会交由当前调用execute方法开启任务的线程去执行该任务

Handler消息机制

  • 消息机制的流程:
    1、创建一个handler对象,重写其中的handleMessage方法
    2、每个线程在使用Handler时都需要绑定对应的且唯一的Looper对象,主线程在启动的时候系统已经帮我们主动调用Looper.parper()去初始化一个Looper对象,子线程需要开发手动去调用Looper.parper()为当前线程绑定自己的Looper对象。
    为什么在线程中使用handler需要绑定Looper对象呢?
    ①在new Handler()时,在构造方法中会去拿当前的Looper对象,如果没有会直接抛异常
    ②同时在构造方法中会将通过Looper构造方法中创建的消息队列取出,在发送消息时,需要将消息放到队列中,如果无法拿到对应的消息队列,直接抛异常

    public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
    	// 获取当前的Looper对象
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        // 取出创建好的消息队列
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    

    唯一体现在,调用prepare()时,第一步会从ThreadLocal中获取当前线程的Looper对象,如果存在则直接抛异常,不存在才继续往下new Looper(),并保存到ThreadLocal中,实现线程与Looper的绑定

    //Looper.prepare()
    public static void prepare() {
        prepare(true);
    }
    
    //初始化Looper对象
    private static void prepare(boolean quitAllowed) {
    	//如果当前线程中已经绑定了Looper,又重新创建一个新的Looper则抛异常,所以一个线程只有一个Looper对象
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
    // sThreadLocal.get() 和sThreadLocal.set()都会以当前线程为唯一准则
    

    3、通过Looper.loop()方法开启循环遍历消息队列获取消息,在其内部首先会去获取当前线程的Looper对象通过myLooper(),如果当前线程未绑定Looper,则会抛异常。然后会通过绑定的Looper对象获取其内部的消息队列,然后通过一个无线for循环,不断的通过queue.next()获取队列中的消息,如果拿到的消息不为null,最终会通过msg.target.dispatchMessage(msg)分发消息,msg.target <==> handler,通过到Message类中可以发现target就是Handler的引用,所以dispatchMessage其实是调用了Handler中的方法,在dispatchMessage中会调用handlerMessage(msg),即回到我们自定义Handler中的handlerMessage方法中处理消息。
    在这里插入图片描述

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        if (me.mInLoop) {
            Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
        }
    
        me.mInLoop = true;
        final MessageQueue queue = me.mQueue;
        
    	// ...省略一段代码
    	
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
    
            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            // Make sure the observer won't change while processing a transaction.
            final Observer observer = sObserver;
    
            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
    
            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;
    
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
    
            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            Object token = null;
            if (observer != null) {
                token = observer.messageDispatchStarting();
            }
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                msg.target.dispatchMessage(msg);
                if (observer != null) {
                    observer.messageDispatched(token, msg);
                }
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } catch (Exception exception) {
                if (observer != null) {
                    observer.dispatchingThrewException(token, msg, exception);
                }
                throw exception;
            } finally {
                ThreadLocalWorkSource.restore(origWorkSource);
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
            }
    
            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }
    
            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }
    
            msg.recycleUnchecked();
        }
    }
    

    4、如果消息队列中取到的Message对象不为null,调用msg.target.dispatchMessage(msg),msg.target就是handler对象,然后调用handler的dispatchMessage()内部会调handleMessage(),后面消息交由handler.handleMessage(msg)方法处理消息

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    

    5、发送消息,我们通过handler.sendMessage(msg)发送消息,其实内部调用的是sendDelayMessage(msg,0)方法,给延迟发送消息时间设置为0,之后在内部调用了sendMessageAtTime(),在该方法内部又调用了enqueueMessage(),在该方法内部会把当前handler对象传到Message.trager变量中msg.traget = this;然后将msg发送的消息对象,uptimeMillis更新时长,传入一个queue消息队列中通过queue.enqueueMessage();存放到消息队列中

    //handler.sendMessage()
    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }
    
    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        //msg.target 为当前handler对象
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();
    
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //将消息存放到消息队列中
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    

    6、消息队列的排序规则: 首先看Message对象里面是存放next:Message下一个执行的消息;

    boolean enqueueMessage(Message msg, long when) {
    		//..........省略不关心代码
    		
                //  1、设置添加的消息等待时常
                msg.when = when; 
                //  2、保存即将要处理的消息
                Message p = mMessages;
                
                boolean needWake;
    
    			//  3、当即将处理的消息不存在/准备添加的消息是立即执行/准备添加的消息等待时常<即将处理消息的等待时常,都会将消息添加到队列第一位
                if (p == null || when == 0 || when < p.when) {
                    //  4、将之前准备要执行的消息指向到要被添加的消息的next上
                    msg.next = p;
                    //  5、将添加的消息,指向到全局消息变量,表示即将要被执行的消息,及队列第一位
                    mMessages = msg;
                    needWake = mBlocked;
                } else {
                    needWake = mBlocked && p.target == null && msg.isAsynchronous();
                    Message prev;
                    
                    //  6、遍历所有消息,进入else中的消息指定不是在队列首位,取出每个Message.next的时常与添加的消息时常比较,时常小的,就会把遍历到的Message.next 指向于当前添加的Message,再将添加的Message.next指向于之前的Message
                    for (;;) {
                        prev = p;
                        p = p.next;
                        if (p == null || when < p.when) {
                            break;
                        }
                        if (needWake && p.isAsynchronous()) {
                            needWake = false;
                        }
                    }
                    msg.next = p; // invariant: p == prev.next
                    prev.next = msg;
                }
    
                // We can assume mPtr != 0 because mQuitting is false.
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
        }
    
  • 补充:
    1、发送消息也可以通过handler.post(Runnable r),这种方式是传入一个Runnable对象,在post内部会调用getPostMessage®返回一个Message对象,在getPostMessage方法里面会将runnable对象存放到 Runnable callback变量中,返回一个message对象后,接着调用sendDelayMessage方法后面与上面流程基本一致。到了处理消息的地方dispatchMessage(),首先会去判断msg.callback不为null,直接msg.callback.run()。
    2、保证一个线程只有一个Looper对象:因为在每次创建新的Looper对象时,都需要去ThreadLocal里面检查当前线程是否存在Looper对象,如果存在则抛出异常,于此同时,只有在创建Looper对象时,在Looper的构造方法中去创建MessageQueue消息队列
    3、 任何线程都可以实例化Handler,只是任意线程只能有唯一的一个Looper对象进行绑定
    4、关于Looper.loop()是一个阻塞的死循环,为什么主线程不会被ANR:在activity的生命周期、点击事件等都是通过主线程的Looper对象不断去消息队列中取消息,然后做不同的处理,如果当前正在处理一个消息,接着又来了另一个消息,但是当前的消息未处理完,导致Looper.loop()循环被卡住,无法正常的去获取下一个消息去处理,就会导致界面卡顿,卡顿时间长就造成了ANR,所以loop循环可能会阻塞主线程,但是一旦有消息写入,loop能够立即获取到,然后处理消息,就不会造成ARN,当消息队列中没有消息时,主线程会被阻塞进入休眠状态,会释放当前的cpu资源

几种异步方式的区别

  • AsyncTask:使用AsyncTask需要继承它,并且需要传入泛型<doInBackGround的参数类型,onProgressUpdate的参数类型,doInBackGround的返回值类型、onPostExecture的参数类型>

    • onPreExecute():执行在主线程中,一般处理准备异步操作前的准备工作
    • doInBackGround():执行在子线程中,处理异步操作的任务
    • onPostExecute():执行在主线程中,异步操作执行完成后(doInBackGround)调用,可以进行界面刷新操作
    • onProgressUpdate():当在doInBackGround中调用publishProgress时,才会执行在主线程中。可在doInBackGround()中调用publishProgress()来更新当前任务执行的进度
    • 总结:AsyncTask是一个抽象的类,子类需要继承它,构造方法有三种重载方式,无参/传handle/传looper,最终都是调用传Looper的方式,并根据传入的Looper对象创建Handler;无参的构造方法默认调用传Looper的构造方法,并使用主线程的Looper对象;传handler的构造方法,最终也是调用传Looper对象的构造方法,并通过传入的handler获取其绑定的Looper对象;
      当执行execute(Params... params),该方法会一次只能运行一个任务,当存在运行中的任务时,又去执行下一个任务会抛异常,接着会执行onPreExecute(),此时还在主线程中执行,随即将任务FutureTask也是Runnable对象放到线程池中,之后任务被执行后,会回调到WorkerRunnable.call,在内部执行doInBackground方法,在doInBackground中执行我们的任务逻辑,当任务执行完毕后,将结果作为postResult(result)的参数,在postResult中通过之前创建的handler将执行的结果发送到指定线程中执行AsyncTask.finish(result),在方法内执行onPostExecute(result);我们可以在doInBackground中执行publishProgress来更新任务执行的进度,在publishProgress方法中会通过hanlder发送MESSAGE_POST_PROGRESS到指定线程中更新进度消息,然后回调AsyncTask.onProgressUpdate
      当执行AsyncTask.execute(runnable),会将runnable任务直接放到线程池中,不会回调onPreExecute、doInBackGround、onPostExecute;
    • 补充:
      1、onPreExecute执行代码:
      /**
      	外部通过asyncTask对象执行任务
      */
      @MainThread
      public final AsyncTask<Params, Progress, Result> execute(Params... params) {
          return executeOnExecutor(sDefaultExecutor, params);
      }
      	
      @MainThread
      public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
              Params... params) {
      
      	// 坚持当前是否有正在执行的任务,存在就抛异常
          if (mStatus != Status.PENDING) {
              switch (mStatus) {
                  case RUNNING:
                      throw new IllegalStateException("Cannot execute task:"
                              + " the task is already running.");
                  case FINISHED:
                      throw new IllegalStateException("Cannot execute task:"
                              + " the task has already been executed "
                              + "(a task can be executed only once)");
              }
          }
      
          mStatus = Status.RUNNING;
      	
      	// 在主线程中回调onPreExecute,可做异步前的准备工作
          onPreExecute();
      
          mWorker.mParams = params;
      
      	// 封装一个FutureRunnable对象也是runnable对像,放到线程池中
          exec.execute(mFuture);
          return this;
      }
      
      2、doInBackground的代码执行:
      	/** 
        		当任务执行到 exec.execute(mFuture)的mFuture时,会回调FuturnRunnable.run(),
        		然后会回调mFuture.WorkerRunnable.call回调
      	*/
      	public AsyncTask(@Nullable Looper callbackLooper) {
          mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
              ? getMainHandler()
              : new Handler(callbackLooper);
      
          mWorker = new WorkerRunnable<Params, Result>() {
              public Result call() throws Exception {
                  mTaskInvoked.set(true);
                  Result result = null;
                  try {
                      Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                      
                      // 业务处理任务逻辑
                      result = doInBackground(mParams);
                      Binder.flushPendingCommands();
                  } catch (Throwable tr) {
                      mCancelled.set(true);
                      throw tr;
                  } finally {
                  	
                  	// 内部会通过构建的handler,将任务执行的结果发送到指定线程中回调onPostExecute
                      postResult(result);
                  }
                  return result;
              }
          };
      
          mFuture = new FutureTask<Result>(mWorker) {
              @Override
              protected void done() {
                  try {
                      postResultIfNotInvoked(get());
                  } catch (InterruptedException e) {
                      android.util.Log.w(LOG_TAG, e);
                  } catch (ExecutionException e) {
                      throw new RuntimeException("An error occurred while executing doInBackground()",
                              e.getCause());
                  } catch (CancellationException e) {
                      postResultIfNotInvoked(null);
                  }
              }
          };
      }
      
      3、onProgressUpdate代码执行逻辑:
      /**
      	可在doInBackground回调中调用publishProgress来更新进度
      */
      @WorkerThread
      protected final void publishProgress(Progress... values) {
          if (!isCancelled()) {
          	
          	// 通过handler发送更新进度到消息到指定的线程中,最终会回调AsyncTask.onProgressUpdate(result.mData)
              getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                      new AsyncTaskResult<Progress>(this, values)).sendToTarget();
          }
      }
      
      4、onPostExecute代码执行逻辑:
       private Result postResult(Result result) {
      
           @SuppressWarnings("unchecked")
           Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                   new AsyncTaskResult<Result>(this, result));
           message.sendToTarget();
           return result;
       }
      
       private static class InternalHandler extends Handler {
           public InternalHandler(Looper looper) {
               super(looper);
           }
      
           @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
           @Override
           public void handleMessage(Message msg) {
               AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
               switch (msg.what) {
               	
               	// 处理执行任务结束消息
                   case MESSAGE_POST_RESULT:
                       // There is only one result
                       result.mTask.finish(result.mData[0]);
                       break;
      
       			// 处理更新任务执行进度消息
                   case MESSAGE_POST_PROGRESS:
                       result.mTask.onProgressUpdate(result.mData);
                       break;
               }
           }
       }
      
       // 会在消息处理handleMessage执行
       private void finish(Result result) {
       if (isCancelled()) {
           onCancelled(result);
       } else {
       	// 回调onPostExecute
           onPostExecute(result);
       }
       mStatus = Status.FINISHED;
      }
      
  • HandlerThread:内部继承了Thread,本身就是一个线程,实现run方法,通过HandlerThread.startThread()开启线程,在run()内部维护了一个Looper对象,通过Looper.loop()不断循环消息队列,通过handler发送消息任务进行处理。
    用法:
    1、创建一个new HandlerThread("线程名称")对象
    2、HandlerThread.startThread()开启线程
    3、HandlerThread内部构建一个Handler new Handler(HandlerThread.getLooper())用于发送任务消息到子线程中处理,因为关联上HandlerThread当前线程的Looper对象,以至于Handler中的消息处理是在子线程中
    4、通过HandlerThread.getThreadHandler()获取到handler进行任务的发送
    5、通过HandlerThread.quit()关闭Looper.loop()退出任务,在退出前先移除消息队列中的消息

  • IntentService:是一个抽象的可以执行耗时操作的Service,且任务结束后自动关闭服务,在IntentService内部,维护了一个ServiceHandler(就是继承了Handler,且是绑定了子线程Looper)和一个HandlerThread。
    实现原理就是通过开启一个HandlerThread的一个子线程,创建一个Handler绑定子线程的Looper,通过handler将消息发送到子线程中处理,在handleMessage中回调抽象方法onHandleIntent,交由业务层实现任务逻辑,当任务结束后,执行service的stopSelf()关闭当前服务,并会停止loop轮训

    	// 绑定了子线程的looper对象,将任务消息发送到handleMessage中执行onHandleIntent回调执行任务逻辑
    	private final class ServiceHandler extends Handler {
            public ServiceHandler(Looper looper) {
                super(looper);
            }
    
            @Override
            public void handleMessage(Message msg) {
                onHandleIntent((Intent)msg.obj);
                // 任务执行完毕后,关闭服务
                stopSelf(msg.arg1);
            }
        }
    	
    	@Override
        public void onCreate() {
            // TODO: It would be nice to have an option to hold a partial wakelock
            // during processing, and to have a static startService(Context, Intent)
            // method that would launch the service & hand off a wakelock.
    
            super.onCreate();
            // 开启子线程,并为handler提供子线程Looper对象
            HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
            thread.start();
    
            mServiceLooper = thread.getLooper();
            mServiceHandler = new ServiceHandler(mServiceLooper);
        }
        	
        @Override
        public void onStart(@Nullable Intent intent, int startId) {
        	// 构建任务消息,用于执行任务回调方法onHandleIntent
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            mServiceHandler.sendMessage(msg);
        }
        	
        @Override
        public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
            onStart(intent, startId);
            return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
        }
    
        @Override
        public void onDestroy() {
        	// HandleThread的run方法中,开启了Looper轮询,导致HandleThread子线程无法停止,所以,HandleThread需要
        	// 在合适的地方关闭Looper循环
            mServiceLooper.quit();
        }
    
    	@WorkerThread
    	protected abstract void onHandleIntent(@Nullable Intent intent);
    

    1、需要继承IntentService类,实现onHandleIntent(),在这里面可执行耗时操作。同时需要在构造方法中调用super(name),作用是给当前的线程定义一个名称,必须调用,否则会报错
    2、开启IntentService和正常的service开启方式一样,startService()开启

ANR的原因

  • activity耗时操作超过5s
  • broadcastReceiver耗时操作超过10s
  • service耗时操作超过20s

内存优化

  • 内存泄漏
    • 单例造成的泄漏:(单例的静态特性,使其生命周期和应用的生命周期一样长,如果一个对象的已经没有用了,但是单例还持有引用,那么就会造成该对象无法被正常释放)
    • 静态变量造成的泄漏:(静态变量的随着类加载就已经存在方法区,直到应用退出才被销毁,所以静态变量持有了短生命周期对象引用导致,短生命周期的引用本该销毁时,却被长生命周期引用所持有,无法释放)解决方案可在适当时机置空
    • 非静态内部类持有外部类的引用:(非静态内部类会默认持有外部类的引用this,当内部类生命周期长于外部类,导致外部类无法被正常释放) 典型场景Handler的使用、new Thread()、AsyncTask 、Timer和TimerTask页面销毁时及时cancel掉任务
    • 集合中添加对象未及时清理
    • bitmap不用时回收资源(bitmap.recycle)
    • 加载大图时,尽量使用Options压缩一下
    • 资源使用后未关闭(IO、Sqlite、File)
    • 属性动画造成的泄漏:(当界面销毁,需要将动画及时cancel)
    • WebView造成的泄漏:解决方案WebView尽量在代码中创建,减少布局中使用,页面销毁时,先从容器中remove控件,然后 调用webView.destory
    • 监听器的注册与反注册动态注册广播,页面关闭时需要取消注册广播、注册观察者模式也需要及时取消注册
  • 减少枚举使用
    • 原因:枚举占用的内存比较大
  • 尽可能使用优化过的数据容器(SparseArray、SparseBooleanArray、LongSparseArray代替HashMap)
    • 原因: 相比HashMap占用的内存更低
  • 布局优化
    • 减少布局的嵌套,提高布局绘制性能
    • 删除不必要的背景
    • 布局中尽量使用include、merge、ViewStub(include:布局服用;merge:减少布局层级;ViewStub:当需要时才会去加载)
    • 自定义view时,避免在onDraw中创建大量的临时变量,会频繁调用GC,造成内存抖动
  • ListView使用注意点:
  • 考虑条目复用convertView,使用ViewHolder
  • 展示大量数据时,建议分页加载、分段加载
  • 可以通过RecyclerView来替代

多进程

  • 优点:
    1、可以最大限度的获取系统资源,毕竟系统为每个进程分配的资源有限
    2、进程间资源隔离,当前进程挂掉也不影响其他进程,很适合 Service 或一些辅助业务模块
  • 缺点:
    1、静态成员和单例模式失效(不同进程访问同一个类会产生多个副本)
    2、线程同步机制失效 (不同进程锁的不是同个对象)
    3、SharedPreferences 可靠性下降 (并发写操作,会造成丢数据)
    4、Application 会多次创建 (每启动一个进程都会被分配一个新的虚拟机)

动态换肤技术

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值