or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

app-events.mdapp-links.mdbolts-tasks.mdcore-authentication.mdgaming.mdgraph-api.mdindex.mdlogin.mdmessenger.mdsharing.md

bolts-tasks.mddocs/

0

# Asynchronous Tasks (Bolts)

1

2

The Bolts framework provides a powerful task management system for handling asynchronous operations with continuation support, error handling, and cancellation. It enables chaining of asynchronous operations and provides a clean alternative to nested callbacks.

3

4

## Task

5

6

The core Task class for managing asynchronous operations:

7

8

```kotlin { .api }

9

class Task<TResult> private constructor() {

10

// Task state

11

val isCompleted: Boolean

12

val isCancelled: Boolean

13

val isFaulted: Boolean

14

val result: TResult?

15

val error: Exception?

16

17

// Continuation methods

18

fun <TContinuationResult> continueWith(

19

continuation: Continuation<TResult, TContinuationResult>

20

): Task<TContinuationResult>

21

22

fun <TContinuationResult> continueWith(

23

continuation: Continuation<TResult, TContinuationResult>,

24

executor: Executor

25

): Task<TContinuationResult>

26

27

fun <TContinuationResult> continueWithTask(

28

continuation: Continuation<TResult, Task<TContinuationResult>>

29

): Task<TContinuationResult>

30

31

fun <TContinuationResult> continueWithTask(

32

continuation: Continuation<TResult, Task<TContinuationResult>>,

33

executor: Executor

34

): Task<TContinuationResult>

35

36

// Success continuations

37

fun <TContinuationResult> onSuccess(

38

continuation: Continuation<TResult, TContinuationResult>

39

): Task<TContinuationResult>

40

41

fun <TContinuationResult> onSuccess(

42

continuation: Continuation<TResult, TContinuationResult>,

43

executor: Executor

44

): Task<TContinuationResult>

45

46

fun <TContinuationResult> onSuccessTask(

47

continuation: Continuation<TResult, Task<TContinuationResult>>

48

): Task<TContinuationResult>

49

50

fun <TContinuationResult> onSuccessTask(

51

continuation: Continuation<TResult, Task<TContinuationResult>>,

52

executor: Executor

53

): Task<TContinuationResult>

54

55

// Wait methods

56

fun waitForCompletion()

57

fun waitForCompletion(duration: Long, timeUnit: TimeUnit): Boolean

58

59

companion object {

60

// Task creation

61

fun <TResult> call(callable: Callable<TResult>): Task<TResult>

62

fun <TResult> call(callable: Callable<TResult>, executor: Executor): Task<TResult>

63

fun <TResult> callInBackground(callable: Callable<TResult>): Task<TResult>

64

fun <TResult> forResult(result: TResult): Task<TResult>

65

fun <TResult> forError(error: Exception): Task<TResult>

66

fun <TResult> cancelled(): Task<TResult>

67

68

// Task composition

69

fun <TResult> whenAll(tasks: Collection<Task<TResult>>): Task<List<TResult>>

70

fun whenAllResult(tasks: Collection<Task<*>>): Task<Void>

71

fun <TResult> whenAny(tasks: Collection<Task<TResult>>): Task<Task<TResult>>

72

fun whenAnyResult(tasks: Collection<Task<*>>): Task<Task<*>>

73

74

// Delay

75

fun delay(millis: Long): Task<Void>

76

fun delay(millis: Long, cancellationToken: CancellationToken): Task<Void>

77

}

78

}

79

80

interface Continuation<TTaskResult, TContinuationResult> {

81

@Throws(Exception::class)

82

fun then(task: Task<TTaskResult>): TContinuationResult

83

}

84

```

85

86

### Basic Task Usage

87

88

