Gỡ lỗi bằng điểm ngắt

1. Trước khi bắt đầu

Cho đến thời điểm này, hầu hết các nhà phát triển mới đều bắt đầu nhận biết về tính năng gỡ lỗi bằng câu lệnh nhật ký. Nếu đã hoàn thành Bài 1, bạn cũng sẽ biết cách đọc dấu vết ngăn xếp và nghiên cứu các thông báo lỗi. Mặc dù cả hai đều là các công cụ gỡ lỗi mạnh mẽ, nhưng các IDE hiện đại cung cấp nhiều chức năng hơn để quá trình gỡ lỗi diễn ra hiệu quả hơn.

Trong bài học này, bạn sẽ tìm hiểu về trình gỡ lỗi tích hợp của Android Studio, cách tạm dừng thực thi ứng dụng và cách thực thi từng dòng mã mỗi lần để xác định nguồn chính xác của lỗi. Bạn cũng sẽ tìm hiểu cách sử dụng một tính năng được gọi là Đồng hồ và theo dõi các biến cụ thể thay vì phải thêm các câu lệnh nhật ký cụ thể.

Điều kiện tiên quyết

  • Biết cách di chuyển trong một dự án trong Android Studio.
  • Quen thuộc với việc ghi nhật ký trong Kotlin.

Kiến thức bạn sẽ học được

  • Cách đính kèm trình gỡ lỗi vào ứng dụng đang chạy của bạn.
  • Sử dụng các điểm ngắt để tạm dừng một ứng dụng đang chạy và kiểm tra mã từng dòng một.
  • Thêm biểu thức có điều kiện vào các điểm ngắt để tiết kiệm thời gian gỡ lỗi.
  • Thêm biến vào ngăn Đồng hồ để hỗ trợ gỡ lỗi.

Bạn cần có

  • Máy tính đã cài đặt Android Studio.

2. Tạo dự án mới

Thay vì gỡ lỗi một ứng dụng lớn và phức tạp, chúng ta sẽ bắt đầu bằng một dự án trống, rồi tạo một đoạn mã có nhiều lỗi để minh hoạ các công cụ gỡ lỗi trong Android Studio.

Bắt đầu bằng cách tạo một dự án Android Studio mới.

  1. Trên màn hình Select a Project Template (Chọn mẫu dự án), hãy chọn Blank Activity (Hoạt động trống).

a949156bcfbf8a56.png

  1. Đặt tên cho ứng dụng là Gỡ lỗi, hãy nhớ đặt ngôn ngữ thành Kotlin và giữ nguyên mọi thứ khác.

9863157e10628a87.png

  1. Bạn sẽ được chào đón bằng một dự án Android Studio mới, hiển thị một tệp có tên là MainActivity.kt.

e3ab4a557c50b9b0.png

Giới thiệu về lỗi

Bạn còn nhớ ví dụ về phép chia cho 0 ở nội dung gỡ lỗi trong Bài 1 không? Trong vòng lặp cuối cùng, khi ứng dụng cố gắng thực hiện phép chia cho 0, ứng dụng sẽ gặp sự cố với java.langArithmeticException vì không thể chia cho 0. Lỗi đó đã tìm thấy và khắc phục bằng cách kiểm tra dấu vết ngăn xếp và giả định này đã được xác minh bằng cách sử dụng câu lệnh nhật ký.

Như bạn đã biết về ví dụ này, nó sẽ được dùng để minh hoạ cách sử dụng các điểm ngắt. Các điểm ngắt bước qua mã mỗi lần một dòng mà không cần thêm báo cáo nhật ký và chạy lại ứng dụng của bạn trước.

  1. Mở MainActivity.kt và thay mã bằng các nội dung sau:
package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

public val TAG = "MainActivity"

class MainActivity : AppCompatActivity() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)
       division()
   }

   fun division() {
       val numerator = 60
       var denominator = 4
       repeat(5) {
           Log.v(TAG, "${numerator / denominator}")
           denominator--
       }
   }

}
  1. Thực thi ứng dụng. Hãy quan sát sự cố ứng dụng sẽ xảy ra như dự kiến.

9468226e5f4d5729.png

3. Gỡ lỗi bằng điểm ngắt

Khi đã tìm hiểu về cách ghi nhật ký, bạn sẽ học được cách đặt nhật ký theo chiến lược để giúp xác định các lỗi và xác minh lỗi đã được khắc phục. Tuy nhiên, khi gặp lỗi không phải do mình tạo ra thì không phải lúc nào bạn cũng biết rõ vị trí đặt các câu lệnh ghi nhật ký hoặc những biến nào nên in ra. Thông thường, bạn chỉ có thể tìm thấy thông tin này trong thời gian chạy.

fun division() {
    val numerator = 60
    var denominator = 4
    repeat(5) {
        Log.v(TAG, "${numerator / denominator}")
        denominator--
    }
}

