Android實(shí)現(xiàn)定時(shí)任務(wù)的幾種方式匯總(附源碼)
一、項(xiàng)目介紹
1. 背景與意義
在 Android 應(yīng)用中,定時(shí)任務(wù)(Scheduled Task)的需求幾乎無(wú)處不在:從定時(shí)刷新數(shù)據(jù)、定時(shí)備份、定時(shí)推送通知,到夜間靜默下載、循環(huán)執(zhí)行某些業(yè)務(wù)邏輯等,都需要系統(tǒng)在指定時(shí)間或間隔觸發(fā)代碼執(zhí)行。由于 Android 系統(tǒng)自身的生命周期管理、Doze 模式、電量?jī)?yōu)化等機(jī)制,定時(shí)任務(wù)的實(shí)現(xiàn)既要保證準(zhǔn)確性,又要兼顧節(jié)電與資源利用,因此常見的幾種實(shí)現(xiàn)方式各有側(cè)重點(diǎn)和使用場(chǎng)景。
本文將從原理、最佳實(shí)踐、優(yōu)勢(shì)與局限等多個(gè)維度,全面梳理 Android 上實(shí)現(xiàn)定時(shí)任務(wù)的主要方案,并輔以完整、可運(yùn)行的示例代碼。本文結(jié)構(gòu)如下:
定時(shí)任務(wù)常見場(chǎng)景與需求
相關(guān)基礎(chǔ)知識(shí)與約束
方案一:
Handler.postDelayed()與Runnable方案二:
Timer/TimerTask方案三:
ScheduledThreadPoolExecutor方案四:
AlarmManager方案五:
JobScheduler方案六:
WorkManager方案七:前臺(tái) Service(
Service+Handler/AlarmManager)環(huán)境與依賴
完整代碼整合(一個(gè)代碼塊,用注釋分隔文件)
方案對(duì)比與選型建議
性能與節(jié)電優(yōu)化
項(xiàng)目總結(jié)與擴(kuò)展思路
FAQ
二、相關(guān)基礎(chǔ)知識(shí)與系統(tǒng)約束
主線程與子線程
Handler:在主線程或指定線程的Looper上調(diào)度Runnable;TimerTask/ScheduledThreadPoolExecutor:在后臺(tái)線程池中執(zhí)行定時(shí)任務(wù),需注意生命周期。
系統(tǒng)節(jié)電機(jī)制
Doze 模式(Android 6.0+)會(huì)延遲或批量處理定時(shí)喚醒;
App Standby、Battery Saver 會(huì)限制后臺(tái)調(diào)度;
進(jìn)程與組件生命周期
進(jìn)程被回收、
Service被銷毀,定時(shí)需要持久化或者與系統(tǒng)調(diào)度器聯(lián)動(dòng);
精準(zhǔn)度與耗電
高頻次高精度喚醒會(huì)消耗大量電量;
應(yīng)用場(chǎng)景決定使用何種精度及調(diào)度器;
跨重啟與持久化
AlarmManager可設(shè)置在設(shè)備重啟后仍然生效(需動(dòng)態(tài)或靜態(tài)注冊(cè)BOOT_COMPLETED);JobScheduler與WorkManager可在重啟后自動(dòng)恢復(fù)。
三、方案一:Handler.postDelayed()
3.1 原理
Handler 通過(guò)向其所綁定的 Looper(通常為主線程)發(fā)送延時(shí)消息,執(zhí)行 Runnable。常用于短時(shí)、低頻、與 UI 交互密切的定時(shí)操作。
3.2 示例代碼
// 用于在 Activity 或 Service 中
private val handler = Handler(Looper.getMainLooper())
private val task = object : Runnable {
override fun run() {
// 執(zhí)行定時(shí)任務(wù)
refreshUI()
// 再次調(diào)度
handler.postDelayed(this, 5000)
}
}
override fun onStart() {
super.onStart()
handler.postDelayed(task, 5000) // 5 秒后首次執(zhí)行
}
override fun onStop() {
super.onStop()
handler.removeCallbacks(task) // 停止調(diào)度
}3.3 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):簡(jiǎn)單易用,可輕松執(zhí)行自定義邏輯;
缺點(diǎn):依賴進(jìn)程存活,進(jìn)程掛掉或設(shè)備休眠時(shí)無(wú)法保證執(zhí)行;高頻調(diào)度耗電;
四、方案二:Timer / TimerTask
4.1 原理
java.util.Timer 在單獨(dú)線程中調(diào)度一個(gè)或多個(gè) TimerTask,基于 java.util.concurrent,適合簡(jiǎn)單后臺(tái)定時(shí)。
4.2 示例代碼
private var timer: Timer? = null
fun startTimer() {
timer = Timer().apply {
scheduleAtFixedRate(object : TimerTask() {
override fun run() {
// 后臺(tái)線程執(zhí)行
performBackgroundWork()
}
}, 0, 10_000) // 10 秒一次
}
}
fun stopTimer() {
timer?.cancel()
timer = null
}4.3 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):易于跨線程執(zhí)行,適合簡(jiǎn)單后臺(tái)定時(shí);
缺點(diǎn):
TimerTask出現(xiàn)異常會(huì)導(dǎo)致后續(xù)任務(wù)無(wú)法執(zhí)行;需要手動(dòng)管理生命周期;
五、方案三:ScheduledThreadPoolExecutor
5.1 原理
基于 java.util.concurrent.ScheduledExecutorService,可創(chuàng)建固定大小線程池,調(diào)度單次或周期性任務(wù)。
5.2 示例代碼
private val scheduler = Executors.newScheduledThreadPool(1)
fun startScheduledTask() {
scheduler.scheduleAtFixedRate({
performBackgroundWork()
}, 0, 15, TimeUnit.MINUTES) // 每 15 分鐘執(zhí)行
}
fun stopScheduledTask() {
scheduler.shutdownNow()
}5.3 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):可控線程池大小,任務(wù)異常不會(huì)影響其他任務(wù);
缺點(diǎn):同樣受進(jìn)程生命周期影響,不可跨重啟;
六、方案四:AlarmManager
6.1 原理
系統(tǒng)級(jí)調(diào)度,使用 AlarmManager 可在指定時(shí)間觸發(fā) PendingIntent,喚醒或啟動(dòng)組件(BroadcastReceiver、Service、Activity),支持跨進(jìn)程和重啟。
6.2 示例代碼
// 注冊(cè)廣播接收者:AlarmReceiver
class AlarmReceiver: BroadcastReceiver() {
override fun onReceive(ctx: Context, intent: Intent) {
// 執(zhí)行任務(wù)
performWork(ctx)
}
}
// 在 AndroidManifest.xml
<receiver android:name=".AlarmReceiver" />
// 在代碼中設(shè)置 Alarm
val am = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val pi = PendingIntent.getBroadcast(this, 0,
Intent(this, AlarmReceiver::class.java), 0)
// 精準(zhǔn)鬧鐘(API 19+可能被合并)
am.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + 60_000, // 1 分鐘后
pi
)周期性任務(wù):
setRepeating()或在onReceive再次注冊(cè);跨重啟恢復(fù):需監(jiān)聽
BOOT_COMPLETED并重注冊(cè)鬧鐘。
6.3 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):系統(tǒng)級(jí)喚醒,可跨重啟、Doze 模式下保證執(zhí)行;
缺點(diǎn):頻繁鬧鐘會(huì)嚴(yán)重耗電;API 19+可能被系統(tǒng)節(jié)省合并;
七、方案五:JobScheduler
7.1 原理
Android 5.0+ 原生 API,管理符合條件的后臺(tái)任務(wù)(網(wǎng)絡(luò)、充電、空閑等),系統(tǒng)按照策略調(diào)度,無(wú)需開發(fā)者手動(dòng)重注冊(cè)。
7.2 示例代碼
class MyJobService: JobService() {
override fun onStartJob(params: JobParameters): Boolean {
// 在后臺(tái)線程執(zhí)行
doWork {
jobFinished(params, false)
}
return true // 還有后臺(tái)線程工作
}
override fun onStopJob(params: JobParameters) = false
}
// 在 Activity 或 Application 中調(diào)度
val tm = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
val job = JobInfo.Builder(1, ComponentName(this, MyJobService::class.java))
.setRequiresCharging(false)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPeriodic(15 * 60 * 1000) // 最小 15 分鐘
.build()
tm.schedule(job)7.3 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):系統(tǒng)自動(dòng)優(yōu)化調(diào)度,省電;支持條件觸發(fā);
缺點(diǎn):API 21+,周期最小 15 分鐘;
八、方案六:WorkManager
8.1 原理
Google 推薦的后臺(tái)任務(wù)庫(kù),兼容 API 14+,內(nèi)部根據(jù)系統(tǒng)版本選擇 JobScheduler / AlarmManager / FirebaseJobDispatcher,支持約束、鏈?zhǔn)?、唯一任?wù)、延遲、周期、持久化、重試等功能。
8.2 示例代碼
class MyWorker(ctx: Context, params: WorkerParameters): Worker(ctx, params) {
override fun doWork(): Result {
performWork(applicationContext)
return Result.success()
}
}
// 在代碼中調(diào)度
val request = PeriodicWorkRequestBuilder<MyWorker>(1, TimeUnit.HOURS)
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build())
.build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"my_hourly_work",
ExistingPeriodicWorkPolicy.KEEP,
request
)8.3 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):API 兼容廣、自動(dòng)選擇最佳調(diào)度器、持久化、易用;
缺點(diǎn):調(diào)度不保證精確及時(shí),多數(shù)場(chǎng)景延遲幾分鐘或更長(zhǎng);
九、方案七:前臺(tái) Service
9.1 原理
啟動(dòng)一個(gè) 前臺(tái) Service(startForeground()),利用 Handler 或 ScheduledExecutor 在其內(nèi)部循環(huán)執(zhí)行任務(wù),確保進(jìn)程與 Service 不被系統(tǒng)殺死。
9.2 示例代碼
class ForegroundTimerService: Service() {
private val handler = Handler(Looper.getMainLooper())
private val task = object: Runnable {
override fun run() {
performWork(this@ForegroundTimerService)
handler.postDelayed(this, 5*60*1000)
}
}
override fun onCreate() {
super.onCreate()
startForeground(1, buildNotification())
handler.post(task)
}
override fun onDestroy() {
handler.removeCallbacks(task)
super.onDestroy()
}
override fun onBind(intent: Intent?) = null
}9.3 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):進(jìn)程常駐,不易被回收,適合高可靠性長(zhǎng)時(shí)任務(wù);
缺點(diǎn):持續(xù)顯示通知,耗電,影響用戶體驗(yàn);
十、環(huán)境與依賴
// app/build.gradle
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdk 34
defaultConfig {
applicationId "com.example.scheduletask"
minSdk 21
targetSdk 34
}
}
dependencies {
implementation 'androidx.work:work-runtime-ktx:2.8.1'
}十一、完整代碼整合
// =======================================================
// 文件:AndroidManifest.xml
// 描述:聲明 Service 與 BroadcastReceiver
// =======================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.scheduletask">
<application android:name=".App">
<!-- AlarmManager Receiver -->
<receiver android:name=".AlarmReceiver"/>
<!-- Foreground Service -->
<service android:name=".ForegroundTimerService"
android:exported="false"/>
<!-- JobScheduler Service -->
<service android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>
</manifest>
// =======================================================
// 文件:App.kt
// 描述:Application,初始化 WorkManager
// =======================================================
package com.example.scheduletask
import android.app.Application
class App : Application()
// =======================================================
// 文件:AlarmReceiver.kt
// 描述:AlarmManager 定時(shí)任務(wù)接收
// =======================================================
package com.example.scheduletask
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(ctx: Context, intent: Intent) {
TaskUtils.log("AlarmManager triggered")
}
}
// =======================================================
// 文件:MyJobService.kt
// 描述:JobScheduler Service
// =======================================================
package com.example.scheduletask
import android.app.job.JobParameters
import android.app.job.JobService
import kotlinx.coroutines.*
class MyJobService: JobService() {
private val scope = CoroutineScope(Dispatchers.Default)
override fun onStartJob(params: JobParameters): Boolean {
scope.launch {
TaskUtils.log("JobScheduler triggered")
jobFinished(params, false)
}
return true
}
override fun onStopJob(params: JobParameters) = false
}
// =======================================================
// 文件:ForegroundTimerService.kt
// 描述:前臺(tái) Service + Handler
// =======================================================
package com.example.scheduletask
import android.app.Notification
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.*
class ForegroundTimerService: Service() {
private val handler = Handler(Looper.getMainLooper())
private val task = object : Runnable {
override fun run() {
TaskUtils.log("ForegroundService task executed")
handler.postDelayed(this, 5*60*1000)
}
}
override fun onCreate() {
super.onCreate()
startForeground(1, buildNotification())
handler.post(task)
}
override fun onDestroy() {
handler.removeCallbacks(task)
super.onDestroy()
}
override fun onBind(intent: Intent?) = null
private fun buildNotification(): Notification {
val pi = PendingIntent.getActivity(
this,0, Intent(this, MainActivity::class.java),0)
return Notification.Builder(this, TaskUtils.CHANNEL_ID)
.setContentTitle("定時(shí)任務(wù)服務(wù)")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pi)
.build()
}
}
// =======================================================
// 文件:TaskUtils.kt
// 描述:工具類:日志與調(diào)度注冊(cè)方法
// =======================================================
package com.example.scheduletask
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import androidx.work.*
import java.util.concurrent.TimeUnit
object TaskUtils {
const val CHANNEL_ID = "task_service_channel"
fun scheduleAlarm(ctx: Context){
val am = ctx.getSystemService(Context.ALARM_SERVICE)
as AlarmManager
val pi = PendingIntent.getBroadcast(
ctx,0, Intent(ctx,AlarmReceiver::class.java),0)
am.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis()+60_000, pi)
}
fun scheduleJob(ctx: Context){
val js = ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE)
as JobScheduler
val job = JobInfo.Builder(1,
ComponentName(ctx, MyJobService::class.java))
.setPeriodic(15*60*1000)
.build()
js.schedule(job)
}
fun scheduleWork(){
val req = PeriodicWorkRequestBuilder<MyWorker>(
1, TimeUnit.HOURS).build()
WorkManager.getInstance(App.instance)
.enqueueUniquePeriodicWork(
"my_hourly_work",
ExistingPeriodicWorkPolicy.KEEP,
req)
}
}
// =======================================================
// 文件:MyWorker.kt
// 描述:WorkManager Worker
// =======================================================
package com.example.scheduletask
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
class MyWorker(ctx: Context, params: WorkerParameters)
: Worker(ctx, params) {
override fun doWork(): Result {
TaskUtils.log("WorkManager triggered")
return Result.success()
}
}
// =======================================================
// 文件:MainActivity.kt
// 描述:演示各方案觸發(fā)與開始
// =======================================================
package com.example.scheduletask
import android.Manifest
import android.content.Intent
import android.os.*
import androidx.appcompat.app.AppCompatActivity
import com.example.scheduletask.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var b: ActivityMainBinding
override fun onCreate(s: Bundle?) {
super.onCreate(s)
b = ActivityMainBinding.inflate(layoutInflater); setContentView(b.root)
b.btnHandler.setOnClickListener {
handler.postDelayed(runnable, 5000)
}
b.btnTimer.setOnClickListener { startTimer() }
b.btnScheduled.setOnClickListener { startScheduled() }
b.btnAlarm.setOnClickListener { TaskUtils.scheduleAlarm(this) }
b.btnJob.setOnClickListener { TaskUtils.scheduleJob(this) }
b.btnWork.setOnClickListener { TaskUtils.scheduleWork() }
b.btnService.setOnClickListener {
startService(Intent(this, ForegroundTimerService::class.java))
}
}
// Handler 示例
private val handler = Handler(Looper.getMainLooper())
private val runnable = object: Runnable {
override fun run() {
TaskUtils.log("Handler.postDelayed triggered")
}
}
// Timer 示例
private var timer: Timer? = null
private fun startTimer(){
timer?.cancel()
timer = Timer().apply {
schedule(object: TimerTask(){
override fun run() {
TaskUtils.log("TimerTask triggered")
}
}, 0, 10000)
}
}
// ScheduledThreadPoolExecutor 示例
private val scheduler = Executors.newScheduledThreadPool(1)
private fun startScheduled(){
scheduler.scheduleAtFixedRate({
TaskUtils.log("ScheduledThreadPoolExecutor triggered")
},0,30,TimeUnit.SECONDS)
}
}十二、方案對(duì)比與選型建議
| 方案 | API 版本 | 精度 | 電量消耗 | 跨重啟 | 適用場(chǎng)景 |
|---|---|---|---|---|---|
| Handler.postDelayed() | API 1 | 高(線程內(nèi)) | 高 | ? | 短時(shí)、界面內(nèi)輕量周期更新 |
| Timer / TimerTask | API 1 | 較高 | 較高 | ? | 簡(jiǎn)單后臺(tái)任務(wù) |
| ScheduledThreadPoolExecutor | API 1 | 較高 | 較高 | ? | 需要線程池管理的后臺(tái)任務(wù) |
| AlarmManager | API 1 | 可精確到毫秒 | 較高 | ? | 指定時(shí)間點(diǎn)精確喚醒、跨重啟 |
| JobScheduler | API 21+ | 批量調(diào)度,不精準(zhǔn) | 低 | ? | 條件觸發(fā)、系統(tǒng)優(yōu)化批量執(zhí)行 |
| WorkManager | API 14+ | 近似周期(分鐘) | 低 | ? | 可鏈?zhǔn)?、可約束、推薦使用 |
| Foreground Service + Handler | API 1 | 高(內(nèi)部調(diào)度) | 高 | ? | 高可靠、長(zhǎng)時(shí)后臺(tái)任務(wù),但影響 UX |
對(duì)于精度要求極高且一次性的提醒,使用
AlarmManager。對(duì)于持續(xù)周期且不要求秒級(jí)精度的后臺(tái)任務(wù),推薦
WorkManager或JobScheduler。對(duì)于UI 內(nèi)短時(shí)刷新,使用
Handler.postDelayed。對(duì)于進(jìn)程常駐需要持續(xù)執(zhí)行的核心任務(wù),可考慮前臺(tái) Service。
十三、性能與節(jié)電優(yōu)化
合并報(bào)警:避免設(shè)置過(guò)多鬧鐘,使用批量或合并喚醒策略。
避開 Doze 限制:對(duì)非關(guān)鍵任務(wù)使用
WorkManager,讓系統(tǒng)統(tǒng)一調(diào)度;動(dòng)態(tài)調(diào)整周期:根據(jù)網(wǎng)絡(luò)、充電狀態(tài)、用戶交互降低喚醒頻率;
短任務(wù)快速完成:在
JobService中盡快完成,避免應(yīng)用常駐;
十四、項(xiàng)目總結(jié)與擴(kuò)展思路
本文全面梳理了 Android 實(shí)現(xiàn)定時(shí)任務(wù)的七種主要方案,從最簡(jiǎn)單的 Handler、Timer,到系統(tǒng)級(jí)的 AlarmManager、JobScheduler,再到兼容性最優(yōu)的 WorkManager 以及高可靠性的前臺(tái) Service,幫助你根據(jù)應(yīng)用場(chǎng)景、精度與耗電三大維度進(jìn)行選型。同時(shí)提供了完整可運(yùn)行的示例代碼,涵蓋注冊(cè)、觸發(fā)、處理與取消等全流程,助你快速落地定時(shí)任務(wù)功能。
拓展思路
混合調(diào)度:在同一場(chǎng)景下組合多種方案,例如通過(guò)
WorkManager管理長(zhǎng)周期任務(wù),并在關(guān)鍵時(shí)刻通過(guò)AlarmManager精確喚醒。自適應(yīng)調(diào)度:根據(jù) App 后臺(tái)/前臺(tái)狀態(tài)動(dòng)態(tài)切換調(diào)度精度。
可視化管理:在應(yīng)用內(nèi)提供定時(shí)任務(wù)列表、運(yùn)行日志與調(diào)度狀態(tài)監(jiān)控。
十五、常見問(wèn)題解答(FAQ)
AlarmManager 為什么不精準(zhǔn)?
Android 19+ 系統(tǒng)會(huì)對(duì)鬧鐘進(jìn)行批量合并,可使用
setExactAndAllowWhileIdle()強(qiáng)制精準(zhǔn),但頻繁喚醒會(huì)被 Doze 限制。
JobScheduler 周期最小為何是 15 分鐘?
系統(tǒng)最小周期為 15 分鐘,用于避免過(guò)度喚醒和電量消耗。
WorkManager 會(huì)消耗大量電量嗎?
不會(huì),系統(tǒng)會(huì)合并調(diào)度,且只在滿足約束時(shí)執(zhí)行,適合大部分后臺(tái)任務(wù)。
前臺(tái) Service 為什么影響用戶體驗(yàn)?
因?yàn)闀?huì)持續(xù)顯示通知,且常駐進(jìn)程,耗電且用戶難以關(guān)閉。
是否需要?jiǎng)討B(tài)注冊(cè) BOOT_COMPLETED?
如果使用
AlarmManager需在重啟后重新注冊(cè)鬧鐘;JobScheduler與WorkManager會(huì)自動(dòng)恢復(fù)。
以上就是Android實(shí)現(xiàn)定時(shí)任務(wù)的幾種方式匯總(附源碼)的詳細(xì)內(nèi)容,更多關(guān)于Android定時(shí)任務(wù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android實(shí)現(xiàn)一周時(shí)間早中晚排班表
項(xiàng)目需求需要實(shí)現(xiàn)一個(gè)動(dòng)態(tài)添加,修改一周早中晚時(shí)間排班表,文章給大家提供了實(shí)現(xiàn)代碼,需要的朋友參考下吧2018-07-07
基于Android平臺(tái)實(shí)現(xiàn)拼圖小游戲
這篇文章主要為大家詳細(xì)介紹了基于Android平臺(tái)實(shí)現(xiàn)拼圖小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
使用Fragment+ViewPager實(shí)現(xiàn)底部導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了使用Fragment+ViewPager實(shí)現(xiàn)底部導(dǎo)航欄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
Android自定View實(shí)現(xiàn)滑動(dòng)驗(yàn)證效果的代碼
這篇文章主要介紹了Android自定View實(shí)現(xiàn)滑動(dòng)驗(yàn)證效果,代碼分為自定義屬性代碼和自定義view代碼及使用方法,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-12-12
Android Chronometer控件實(shí)現(xiàn)計(jì)時(shí)器函數(shù)詳解
這篇文章主要為大家詳細(xì)介紹了Android Chronometer控件實(shí)現(xiàn)計(jì)時(shí)器函數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-04-04
Android手勢(shì)識(shí)別器GestureDetector使用詳解
這篇文章主要為大家詳細(xì)介紹了Android手勢(shì)識(shí)別器GestureDetector的使用方法解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
Android中使用Kotlin實(shí)現(xiàn)一個(gè)簡(jiǎn)單的登錄界面
Kotlin 是一種在 Java 虛擬機(jī)上運(yùn)行的靜態(tài)類型編程語(yǔ)言,被稱之為 Android 世界的Swift,由 JetBrains 設(shè)計(jì)開發(fā)并開源。接下來(lái)本文通過(guò)實(shí)例代碼給大家講解Android中使用Kotlin實(shí)現(xiàn)一個(gè)簡(jiǎn)單的登錄界面,一起看看吧2017-09-09