```kotlin

89

class TaskExamples {

90

91

fun basicTaskUsage() {

92

// Create a task from a callable

93

val task = Task.call {

94

// Simulate some work

95

Thread.sleep(1000)

96

"Task completed successfully"

97

}

98

99

// Continue with the result

100

task.continueWith { task ->

101

if (task.isFaulted) {

102

Log.e("Task", "Task failed: ${task.error?.message}")

103

"Error occurred"

104

} else {

105

val result = task.result

106

Log.d("Task", "Task result: $result")

107

result?.uppercase()

108

}

109

}.continueWith { task ->

110

val finalResult = task.result

111

Log.d("Task", "Final result: $finalResult")

112

finalResult

113

}

114

}

115

116

fun backgroundTaskUsage() {

117

// Execute task in background

118

Task.callInBackground {

119

// Perform network request or database operation

120

fetchDataFromApi()

121

}.onSuccess { result ->

122

// This runs on the main thread by default

123

Log.d("Task", "Data fetched: $result")

124

updateUI(result)

125

}.continueWith { task ->

126

if (task.isFaulted) {

127

Log.e("Task", "Background task failed: ${task.error?.message}")

128

handleError(task.error)

129

}

130

null

131

}

132

}

133

134

fun chainedTasksExample() {

135

// Chain multiple asynchronous operations

136

Task.callInBackground {

137

authenticateUser()

138

}.onSuccessTask { authResult ->

139

// Return another task

140

Task.callInBackground {

141

fetchUserProfile(authResult.userId)

142

}

143

}.onSuccessTask { profile ->

144

// Another chained operation

145

Task.callInBackground {

146

loadUserPreferences(profile.id)

147

}

148

}.onSuccess { preferences ->

149

// Final success handler

150

Log.d("Task", "All operations completed")

151

setupUserSession(preferences)

152

}.continueWith { task ->

153

if (task.isFaulted) {

154

Log.e("Task", "Chain failed: ${task.error?.message}")

155

showLoginScreen()

156

}

157

null

158

}

159

}

160

}

161

```

162

163

## Task Completion Source

164

165

Manual control over task completion:

166

167

```kotlin { .api }

168

class TaskCompletionSource<TResult> {

169

val task: Task<TResult>

170

val isCancellationRequested: Boolean

171

172

fun setResult(result: TResult): Boolean

173

fun trySetResult(result: TResult): Boolean

174

fun setError(error: Exception): Boolean

175

fun trySetError(error: Exception): Boolean

176

fun setCancelled(): Boolean

177

fun trySetCancelled(): Boolean

178

}

179

```

180

181

### Task Completion Source Usage

182

183

```kotlin

184

class ManualTaskControl {

185

186

fun createManualTask(): Task<String> {

187

val tcs = TaskCompletionSource<String>()

188

189

// Simulate async operation with manual completion

190

Thread {

191

try {

192

Thread.sleep(2000)

193

// Manually complete the task

194

tcs.setResult("Manual task completed")

195

} catch (e: InterruptedException) {

196

tcs.setError(e)

197

}

198

}.start()

199

200

return tcs.task

201

}

202

203

fun createConditionalTask(condition: Boolean): Task<String> {

204

val tcs = TaskCompletionSource<String>()

205

206

if (condition) {

207

tcs.setResult("Condition met")

208

} else {

209

tcs.setError(IllegalStateException("Condition not met"))

210

}

211

212

return tcs.task

213

}

214

215

fun createTimeoutTask(timeoutMs: Long): Task<String> {

216

val tcs = TaskCompletionSource<String>()

217

218

// Set up timeout

219

Handler(Looper.getMainLooper()).postDelayed({

220

if (!tcs.task.isCompleted) {

221

tcs.setError(TimeoutException("Task timed out"))

222

}

223

}, timeoutMs)

224

225

// Simulate work

226

Thread {

227

try {

228

Thread.sleep(timeoutMs + 1000) // Will timeout

229

tcs.trySetResult("Work completed")

230

} catch (e: Exception) {

231

tcs.trySetError(e)

232

}

233

}.start()

234

235

return tcs.task

236

}

237

}

238

```

239

240

## Cancellation Support

241

242

Handle task cancellation with cancellation tokens:

243

244

```kotlin { .api }

245

class CancellationToken {

246

val isCancellationRequested: Boolean

247

248

fun throwIfCancellationRequested()

249

fun register(action: Runnable): CancellationTokenRegistration

250

}

251

252

class CancellationTokenSource {

253

val token: CancellationToken

254

val isCancellationRequested: Boolean

255

256

fun cancel()

257

fun cancelAfter(delayMs: Long)

258

fun close()

259

}

260

261

class CancellationTokenRegistration {

262

fun close()

263

}

264

```

265

266

### Cancellation Usage

267

268