Đây là nơi các điểm ngắt xuất hiện! Ngay cả khi không biết rõ nguyên nhân gây ra lỗi dựa trên thông tin trong dấu vết ngăn xếp, bạn vẫn có thể thêm điểm ngắt làm dấu dừng cho một dòng mã cụ thể. Khi đạt đến điểm ngắt, nó sẽ tạm dừng việc thực thi, theo đó, bạn có thể sử dụng các công cụ gỡ lỗi khác trong thời gian chạy để xem cận cảnh điều gì đang diễn ra và sự cố là gì.

Đính kèm trình gỡ lỗi

Sau bối cảnh, Android Studio sử dụng một công cụ được gọi là Cầu gỡ lỗi Android, hay còn được gọi là ADB. Đây là một công cụ dòng lệnh được tích hợp vào Android Studio và cung cấp khả năng gỡ lỗi, chẳng hạn như điểm ngắt, cho các ứng dụng đang chạy của bạn. Công cụ gỡ lỗi thường được gọi là trình gỡ lỗi.

Để sử dụng hoặc đính kèm trình gỡ lỗi vào ứng dụng, bạn không thể chỉ chạy ứng dụng bằng Run > Run (Chạy > Chạy) như trước đây. Thay vào đó, bạn chạy ứng dụng bằng Run > Debug ‘app' (Chạy > Gỡ lỗi "ứng dụng").

340a8e850b3c86d3.png

Thêm điểm ngắt vào dự án của bạn

Thực hiện các bước sau để xem điểm ngắt hoạt động:

  1. Thêm một điểm ngắt bằng cách nhấp vào máng (gutter) bên cạnh số dòng mà bạn muốn tạm dừng. Một dấu chấm sẽ xuất hiện bên cạnh số dòng và dòng này sẽ được đánh dấu.

629ac33dfb3873e.png

  1. Chạy ứng dụng với trình gỡ lỗi được đính kèm sử dụng Run > Debug ‘app' (Chạy > Gỡ lỗi "ứng dụng") hoặc biểu tượng a71c8b295db5927d.png trên thanh công cụ. Khi ứng dụng khởi chạy, bạn sẽ thấy một màn hình như sau:

3bd9cbe69d5a0d0e.png

Khi ứng dụng đã chạy, bạn sẽ thấy điểm ngắt được đánh dấu khi nó được kích hoạt.

928fc1194966c9.png

Ở cuối màn hình mà trước đó bạn đã xem cửa sổ Logcat, một thẻ Gỡ lỗi mới đã mở ra.

447d9743c118babd.png

Bên trái là danh sách các hàm, chính là danh sách các hàm xuất hiện trong dấu vết ngăn xếp. Ở bên phải là ngăn bạn có thể kiểm tra giá trị của các biến riêng lẻ trong hàm hiện tại (tức là division()). Ở trên cùng, cũng có các nút giúp bạn điều hướng chương trình trong khi nó đang tạm dừng. Nút hay sử dụng nhất là Step Over (Bước qua) để thực thi dòng mã được đánh dấu duy nhất.

48219b96d5ab6ba6.png

Thực hiện các bước sau để gỡ lỗi mã:

  1. Sau khi đạt đến điểm ngắt, dòng 19 (khai báo biến numerator) hiện đã được đánh dấu nhưng chưa chạy. Sử dụng nút Step Over fbdcba647f9844c4.png (Bước qua) để thực thi dòng 19. Bây giờ, dòng 20 sẽ được đánh dấu.

eaacf76805166461.png

  1. Đặt điểm ngắt tại dòng 22. Đây là nơi diễn ra sự phân chia và là dòng mà dấu vết ngăn xếp báo cáo ngoại lệ.

1f18ab31dc58a1a7.png

  1. Dùng nút Resume Program616d16841834ae2a.png (Tiếp tục chương trình) ở bên trái cửa sổ Debug (Gỡ lỗi) để chuyển đến điểm ngắt tiếp theo. Chạy phần còn lại của hàm division().

3a9c3edc893f9720.png

  1. Lưu ý việc thực thi sẽ dừng ở dòng 17 trước khi thực thi nó.

aa56331ad870cd40.png

  1. Giá trị của mỗi biến numeratordenominator hiển thị bên cạnh các nội dung khai báo của biến đó. Bạn có thể xem giá trị của các biến trong cửa sổ gỡ lỗi trên thẻ Biến.

5b3515c5580ee7dd.png

  1. Nhấn nút Resume Program (Tiếp tục chương trình) ở bên trái cửa sổ gỡ lỗi bốn lần. Mỗi khi vòng lặp tạm dừng và quan sát các giá trị của numeratordenominator. Trong lần lặp lại gần nhất, numerator phải là 60denominator phải là 0. Và bạn không thể chia 60 cho 0!

56ea223612b88125.png

