| @ -1,38 +0,0 @@ | ||||
| --- | ||||
| Activity | ||||
| --- | ||||
| 
 | ||||
| #### 目录 | ||||
| 
 | ||||
| 1. 思维导图 | ||||
| 2. 基本使用 | ||||
| 
 | ||||
|    - Activity 启动以及生命周期 | ||||
|      - Activity 启动 | ||||
|        - 显式启动 | ||||
|        - 隐式启动 | ||||
|      - 生命周期 | ||||
|        - 正常生命周期 | ||||
|        - 异常生命周期 | ||||
|          - 横竖屏切换 | ||||
|          - 异常退出 | ||||
|    - 启动模式 | ||||
|      - standard | ||||
|      - singleTop | ||||
|      - singleTask | ||||
|      - singleInstance | ||||
|    - 常用回调函数 | ||||
| 
 | ||||
|      - setResult / onActivityResult | ||||
| 
 | ||||
|      - onNewIntent | ||||
|      - onConfigurationChanged | ||||
|      - onSaveInstanceState / onRestoreInstanceState | ||||
|      - onTrimMemory | ||||
|    - 通信交互 | ||||
| 
 | ||||
|      - 与 Activity 通信 | ||||
|      - 与 Fragment 通信 | ||||
|      - 与 Service 通信 | ||||
| 3. 高级玩法 | ||||
|    - 根 Activity 启动流程 | ||||
| @ -0,0 +1,25 @@ | ||||
| --- | ||||
| AsyncTask | ||||
| --- | ||||
| 
 | ||||
| #### 目录 | ||||
| 
 | ||||
| 1. 思维导图 | ||||
| 2. 概述 | ||||
| 3. 具体使用 | ||||
| 4. 源码分析 | ||||
| 5. 参考 | ||||
| 
 | ||||
| #### 思维导图 | ||||
| 
 | ||||
| #### 概述 | ||||
| 
 | ||||
| AsyncTask 是一个轻量级的异步任务类、抽象泛型类。 | ||||
| 
 | ||||
| #### 具体使用 | ||||
| 
 | ||||
| #### 源码分析 | ||||
| 
 | ||||
| #### 参考 | ||||
| 
 | ||||