```kotlin

269

class CancellationExamples {

270

271

fun cancellableTask() {

272

val cancellationSource = CancellationTokenSource()

273

val cancellationToken = cancellationSource.token

274

275

val task = Task.call({

276

// Long running operation

277

for (i in 1..100) {

278

// Check for cancellation

279

cancellationToken.throwIfCancellationRequested()

280

281

// Simulate work

282

Thread.sleep(100)

283

Log.d("Task", "Progress: $i/100")

284

}

285

"Task completed"

286

}, BoltsExecutors.background())

287

288

// Cancel after 5 seconds

289

Handler(Looper.getMainLooper()).postDelayed({

290

cancellationSource.cancel()

291

Log.d("Task", "Cancellation requested")

292

}, 5000)

293

294

task.continueWith { task ->

295

when {

296

task.isCancelled -> Log.d("Task", "Task was cancelled")

297

task.isFaulted -> Log.e("Task", "Task failed: ${task.error?.message}")

298

else -> Log.d("Task", "Task completed: ${task.result}")

299

}

300

null

301

}

302

}

303

304

fun cancellationWithCleanup() {

305

val cancellationSource = CancellationTokenSource()

306

307

// Register cleanup action

308

val registration = cancellationSource.token.register {

309

Log.d("Task", "Performing cleanup...")

310

cleanupResources()

311

}

312

313

val task = Task.callInBackground {

314

try {

315

performLongRunningOperation(cancellationSource.token)

316

} finally {

317

registration.close()

318

}

319

}

320

321

// Auto-cancel after timeout

322

cancellationSource.cancelAfter(10000) // 10 seconds

323

324

return task

325

}

326

}

327

```

328

329

## Task Executors

330

331

Control where tasks execute:

332

333

```kotlin { .api }

334

object BoltsExecutors {

335

fun background(): Executor

336

fun immediate(): Executor

337

}

338

339

object AndroidExecutors {

340

fun mainThread(): Executor

341

fun uiThread(): Executor

342

}

343

```

344

345

### Executor Usage

346

347

```kotlin

348

class ExecutorExamples {

349

350

fun executorControlExample() {

351

// Background task

352

Task.call({

353

// Heavy computation

354

performCpuIntensiveWork()

355

}, BoltsExecutors.background())

356

.continueWith({ task ->

357

// Process result on background thread

358

processResult(task.result)

359

}, BoltsExecutors.background())

360

.continueWith({ task ->

361

// Update UI on main thread

362

updateUI(task.result)

363

null

364

}, AndroidExecutors.mainThread())

365

}

366

367

fun immediateExecutorExample() {

368

// Task that executes immediately on current thread

369

val result = Task.forResult("immediate result")

370

371

result.continueWith({ task ->

372

Log.d("Task", "This runs immediately: ${task.result}")

373

null

374

}, BoltsExecutors.immediate())

375

}

376

}

377

```

378

379

## Task Composition

380

381

Combine multiple tasks:

382

383

```kotlin

384

class TaskComposition {

385

386

fun parallelTasksExample() {

387

val task1 = Task.callInBackground { fetchUserData() }

388

val task2 = Task.callInBackground { fetchUserPreferences() }

389

val task3 = Task.callInBackground { fetchUserSettings() }

390

391

// Wait for all tasks to complete

392

Task.whenAll(listOf(task1, task2, task3))

393

.onSuccess { results ->

394

val userData = results[0]

395

val preferences = results[1]

396

val settings = results[2]

397

398

// Combine all results

399

setupUserSession(userData, preferences, settings)

400

}

401

.continueWith { task ->

402

if (task.isFaulted) {

403

Log.e("Task", "One or more tasks failed: ${task.error?.message}")

404

handleError(task.error)

405

}

406

null

407

}

408

}

409

410

fun raceConditionExample() {

411

val cacheTask = Task.callInBackground { loadFromCache() }

412

val networkTask = Task.callInBackground { loadFromNetwork() }

413

414

// Use whichever completes first

415

Task.whenAny(listOf(cacheTask, networkTask))

416

.onSuccess { firstCompletedTask ->

417

val winningTask = firstCompletedTask

418

if (!winningTask.isFaulted) {

419

Log.d("Task", "Using result from fastest source")

420

processData(winningTask.result)

421

} else {

422

Log.w("Task", "Fastest task failed, waiting for other...")

423

// Handle the case where first task failed

424

}

425

}

426

}

427

428

fun conditionalChainingExample() {

429

Task.callInBackground {

430

checkUserAuthentication()

431

}.onSuccessTask { isAuthenticated ->

432

if (isAuthenticated) {

433

// User is authenticated, fetch protected data

434

Task.callInBackground { fetchProtectedUserData() }

435

} else {

436

// User not authenticated, redirect to login

437

Task.forResult(null)

438

}

439

}.onSuccess { protectedData ->

440

if (protectedData != null) {

441

displayUserData(protectedData)

442

} else {

443

showLoginScreen()

444

}

445

}

446

}

447

}

448

```

449

450

## Error Handling Patterns

451

452

Advanced error handling with tasks:

453

454