Bây giờ bạn đã biết dòng mã chính xác gây ra lỗi và biết chính xác lý do. Giống như trước đây, bạn có thể sửa lỗi bằng cách thay đổi số lần lặp lại mã từ 5 thành 4.

fun division() {
    val numerator = 60
    var denominator = 4
    repeat(4) {
        Log.v(TAG, "${numerator / denominator}")
        denominator--
    }
}

4. Đặt điều kiện cho điểm ngắt

Trong phần trước, bạn phải thực hiện từng bước lặp của vòng lặp cho đến khi mẫu số bằng 0. Trong các ứng dụng phức tạp hơn, cách này có thể khiến bạn thấy tẻ nhạt khi có ít thông tin hơn về lỗi. Tuy nhiên, nếu có giả định (chẳng hạn như ứng dụng chỉ gặp sự cố khi mẫu số bằng 0), bạn có thể sửa đổi điểm ngắt để điểm ngắt chỉ bị đạt đến nếu giả định này được đáp ứng thay vì phải vượt qua từng bước lặp của vòng lặp.

  1. Nếu cần, hãy tạo lại lỗi bằng cách thay đổi 4 thành 5 trong vòng lặp lại.
repeat(4) {
    ...
}
  1. Đặt điểm ngắt mới trên dòng có câu lệnh repeat.

47fcc3aeb814a9d7.png

  1. Nhấp chuột phải vào biểu tượng điểm ngắt màu đỏ. Một trình đơn sẽ xuất hiện với một vài tuỳ chọn, chẳng hạn như liệu có bật điểm ngắt hay không. Điểm ngắt bị vô hiệu hoá vẫn tồn tại nhưng sẽ không được kích hoạt trong thời gian chạy. Bạn cũng có thể thêm biểu thức Kotlin nếu biểu thức này đánh giá là đúng, điểm ngắt sẽ được kích hoạt. Ví dụ: nếu bạn sử dụng biểu thức denominator > 3, điểm ngắt sẽ chỉ được kích hoạt trong lần lặp đầu tiên của vòng lặp. Để chỉ kích hoạt điểm ngắt khi ứng dụng có khả năng chia cho 0, hãy đặt biểu thức thành denominator == 0. Các tuỳ chọn cho điểm ngắt phải có dạng như sau:

76045ef783d5389b.png

  1. Chạy ứng dụng sử dụng Run > Debug ‘app' (Chạy > Gỡ lỗi "ứng dụng") và quan sát thấy điểm ngắt đã đạt đến.

74ba264a6eab7db7.png

Bạn có thể thấy mẫu số này đã bằng 0. Điểm ngắt chỉ được kích hoạt khi điều kiện đã được đáp ứng, giúp bạn tiết kiệm thời gian và công sức duyệt mã.

153be06e8a19e61d.png

  1. Giống như trước đây, bạn sẽ thấy lỗi là do vòng lặp thực thi một quá nhiều lần, trong đó mẫu số được đặt thành 0.

Thêm đồng hồ

Nếu muốn theo dõi một giá trị cụ thể trong khi gỡ lỗi, bạn không cần phải tìm kiếm trong thẻ Variables (Biến) để tìm giá trị đó. Bạn có thể thêm Đồng hồ để theo dõi các biến cụ thể. Những biến này sẽ hiển thị trong ngăn gỡ lỗi. Khi việc thực thi bị tạm dừng và biến đó nằm trong phạm vi thực thi, biến đó sẽ hiển thị trong ngăn Đồng hồ. Thao tác này giúp việc gỡ lỗi của bạn hiệu quả hơn khi làm việc với các dự án lớn hơn. Bạn sẽ có thể theo dõi tất cả các biến có liên quan ở cùng một nơi.

  1. Trong chế độ xem gỡ lỗi, ở bên phải ngăn biến sẽ có một ngăn trống khác có tên Đồng hồ. Nhấp vào nút dấu cộng c97b1f6a879b0563.png ở góc trên cùng bên trái. Bạn có thể thấy một tuỳ chọn trình đơn với nội dung Đồng hồ mới.

4d27cc7c5222377b.png

  1. Nhập tên của biến denominator vào trường được cung cấp và nhấp Enter.
  2. Chạy lại ứng dụng của bạn bằng cách Chạy > gỡ lỗi 'ứng dụng' và quan sát thấy khi đạt đến điểm ngắt, bạn sẽ thấy giá trị của mẫu số trong ngăn Đồng hồ.

5. Xin chúc mừng

Tóm tắt:

  • Bạn có thể đặt để các điểm ngắt tạm dừng việc thực thi ứng dụng.
  • Khi việc thực thi bị dừng, bạn có thể "can thiệp" để chỉ thực thi một dòng mã.
  • Bạn có thể đặt các câu lệnh có điều kiện để chỉ kích hoạt các điểm ngắt dựa trên biểu thức Kotlin.
  • Đồng hồ cho phép bạn nhóm các biến quan tâm khi gỡ lỗi.

Tìm hiểu thêm