├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── aidl │ └── me │ │ └── wcy │ │ └── app │ │ └── IUserInterface.aidl │ ├── java │ └── me │ │ └── wcy │ │ └── app │ │ ├── AidlDemoActivity.kt │ │ ├── BlockingQueueActivity.kt │ │ ├── CoroutineActivity.kt │ │ ├── FlowDemoActivity.kt │ │ ├── MainActivity.kt │ │ ├── MainViewModel.kt │ │ ├── RxJavaDemoActivity.kt │ │ ├── ViewBindingEx.kt │ │ ├── aidl │ │ └── UserService.kt │ │ ├── asynclayout │ │ ├── AsyncLayoutActivity.kt │ │ ├── AsyncLayoutFragment.kt │ │ ├── AsyncLayoutHelper.kt │ │ ├── AsyncLayoutInflaterEx.kt │ │ └── FakeView.kt │ │ ├── dialogfragment │ │ ├── DialogFragmentActivity.kt │ │ ├── TestDialog.kt │ │ └── TestFragment.kt │ │ └── viewlifecycle │ │ ├── LifecycleView.kt │ │ └── ViewLifecycleActivity.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_async_layout.xml │ ├── activity_blocking_queue.xml │ ├── activity_coroutine.xml │ ├── activity_dialog_fragment.xml │ ├── activity_main.xml │ ├── activity_rxjava_demo.xml │ ├── activity_view_lifecycle.xml │ ├── fragment_complex.xml │ ├── fragment_complex_placeholder.xml │ └── fragment_dialog.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── code ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ └── java │ └── me │ └── wcy │ └── code │ ├── array │ ├── Move_Zeroes.java │ └── Rotate_Image.java │ ├── dynamic_programming │ ├── Coin_Change.java │ ├── Jump_Game.java │ ├── Longest_Increasing_Subsequence.java │ └── Unique_Paths.java │ ├── linkedlist │ ├── Deep_Clone_Node.java │ ├── ListNode.java │ ├── Odd_Even_Linked_List.java │ └── Reverse_Linked_List.java │ ├── sort │ └── QuickSort.java │ ├── string │ ├── Increasing_Triplet_Subsequence.java │ ├── Longest_Palindromic_Substring.java │ └── Longest_Substring_Without_Repeating_Characters.java │ └── trees │ ├── Binary_Tree_Level_Order_Traversal.java │ ├── Binary_Tree_Zigzag_Level_Order_Traversal.java │ ├── Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.java │ ├── Kth_Smallest_Element_in_a_BST.java │ ├── Populating_Next_Right_Pointers_in_Each_Node.java │ └── TreeNode.java ├── doc ├── algorithm │ ├── algorithm.md │ └── leetcode.md ├── android │ ├── android.md │ └── image │ │ ├── activity_lifecycle.jpg │ │ ├── touch_event_consume.jpg │ │ ├── touch_event_not_consume.jpg │ │ ├── tween_animation.png │ │ ├── view_draw_process.jpg │ │ └── view_model.webp ├── java │ ├── image │ │ └── hashmap.jpg │ └── java.md ├── network │ ├── image │ │ ├── sliding_window.jpg │ │ └── tcp_ip.jpg │ └── network.md ├── os │ └── os.md └── resume │ ├── introduce.md │ └── resume.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # android-interview 2 | 3 | Android面试要点 4 | 5 | 1. [Android](https://github.com/wangchenyan/android-interview/blob/master/doc/android/android.md) 6 | 7 | 2. [Java](https://github.com/wangchenyan/android-interview/blob/master/doc/java/java.md) 8 | 9 | 3. [数据结构与算法](https://github.com/wangchenyan/android-interview/blob/master/doc/algorithm/algorithm.md) 10 | 11 | 4. [操作系统](https://github.com/wangchenyan/android-interview/blob/master/doc/os/os.md) 12 | 13 | 5. [计算机网络](https://github.com/wangchenyan/android-interview/blob/master/doc/network/network.md) 14 | 15 | 6. [算法题](https://github.com/wangchenyan/android-interview/blob/master/doc/algorithm/leetcode.md) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion 30 6 | 7 | defaultConfig { 8 | applicationId "me.wcy.app" 9 | minSdkVersion 23 10 | targetSdkVersion 30 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | 22 | viewBinding { 23 | enabled = true 24 | } 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(dir: 'libs', include: ['*.jar']) 29 | implementation 'androidx.core:core-ktx:1.3.2' 30 | implementation 'androidx.appcompat:appcompat:1.2.0' 31 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' 32 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' 33 | implementation 'androidx.fragment:fragment-ktx:1.2.0-rc05' 34 | implementation 'androidx.constraintlayout:constraintlayout:2.1.1' 35 | implementation 'androidx.asynclayoutinflater:asynclayoutinflater:1.0.0' 36 | implementation 'com.squareup.okhttp3:okhttp:4.9.0' 37 | implementation 'io.reactivex.rxjava2:rxjava:2.2.20' 38 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' 39 | implementation 'com.github.mthli:RxCoroutineSchedulers:v2.0.3' 40 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' 41 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' 42 | implementation 'com.facebook.fresco:fresco:2.5.0' 43 | } 44 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/aidl/me/wcy/app/IUserInterface.aidl: -------------------------------------------------------------------------------- 1 | // IUserInterface.aidl 2 | package me.wcy.app; 3 | 4 | // Declare any non-default types here with import statements 5 | 6 | interface IUserInterface { 7 | long getUserId(); 8 | 9 | String getUserName(long userId); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/me/wcy/app/AidlDemoActivity.kt: -------------------------------------------------------------------------------- 1 | package me.wcy.app 2 | 3 | import android.content.ComponentName 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.content.ServiceConnection 7 | import android.os.Bundle 8 | import android.os.IBinder 9 | import androidx.appcompat.app.AppCompatActivity 10 | 11 | /** 12 | * Created by wangchenyan.top on 2021/9/6. 13 | */ 14 | class AidlDemoActivity : AppCompatActivity() { 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | 19 | val intent = Intent() 20 | intent.action = "me.wcy.user" 21 | intent.component = ComponentName("me.wcy.app", "me.wcy.app.aidl.UserService") 22 | bindService(intent, conn, Context.BIND_AUTO_CREATE) 23 | } 24 | 25 | private var userInterface: IUserInterface? = null 26 | 27 | private val conn = object : ServiceConnection { 28 | override fun onServiceDisconnected(name: ComponentName?) { 29 | userInterface = null 30 | } 31 | 32 | override fun onServiceConnected(name: ComponentName?, service: IBinder?) { 33 | userInterface = IUserInterface.Stub.asInterface(service) 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/me/wcy/app/BlockingQueueActivity.kt: -------------------------------------------------------------------------------- 1 | package me.wcy.app 2 | 3 | import android.os.* 4 | import android.util.Log 5 | import androidx.activity.ComponentActivity 6 | import androidx.lifecycle.lifecycleScope 7 | import kotlinx.coroutines.asCoroutineDispatcher 8 | import kotlinx.coroutines.launch 9 | import me.wcy.app.databinding.ActivityBlockingQueueBinding 10 | import java.util.concurrent.ArrayBlockingQueue 11 | import java.util.concurrent.BlockingQueue 12 | import java.util.concurrent.Executors 13 | 14 | /** 15 | * Created by wangchenyan.top on 2021/9/6. 16 | */ 17 | class BlockingQueueActivity : ComponentActivity() { 18 | private val viewBinding by viewBindings() 19 | private val toBeDispatchedMessages: BlockingQueue = ArrayBlockingQueue(100) 20 | 21 | val routeHandlerThread = 22 | HandlerThread(BlockingQueueActivity::class.java.simpleName).apply { start() } 23 | val routeHandler = object : Handler(routeHandlerThread.looper) { 24 | override fun handleMessage(msg: Message) { 25 | when (msg.what) { 26 | 0 -> { 27 | val msg = msg.obj.toString() 28 | toBeDispatchedMessages.add(msg) 29 | } 30 | 1 -> { 31 | if (toBeDispatchedMessages.isNotEmpty()) { 32 | startDispatchMessages() 33 | scheduleNextDispatch() 34 | } 35 | } 36 | } 37 | } 38 | } 39 | 40 | override fun onCreate(savedInstanceState: Bundle?) { 41 | super.onCreate(savedInstanceState) 42 | setContentView(viewBinding.root) 43 | 44 | Thread { 45 | for (i in 0..1000) { 46 | enqueueNewMessage(i.toString()) 47 | //SystemClock.sleep(10) 48 | } 49 | }.start() 50 | } 51 | 52 | fun enqueueNewMessage(newMessage: String) { 53 | // routeHandler.sendMessage(Message.obtain(routeHandler, 0, newMessage)) 54 | toBeDispatchedMessages.put(newMessage) 55 | scheduleNextDispatch() 56 | } 57 | 58 | private fun scheduleNextDispatch() { 59 | routeHandler.sendEmptyMessage(1) 60 | } 61 | 62 | private fun startDispatchMessages() { 63 | val dispatchedMessage = toBeDispatchedMessages.poll() ?: return 64 | onRouterMessageReceived(dispatchedMessage) 65 | } 66 | 67 | private val coroutineDispatcher by lazy { 68 | Executors.newSingleThreadScheduledExecutor { Thread(it, "message-dispatcher") } 69 | .asCoroutineDispatcher() 70 | } 71 | 72 | private fun onRouterMessageReceived(message: String) { 73 | lifecycleScope.launch(coroutineDispatcher) { 74 | SystemClock.sleep(1000L) 75 | Log.e("WCY", "dispatch msg:$message") 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/java/me/wcy/app/CoroutineActivity.kt: -------------------------------------------------------------------------------- 1 | package me.wcy.app 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import androidx.activity.ComponentActivity 6 | import androidx.lifecycle.lifecycleScope 7 | import kotlinx.coroutines.* 8 | import kotlinx.coroutines.sync.Mutex 9 | import kotlinx.coroutines.sync.withLock 10 | import me.wcy.app.databinding.ActivityCoroutineBinding 11 | 12 | /** 13 | * Created by wangchenyan.top on 2021/9/6. 14 | */ 15 | class CoroutineActivity : ComponentActivity() { 16 | private val viewBinding by viewBindings() 17 | private var customScope: CoroutineScope? = null 18 | private val mutex = Mutex() 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContentView(viewBinding.root) 23 | 24 | lifecycleScope.launch(Dispatchers.IO) { 25 | repeat(100) { 26 | launch { 27 | mutex.withLock { 28 | tick("lifecycleScope") 29 | delay(10000) 30 | } 31 | } 32 | delay(3000) 33 | } 34 | } 35 | 36 | viewBinding.btnStart.setOnClickListener { 37 | customScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) 38 | customScope?.launch { 39 | repeat(100) { 40 | launch { 41 | mutex.withLock { 42 | tick("customScope") 43 | delay(10000) 44 | } 45 | } 46 | delay(3000) 47 | } 48 | } 49 | } 50 | 51 | viewBinding.btnCancel.setOnClickListener { 52 | customScope?.cancel() 53 | customScope = null 54 | } 55 | } 56 | 57 | private fun tick(tag: String) { 58 | Log.e("WCY", "$tag tick in ${Thread.currentThread().name}") 59 | } 60 | } -------------------------------------------------------------------------------- /app/src/main/java/me/wcy/app/FlowDemoActivity.kt: -------------------------------------------------------------------------------- 1 | package me.wcy.app 2 | 3 | import android.os.Bundle 4 | import android.os.SystemClock 5 | import android.util.Log 6 | import androidx.activity.ComponentActivity 7 | import io.reactivex.Observable 8 | import io.reactivex.schedulers.Schedulers 9 | import kotlinx.coroutines.CoroutineScope 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.SupervisorJob 12 | import kotlinx.coroutines.flow.* 13 | import kotlinx.coroutines.launch 14 | 15 | /** 16 | * Created by wangchenyan.top on 2021/9/6. 17 | */ 18 | class FlowDemoActivity : ComponentActivity(), 19 | CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.IO) { 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | 24 | launch { 25 | test() 26 | } 27 | } 28 | 29 | private suspend fun test() { 30 | val list = listOf(1, 2, 3) 31 | val resList = mutableListOf() 32 | Log.e("WCY", "start") 33 | list.map { flowOf(it) } 34 | .merge() 35 | .map { 36 | SystemClock.sleep(3000) 37 | it.toString() 38 | } 39 | .flowOn(Dispatchers.IO) 40 | .collect { 41 | resList.add(it) 42 | } 43 | Log.e("WCY", "end") 44 | } 45 | 46 | private fun testRxjava() { 47 | Log.e("WCY", "rx start") 48 | val list = listOf(1, 2, 3) 49 | Observable.fromIterable(list) 50 | .observeOn(Schedulers.io()) 51 | .map { 52 | SystemClock.sleep(3000) 53 | it.toString() 54 | } 55 | .toList() 56 | .subscribe { t -> 57 | Log.e("WCY", "rx end") 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /app/src/main/java/me/wcy/app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package me.wcy.app 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.util.Log 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.lifecycle.lifecycleScope 8 | import com.facebook.common.references.CloseableReference 9 | import kotlinx.coroutines.Dispatchers 10 | import kotlinx.coroutines.cancel 11 | import kotlinx.coroutines.launch 12 | import kotlinx.coroutines.withContext 13 | import me.wcy.app.asynclayout.AsyncLayoutActivity 14 | import me.wcy.app.databinding.ActivityMainBinding 15 | import java.io.Closeable 16 | 17 | class MainActivity : AppCompatActivity() { 18 | private val viewBinding by viewBindings() 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContentView(viewBinding.root) 23 | 24 | CustomModuleManager.create() 25 | 26 | //startActivity(Intent(this, FlowDemoActivity::class.java)) 27 | 28 | viewBinding.btnFlow.setOnClickListener { 29 | startActivity(Intent(this, FlowDemoActivity::class.java)) 30 | } 31 | viewBinding.btnCoroutine.setOnClickListener { 32 | startActivity(Intent(this, CoroutineActivity::class.java)) 33 | } 34 | viewBinding.btnAsyncLayout.setOnClickListener { 35 | startActivity(Intent(this, AsyncLayoutActivity::class.java)) 36 | } 37 | 38 | lifecycleScope.launch { 39 | val res = test() 40 | Log.e("WCY", "res=$res") 41 | } 42 | } 43 | 44 | private suspend fun test(): String { 45 | return withContext(Dispatchers.IO) { 46 | cancel() 47 | return@withContext "lalala" 48 | } 49 | } 50 | 51 | private fun closeable() { 52 | val model = Model() 53 | val ref = CloseableReference.of(model) 54 | ref.get() 55 | // do something 56 | ref.close() 57 | } 58 | 59 | override fun onDestroy() { 60 | super.onDestroy() 61 | CustomModuleManager.destroy() 62 | } 63 | } 64 | 65 | interface CustomModuleManager { 66 | companion object { 67 | private var member: CustomModuleManagerImpl? = null 68 | 69 | fun create() { 70 | member = CustomModuleManagerImpl() 71 | } 72 | 73 | fun destroy() { 74 | member = null 75 | } 76 | } 77 | } 78 | 79 | class CustomModuleManagerImpl : CustomModuleManager { 80 | 81 | } 82 | 83 | class Model : Closeable { 84 | var value: Int = 0 85 | 86 | override fun close() { 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/me/wcy/app/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package me.wcy.app 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import androidx.lifecycle.ViewModel 5 | 6 | /** 7 | * Created by wcy on 2021/1/25. 8 | */ 9 | class MainViewModel : ViewModel() { 10 | 11 | val mainData = MutableLiveData("s") 12 | } -------------------------------------------------------------------------------- /app/src/main/java/me/wcy/app/RxJavaDemoActivity.kt: -------------------------------------------------------------------------------- 1 | package me.wcy.app 2 | 3 | import android.os.Bundle 4 | import android.os.SystemClock 5 | import android.util.Log 6 | import android.widget.Button 7 | import androidx.appcompat.app.AppCompatActivity 8 | import io.github.mthli.rxcoroutineschedulers.asScheduler 9 | import io.reactivex.Single 10 | import io.reactivex.disposables.Disposable 11 | import io.reactivex.subjects.PublishSubject 12 | import kotlinx.coroutines.Dispatchers 13 | import kotlinx.coroutines.asCoroutineDispatcher 14 | import java.util.concurrent.Executors 15 | 16 | /** 17 | * Created by wangchenyan.top on 2021/9/6. 18 | */ 19 | class RxJavaDemoActivity : AppCompatActivity() { 20 | private var currentPosition = PublishSubject.create() 21 | private var disposable: Disposable? = null 22 | private var time = 0L 23 | 24 | private val playbackFsmDispatcher by lazy { 25 | Executors.newSingleThreadExecutor { 26 | Thread(it, "playback-msg-dispatch-thread") 27 | }.asCoroutineDispatcher() 28 | } 29 | 30 | override fun onCreate(savedInstanceState: Bundle?) { 31 | super.onCreate(savedInstanceState) 32 | setContentView(R.layout.activity_main) 33 | 34 | findViewById