```kotlin

455

class TaskErrorHandling {

456

457

fun retryPattern() {

458

fun attemptOperation(attempt: Int = 1): Task<String> {

459

return Task.callInBackground {

460

if (Math.random() < 0.7 && attempt < 3) {

461

throw IOException("Network error (attempt $attempt)")

462

}

463

"Operation successful on attempt $attempt"

464

}.continueWithTask { task ->

465

if (task.isFaulted && attempt < 3) {

466

Log.w("Task", "Attempt $attempt failed, retrying...")

467

Task.delay(1000 * attempt).continueWithTask {

468

attemptOperation(attempt + 1)

469

}

470

} else {

471

Task.forResult(task.result ?: throw task.error!!)

472

}

473

}

474

}

475

476

attemptOperation().onSuccess { result ->

477

Log.d("Task", "Final result: $result")

478

}.continueWith { task ->

479

if (task.isFaulted) {

480

Log.e("Task", "All retry attempts failed: ${task.error?.message}")

481

}

482

null

483

}

484

}

485

486

fun fallbackPattern() {

487

Task.callInBackground {

488

fetchFromPrimarySource()

489

}.continueWithTask { task ->

490

if (task.isFaulted) {

491

Log.w("Task", "Primary source failed, trying fallback...")

492

Task.callInBackground { fetchFromFallbackSource() }

493

} else {

494

Task.forResult(task.result)

495

}

496

}.continueWithTask { task ->

497

if (task.isFaulted) {

498

Log.w("Task", "Fallback failed, using cache...")

499

Task.callInBackground { fetchFromCache() }

500

} else {

501

Task.forResult(task.result)

502

}

503

}.onSuccess { result ->

504

Log.d("Task", "Data retrieved: $result")

505

processData(result)

506

}.continueWith { task ->

507

if (task.isFaulted) {

508

Log.e("Task", "All sources failed: ${task.error?.message}")

509

showErrorMessage("Unable to load data")

510

}

511

null

512

}

513

}

514

515

fun timeoutPattern() {

516

val timeoutTask = Task.delay(5000).continueWith {

517

throw TimeoutException("Operation timed out")

518

}

519

520

val operationTask = Task.callInBackground {

521

performSlowOperation()

522

}

523

524

Task.whenAny(listOf(operationTask, timeoutTask))

525

.onSuccessTask { firstCompleted ->

526

if (firstCompleted == operationTask && !operationTask.isFaulted) {

527

Task.forResult(operationTask.result)

528

} else {

529

Task.forError<String>(TimeoutException("Operation timed out"))

530

}

531

}

532

.onSuccess { result ->

533

Log.d("Task", "Operation completed within timeout: $result")

534

}

535

.continueWith { task ->

536

if (task.isFaulted) {

537

Log.e("Task", "Operation failed or timed out: ${task.error?.message}")

538

}

539

null

540

}

541

}

542

}

543

```

544

545

## Integration with Facebook SDK

546

547

Using Bolts tasks with Facebook SDK operations:

548

549

```kotlin

550

class FacebookBoltsIntegration {

551

552

fun facebookLoginWithTasks(): Task<AccessToken> {

553

val tcs = TaskCompletionSource<AccessToken>()

554

555

val loginManager = LoginManager.getInstance()

556

loginManager.registerCallback(callbackManager, object : FacebookCallback<LoginResult> {

557

override fun onSuccess(result: LoginResult) {

558

tcs.setResult(result.accessToken)

559

}

560

561

override fun onCancel() {

562

tcs.setError(FacebookOperationCanceledException("Login cancelled"))

563

}

564

565

override fun onError(error: FacebookException) {

566

tcs.setError(error)

567

}

568

})

569

570

loginManager.logIn(activity, listOf("email", "public_profile"))

571

return tcs.task

572

}

573

574

fun graphRequestWithTasks(graphPath: String): Task<JSONObject> {

575

val tcs = TaskCompletionSource<JSONObject>()

576

577

val request = GraphRequest.newGraphPathRequest(

578

AccessToken.getCurrentAccessToken(),

579

graphPath

580

) { response ->

581

if (response.error != null) {

582

tcs.setError(FacebookGraphResponseException(response, response.error!!.errorMessage))

583

} else {

584

response.jsonObject?.let {

585

tcs.setResult(it)

586

} ?: tcs.setError(FacebookException("Empty response"))

587

}

588

}

589

590

request.executeAsync()

591

return tcs.task

592

}

593

594

fun completeUserSetupChain(): Task<Void> {

595

return facebookLoginWithTasks()

596

.onSuccessTask { accessToken ->

597

graphRequestWithTasks("/me?fields=id,name,email")

598

}

599

.onSuccessTask { userInfo ->

600

Task.callInBackground {

601

saveUserInfo(userInfo)

602

}

603

}

604

.onSuccessTask {

605

Task.callInBackground {

606

loadUserPreferences()

607

}

608

}

609

.onSuccess { preferences ->

610

setupUserSession(preferences)

611

null

612

}

613

}

614

}

615

```