| [译文:Android中糟糕的AsyncTask](https://droidyue.com/blog/2014/11/08/bad-smell-of-asynctask-in-android/) | ||||
| @ -0,0 +1,172 @@ | ||||
| --- | ||||
| HandlerThread | ||||
| --- | ||||
| 
 | ||||
| #### 目录 | ||||
| 
 | ||||
| 1. 思维导图 | ||||
| 2. 概述 | ||||
| 3. 具体使用 | ||||
| 4. 源码分析 | ||||
| 5. 参考 | ||||
| 
 | ||||
| #### 思维导图 | ||||
| 
 | ||||
| #### 概述 | ||||
| 
 | ||||
| HandlerThread 继承于 Thread,所以它本质就是个 Thread。与普通 Thread 的区别在于,它不仅建立了一个线程,并且创建了消息队列,有自己的 Looper,可以让我们在自己的线程中分发和处理消息,并对外提供自己的 Looper 的 get 方法。 | ||||
| 
 | ||||
| HandlerThread 自带 Looper 使它可以通过消息队列来重复使用当前线程,节省系统资源开销。这是它的优点也是缺点,每个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。 | ||||
| 
 | ||||
| #### 具体使用 | ||||
| 
 | ||||
| ```java | ||||
| public class HandlerThreadActivity extends AppCompatActivity { | ||||
| 
 | ||||
|     private Button mButton; | ||||
|     private HandlerThread mHandlerThread; | ||||
|     private Handler mUiHandler; | ||||
|     private Handler mChildHandler; | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(@Nullable Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_handler); | ||||
|         initView(); | ||||
| 
 | ||||
|         mHandlerThread = new HandlerThread("HandlerThread"); | ||||
|         mHandlerThread.start(); | ||||
|         mUiHandler = new Handler(new Handler.Callback() { | ||||
|             @Override | ||||
|             public boolean handleMessage(Message msg) { | ||||
|                 if (msg.what == 2) { | ||||
|                     mButton.setText("子线程更新"); | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
|         }); | ||||
|         mChildHandler = new Handler(mHandlerThread.getLooper(), new Handler.Callback() { | ||||
|             @Override | ||||
|             public boolean handleMessage(Message msg) { | ||||
|                 if (msg.what == 1) { | ||||
|                     try { | ||||
|                         //子线程模拟延迟处理 | ||||
|                         Thread.sleep(2000); | ||||
|                         mUiHandler.sendEmptyMessage(2); | ||||
|                     } catch (InterruptedException e) { | ||||
|                         e.printStackTrace(); | ||||
|                     } | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public void initView() { | ||||
|         mButton = findViewById(R.id.btn_show); | ||||
|         mButton.setOnClickListener(new View.OnClickListener() { | ||||
|             @Override | ||||
|             public void onClick(View v) { | ||||
|                 mChildHandler.sendEmptyMessage(1); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| #### 源码分析 | ||||
| 
 | ||||
| ```java | ||||
| public class HandlerThread extends Thread { | ||||
|     int mPriority; | ||||
|     int mTid = -1; | ||||
|     Looper mLooper; | ||||
|     private @Nullable Handler mHandler; | ||||
| 
 | ||||
|     public HandlerThread(String name) { | ||||
|         super(name); | ||||
|         mPriority = Process.THREAD_PRIORITY_DEFAULT; | ||||
|     } | ||||
|      | ||||
|     public HandlerThread(String name, int priority) { | ||||
|         super(name); | ||||
|         mPriority = priority; | ||||
|     } | ||||
|      | ||||
|     protected void onLooperPrepared() { | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void run() { | ||||
|         mTid = Process.myTid(); | ||||
|         Looper.prepare(); | ||||
|         synchronized (this) { | ||||
|             mLooper = Looper.myLooper(); | ||||
|             notifyAll(); | ||||
|         } | ||||
|         Process.setThreadPriority(mPriority); | ||||
|         onLooperPrepared(); | ||||
|         Looper.loop(); | ||||
|         mTid = -1; | ||||
|     } | ||||
|      | ||||
|     public Looper getLooper() { | ||||
|         if (!isAlive()) { | ||||
|             return null; | ||||
|         } | ||||
|          | ||||
|         synchronized (this) { | ||||
|             while (isAlive() && mLooper == null) { | ||||
|                 try { | ||||
|                     wait(); | ||||
|                 } catch (InterruptedException e) { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return mLooper; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public Handler getThreadHandler() { | ||||
|         if (mHandler == null) { | ||||
|             mHandler = new Handler(getLooper()); | ||||
|         } | ||||
|         return mHandler; | ||||
|     } | ||||
| 
 | ||||
|     public boolean quit() { | ||||
|         Looper looper = getLooper(); | ||||
|         if (looper != null) { | ||||
|             looper.quit(); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     public boolean quitSafely() { | ||||
|         Looper looper = getLooper(); | ||||
|         if (looper != null) { | ||||
|             looper.quitSafely(); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     public int getThreadId() { | ||||
|         return mTid; | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 源码很简单,就是在 run 方法中执行 Looper.prepare()、Looper.loop() 构造消息循环系统。外界可以通过 getLooper() 这个方法拿到这个 Looper。 | ||||
| 
 | ||||
| 总结为下: | ||||
| 
 | ||||
| 1. HandlerThread 是一个自带 Looper 的线程,因此只能作为子线程使用 | ||||
| 2. HandlerThread 必须配合 Handler 使用,HandlerThread 线程中具体做什么事,需要在 Handler 的 callback 中进行,因为它自己的 run 方法被写死了 | ||||
| 3. 子线程的 Handler 与 HandlerThread 关系建立是通过构造子线程的Handler 传入 HandlerThread 的 Looper 。所以在此之前,必须先调用 mHandlerThread.start 让 run 方法跑起来 Looper 才能创建。 | ||||
| 
 | ||||
| #### 参考 | ||||
| 
 | ||||
| [Android中的线程形态(二)(HandlerThread/IntentService)](https://www.jianshu.com/p/4ca760e5040b) | ||||
| @ -0,0 +1,194 @@ | ||||
| --- | ||||
| IntentService | ||||
| --- | ||||
| 
 | ||||
| #### 目录 | ||||
| 
 | ||||
| 1. 思维导图 | ||||
| 2. 概述 | ||||
| 3. 具体使用 | ||||
| 4. 源码分析 | ||||
| 5. 参考 | ||||
| 
 | ||||
| #### 思维导图 | ||||
| 
 | ||||
| #### 概述 | ||||
| 
 | ||||
| IntentService 是继承于 Service 并处理异步请求的一个类,内部实现是 HandlerThread,处理完子线程的事后自动 stopService。 | ||||
| 
 | ||||
| #### 具体使用 | ||||
| 
 | ||||
| 首先创建: | ||||
| 
 | ||||
| ```java | ||||
| public class MyIntentService extends IntentService { | ||||
| 
 | ||||
|     private static final String TAG = "MyIntentService"; | ||||
| 
 | ||||
|     public MyIntentService() { | ||||
|         //IntentService 工作线程的名字 | ||||
|         super("MyIntentService"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         Log.i(TAG, "onCreate: "); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int onStartCommand(@Nullable Intent intent, int flags, int startId) { | ||||
|         Log.i(TAG, "onStartCommand: "); | ||||
|         return super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         Log.i(TAG, "onDestroy: "); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onHandleIntent(@Nullable Intent intent) { | ||||
|         if (intent != null) { | ||||
|             String taskName = intent.getStringExtra("taskName"); | ||||
|             Log.i(TAG, "onHandleIntent: " + taskName); | ||||
|             switch (taskName) { | ||||
|                 case "task1": | ||||
|                     //任务一 | ||||
|                     try { | ||||
|                         Thread.sleep(3000); | ||||
|                     } catch (InterruptedException e) { | ||||
|                         e.printStackTrace(); | ||||
|                     } | ||||
|                     break; | ||||
|                 case "task2": | ||||
|                     //任务二 | ||||
|                     break; | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Activity 中: | ||||
| 
 | ||||
| ```java | ||||
|     public void onClick(View v) { | ||||
|         Intent intent = new Intent(this, MyIntentService.class); | ||||
|         switch (v.getId()) { | ||||
|             case R.id.btn1: | ||||
|                 intent.putExtra("taskName", "task1"); | ||||
|                 startService(intent); | ||||
|                 break; | ||||
|             case R.id.btn2: | ||||
|                 intent.putExtra("taskName", "task2"); | ||||
|                 startService(intent); | ||||
|                 break; | ||||
|             default: | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| ``` | ||||
| 
 | ||||
| 这里如果点击按钮一后立马点击按钮二,日志打印如下: | ||||
| 
 | ||||
| ``` | ||||
| onCreate、onStartCommand、onHandleIntent: task1、 | ||||
| onStartCommand、onHandleIntent: task2、onDestroy | ||||
| ``` | ||||
| 
 | ||||
| 如果是等三秒后再点击按钮二,就是: | ||||
| 
 | ||||
| ``` | ||||
| onCreate、onStartCommand、onHandleIntent: task1、onDestroy、 | ||||
| onCreate、onStartCommand、onHandleIntent: task2、onDestroy | ||||
| ``` | ||||
| 
 | ||||
| 这下就清楚了吧。 | ||||
| 
 | ||||
| #### 源码分析 | ||||
| 
 | ||||
| ```java | ||||
| public abstract class IntentService extends Service { | ||||
|     private volatile Looper mServiceLooper; | ||||
|     private volatile ServiceHandler mServiceHandler; | ||||
|     private String mName; | ||||
|     private boolean mRedelivery; | ||||
| 
 | ||||
|     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); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public IntentService(String name) { | ||||
|         super(); | ||||
|         //IntentService 的线程名 | ||||
|         mName = name; | ||||
|     } | ||||
| 
 | ||||
|     public void setIntentRedelivery(boolean enabled) { | ||||
|         mRedelivery = enabled; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); | ||||
|         thread.start(); | ||||
| 		 | ||||
|         //构造子线程 Handler | ||||
|         mServiceLooper = thread.getLooper(); | ||||
|         mServiceHandler = new ServiceHandler(mServiceLooper); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onStart(@Nullable Intent intent, int startId) { | ||||
|         Message msg = mServiceHandler.obtainMessage(); | ||||
|         msg.arg1 = startId; | ||||
|         msg.obj = intent; | ||||
|         //在 Service 启动的时候发送消息,子线程开始工作 | ||||
|         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() { | ||||
|         mServiceLooper.quit(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @Nullable | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @WorkerThread | ||||
|     protected abstract void onHandleIntent(@Nullable Intent intent); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 总结如下: | ||||
| 
 | ||||
| 1. Service onCreate 的时候通过 HandlerThread 构建子线程的 Handler | ||||
| 2. Service onStartCommand 中通过子线程 Handler 发送消息 | ||||
| 3. 子线程 handlerMessage 中调用我们重写的 onHandlerIntent 执行异步任务,执行完之后 Service 销毁 | ||||
| 
 | ||||
| #### 参考 | ||||
| @ -0,0 +1,18 @@ | ||||
| --- | ||||
| 屏幕适配 | ||||
| --- | ||||
| 
 | ||||
| #### 目录 | ||||
| 
 | ||||
| 1. 思维导图 | ||||
| 2. 适配方案 | ||||
| 3. 参考 | ||||
| 
 | ||||
| #### 思维导图 | ||||
| 
 | ||||
| #### 适配方案 | ||||
| 
 | ||||
| #### 参考 | ||||
| 
 | ||||
| [一种极低成本的Android屏幕适配方式](https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA) | ||||
| 
 | ||||
| Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 135 KiB | 
| Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB | 
| Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB | 
| After Width: | Height: | Size: 76 KiB | 
| Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB | 
| Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB | 
| Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB | 
| Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB | 
| Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 153 KiB | 
| Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB | 
| Before Width: | Height: | Size: 285 KiB After Width: | Height: | Size: 285 KiB | 
| Before Width: | Height: | Size: 191 KiB After Width: | Height: | Size: 191 KiB | 
| Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB | 
| Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB | 
| Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 155 KiB | 
| Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB | 
| Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB | 
| Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB | 
| Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB | 
| Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |