onCreate — nó là gì, khởi tạo Activity trong Android

Tác giả: IT Sectr Đã đăng: 2026-03-03 Thời gian đọc: 10 phút

onCreate là phương thức đầu tiên và duy nhất bắt buộc trong vòng đời của Activity và Fragment trong Android. Hệ thống gọi nó một lần khi tạo một thành phần, truyền tham số Bundle với trạng thái đã lưu trước đó. Bên trong onCreate, nhà phát triển khởi tạo giao diện người dùng, liên kết các phần tử View, cấu hình trình xử lý sự kiện và khôi phục dữ liệu từ savedInstanceState. Nếu không có triển khai onCreate đúng, không một ứng dụng Android nào có thể khởi chạy — nó là điểm vào cho mỗi màn hình. Để biết thêm chi tiết về vòng đời Activity nói chung, hãy đọc bài viết Activity Lifecycle.

Điểm chính

  • onCreate — phương thức vòng đời đầu tiên và duy nhất bắt buộc; được gọi một lần khi tạo Activity hoặc Fragment
  • Tham số Bundle — savedInstanceState chứa dữ liệu đã lưu trong onSaveInstanceState, hoặc null nếu Activity được tạo lần đầu
  • setContentView — lệnh gọi bắt buộc trong onCreate cho Activity; liên kết bố cục XML với mã
  • Khởi tạo UI — findViewById, thiết lập bộ chuyển đổi RecyclerView, thiết lập trình lắng nghe nhấp — các tác vụ onCreate điển hình
  • Fragment.onCreate — khác với Activity: ở đây không gọi setContentView, bố cục được truyền qua onCreateView
  • Giới hạn thời gian — onCreate phải hoàn thành trong 5 giây (ngưỡng ANR), các thao tác dài được chuyển sang luồng nền
  • ViewModel và onCreate — khởi tạo ViewModel trong onCreate cho phép dữ liệu sống sót qua xoay màn hình mà không mất

OnCreate trong Android là gì

onCreate là một phương thức gọi lại (callback) mà Android gọi khi tạo một thể hiện mới của Activity hoặc Fragment. Đây là điểm vào đầu tiên trong mã màn hình người dùng: không có mã người dùng nào được thực thi trước khi onCreate được gọi. Hệ thống truyền một tham số Bundle cho phương thức, chứa dữ liệu đã lưu trước đó (khi tạo lại) hoặc null (khi khởi chạy lần đầu).

Phương thức onCreate được định nghĩa trong lớp android.app.Activity và trong lớp androidx.fragment.app.Fragment. Cả hai biến thể đều thực hiện các tác vụ tương tự: khởi tạo thành phần, thiết lập UI và khôi phục trạng thái. Tuy nhiên, cách triển khai cụ thể khác nhau — Activity sử dụng setContentView để tải bố cục, trong khi Fragment trả về View qua onCreateView. Nhà phát triển phải ghi đè ít nhất onCreate trong Activity — nếu không, Android không thể hiển thị màn hình.

onCreate được gọi nghiêm ngặt một lần trong toàn bộ vòng đời của một thể hiện Activity. Ngay cả khi xoay màn hình, một thể hiện Activity mới nhận được một lệnh gọi onCreate mới với Bundle từ thể hiện trước. Điều này làm cho onCreate trở thành nơi lý tưởng cho việc khởi tạo một lần: tải dữ liệu, tạo bộ chuyển đổi, thiết lập các thành phần DI qua Dagger hoặc Hilt.

onCreate trong Activity

Trong Activity, phương thức onCreate thực hiện bốn tác vụ chính: tải bố cục layout, khởi tạo các phần tử View, khôi phục trạng thái từ Bundle và thiết lập trình xử lý sự kiện chính. Mã tối thiểu bắt buộc trong onCreate là gọi super.onCreate(savedInstanceState)setContentView(R.layout.activity_main).

kotlin
class MainActivity : AppCompatActivity() {
    private var binding: ActivityMainBinding? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ViewBinding — sự thay thế hiện đại cho findViewById
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding?.root)

        // Khởi tạo bằng binding
        binding?.apply {
            welcomeText.text = getString(R.string.welcome)
            startButton.setOnClickListener { startGame() }
        }

        // Khôi phục trạng thái
        if (savedInstanceState != null) {
            score = savedInstanceState.getInt("score", 0)
            binding?.scoreText?.text = score.toString()
        }
    }
}

Thực hành hiện đại sử dụng ViewBinding thay vì findViewById. ViewBinding tạo lớp ActivityMainBinding tại thời điểm biên dịch, loại bỏ lỗi do ID không chính xác và giảm mã mẫu. Google khuyến nghị ViewBinding là cách tiêu chuẩn để truy cập View trong Activity và Fragment kể từ Android Studio 3.6.

Thứ tự các thao tác trong onCreate phải nghiêm ngặt: đầu tiên super, sau đó setContentView, rồi mọi thứ khác. Gọi findViewById trước setContentView trả về null — bố cục chưa được tải và các phần tử View không tồn tại trong hệ phân cấp. Đây là một trong những lỗi phổ biến nhất của các nhà phát triển Android mới bắt đầu.

onCreate trong Fragment

onCreate trong Fragment khác với Activity: ở đây không gọi setContentView, chỉ thực hiện khởi tạo dữ liệu không liên quan đến UI. Fragment tách việc tạo thành phần và tạo View thành hai phương thức riêng biệt: onCreate (được gọi một lần) và onCreateView (được gọi mỗi khi View được tạo hoặc tạo lại).

kotlin
class UserListFragment : Fragment() {
    private lateinit var viewModel: UserViewModel
    private var binding: FragmentUserListBinding? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Khởi tạo ViewModel — sống sót qua việc tạo lại View
        viewModel = ViewModelProvider(this)[UserViewModel::class.java]

        // Đối số từ FragmentManager
        arguments?.let {
            viewModel.loadUser(it.getString("user_id") ?: "")
        }

        // Lưu khi xoay
        retainInstance = true
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentUserListBinding.inflate(inflater, container, false)
        return binding!!.root
    }
}

Sự khác biệt chính giữa onCreate của Activity và Fragment: onCreate trong Fragment không được chứa mã liên quan đến View, vì View có thể bị phá hủy và tạo lại (ví dụ, khi chuyển đổi tab ViewPager), trong khi onCreate chỉ được gọi một lần. Tải dữ liệu, thiết lập ViewModel và khởi tạo bộ chuyển đổi là các tác vụ của onCreate, trong khi liên kết View là tác vụ của onViewCreated.

savedInstanceState và khôi phục trạng thái

Tham số savedInstanceState trong onCreate là một cơ chế để lưu và khôi phục trạng thái tạm thời của Activity hoặc Fragment. Khi hệ thống phá hủy một Activity (xoay màn hình, thiếu bộ nhớ), nó gọi onSaveInstanceState(), nơi nhà phát triển đặt các mục khóa-giá trị vào Bundle. Khi một thể hiện mới được tạo, Bundle này được trả về trong onCreate.

Bundle hỗ trợ các kiểu dữ liệu sau: String, Integer, Boolean, Long, Float, Double, mảng của chúng, cũng như các đối tượng Parcelable và Serializable. Đối với các đối tượng phức tạp, Parcelable được sử dụng — một cơ chế tuần tự hóa hiệu quả hơn dành riêng cho Android. Kích thước Bundle bị giới hạn ở khoảng 500 KB — vượt quá giới hạn sẽ gây ra TransactionTooLargeException.

kotlin
companion object {
    private const val KEY_USER_NAME = "user_name"
    private const val KEY_SCORE = "score"
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_game)

    if (savedInstanceState != null) {
        userName = savedInstanceState.getString(KEY_USER_NAME) ?: ""
        currentScore = savedInstanceState.getInt(KEY_SCORE)
    }
}

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putString(KEY_USER_NAME, userName)
    outState.putInt(KEY_SCORE, currentScore)
}

Điều quan trọng cần hiểu: onSaveInstanceState không được gọi khi người dùng đóng Activity một cách rõ ràng qua finish() hoặc nút Quay lại. Hệ thống cho rằng người dùng đang kết thúc công việc một cách có ý thức và không cần lưu trạng thái. Do đó, bạn không thể chỉ dựa vào savedInstanceState để lưu trữ dữ liệu dài hạn — hãy sử dụng Room, DataStore hoặc SharedPreferences.

Thời gian và giới hạn của onCreate

onCreate thực thi trên luồng chính (UI) và hệ thống chờ nó hoàn thành trước khi hiển thị Activity trên màn hình. Nếu onCreate mất hơn 5 giây, hệ thống hiển thị hộp thoại ANR (Application Not Responding) và đề nghị người dùng đóng ứng dụng. Các thao tác dài, như tải dữ liệu từ mạng hoặc đọc từ cơ sở dữ liệu, phải được chuyển sang luồng nền.

Theo khuyến nghị của Google Android Performance (2025), onCreate sẽ hoàn thành trong dưới 1 giây trên các thiết bị tầm trung. Để đạt được điều này: sử dụng khởi tạo lười (lazy delegate trong Kotlin), hoãn tải dữ liệu nặng sang onResume hoặc qua coroutines, áp dụng ViewStub cho các thành phần UI ít được sử dụng và lập hồ sơ thời gian khởi động qua Android Vitals.

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

    // Khởi tạo lười — đối tượng chỉ được tạo khi truy cập lần đầu
    val heavyData by lazy {
        HeavyDataLoader.load()
    }

    // Tải dữ liệu trong luồng nền qua lifecycleScope
    lifecycleScope.launch(Dispatchers.IO) {
        val users = userDao.getAllUsers()
        withContext(Dispatchers.Main) {
            adapter.submitList(users)
        }
    }
}

Công cụ lập hồ sơ: Android Studio Profiler (tab CPU) hiển thị thời gian thực thi chính xác của từng phương thức. Trong Android Vitals (Google Play Console), bạn có thể theo dõi chỉ số “Thời gian khởi động nguội” — nếu onCreate của Activity vượt quá 500 ms, bảng điều khiển sẽ đánh dấu đây là vấn đề hiệu suất. Tại IT Sectr, chúng tôi sử dụng các bài kiểm tra Macrobenchmark để tự động kiểm soát thời gian khởi động của mỗi Activity trong đường ống CI.

ViewModel và onCreate

ViewModel là cách tốt nhất để khởi tạo dữ liệu trong onCreate mà cần sống sót qua xoay màn hình. ViewModel được tạo trong onCreate qua ViewModelProvider và được giữ lại tự động khi có thay đổi cấu hình. Khi một Activity được tạo lại sau khi xoay, ViewModel vẫn còn trong bộ nhớ và onCreate nhận được cùng ViewModel mà không mất dữ liệu.

kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_profile)

    // ViewModel được tạo một lần và sống sót qua các thay đổi cấu hình
    val viewModel: ProfileViewModel =
        ViewModelProvider(this)[ProfileViewModel::class.java]

    // Quan sát LiveData — UI tự động cập nhật khi dữ liệu thay đổi
    viewModel.user.observe(this) { user ->
        binding?.userName?.text = user.name
        binding?.userEmail?.text = user.email
    }

    // Tải dữ liệu nếu ViewModel vừa được tạo
    if (savedInstanceState == null) {
        viewModel.loadProfile(userId)
    }
}

Sự kết hợp ViewModel + LiveData/StateFlow giải quyết vấn đề xoay màn hình mà không cần lưu thủ công vào Bundle. ViewModel lưu trữ dữ liệu trong bộ nhớ, LiveData tự động đăng ký lại Activity khi tạo lại và StateFlow (từ Kotlin Coroutines) thêm tính phản ứng với hỗ trợ coroutine. Đây là kiến trúc tiêu chuẩn được Google khuyến nghị trong Guide to App Architecture.

Các lỗi thường gặp khi làm việc với onCreate

Ngay cả các nhà phát triển có kinh nghiệm cũng mắc phải các lỗi điển hình trong onCreate. Hãy xem xét năm vấn đề phổ biến nhất và cách tránh chúng.

Làm việc với View trước setContentView

Lỗi phổ biến nhất là cố gắng tìm View qua findViewById trước khi gọi setContentView. Tất cả các phần tử View được tạo tại thời điểm mở rộng bố cục, vì vậy bất kỳ lệnh gọi findViewById nào trước setContentView đều trả về null và gây ra NullPointerException khi cố gắng sử dụng View. Giải pháp: thứ tự nghiêm ngặt — đầu tiên super, sau đó setContentView, rồi findViewById hoặc ViewBinding.

Chặn luồng UI bằng các thao tác dài

Tải dữ liệu từ mạng, đọc từ cơ sở dữ liệu hoặc xử lý mảng lớn trực tiếp trong onCreate sẽ chặn việc kết xuất khung hình đầu tiên. Người dùng nhìn thấy màn hình đen cho đến khi onCreate hoàn thành, điều này làm giảm nhận thức về tốc độ ứng dụng. Giải pháp: sử dụng lifecycleScope.launch cho các thao tác bất đồng bộ, hiển thị khung xương (UI placeholder) cho đến khi tải xong.

Bỏ qua savedInstanceState

Nếu bạn không khôi phục trạng thái từ Bundle khi xoay màn hình, người dùng sẽ mất tất cả dữ liệu nhập chưa được lưu: văn bản trong trường biểu mẫu, vị trí cuộn, các mục đã chọn. Giải pháp: luôn kiểm tra savedInstanceState != null trong onCreate để khôi phục dữ liệu, ngay cả khi việc mất trạng thái có vẻ không chắc chắn.

Rò rỉ bộ nhớ qua các lớp ẩn danh

Các lớp ẩn danh và lambda trong onCreate có thể ngầm giữ tham chiếu đến Activity sau khi nó bị phá hủy. Ví dụ, Handler được tạo trong onCreate tiếp tục thực hiện các tác vụ trễ ngay cả sau khi Activity bị phá hủy. Giải pháp: sử dụng LifecycleObserver, ViewModel và lifecycleScope, tự động hủy các tác vụ khi bị phá hủy.

Khởi tạo quá mức trong Fragment.onCreate

Khởi tạo View trong Fragment.onCreate là một lỗi logic, vì View có thể được tạo lại mà không cần gọi onCreate. Nếu bạn đặt trình lắng nghe trong onCreate nhưng liên kết View trong onCreateView, trình lắng nghe sẽ vẫn ở lại trên View cũ khi tạo lại. Giải pháp: thực hiện tất cả công việc liên quan đến View trong onViewCreated, để onCreate chỉ dành cho việc khởi tạo lớp dữ liệu.

Câu hỏi thường gặp

Có bắt buộc phải ghi đè onCreate trong Activity không?

Có, việc ghi đè onCreate là bắt buộc đối với bất kỳ Activity nào hiển thị giao diện người dùng. Nếu không có nó, không thể gọi setContentView và tải bố cục XML. Nếu Activity không có UI (ví dụ, Activity giả trong suốt), onCreate vẫn được ghi đè, nhưng không gọi setContentView.

OnCreate có thể được gọi lại mà không phá hủy Activity không?

Không, onCreate không thể được gọi lại cho cùng một thể hiện Activity. Nếu Activity bị phá hủy và tạo lại (xoay màn hình, thiếu bộ nhớ), đó là một thể hiện mới với một lệnh gọi onCreate mới. Ngoại lệ là phương thức recreate(), phá hủy và tạo lại Activity một cách cưỡng bức, nhưng đây là việc tạo lại một thể hiện mới.

Điều gì xảy ra nếu không gọi super.onCreate?

Nếu bạn không gọi super.onCreate(savedInstanceState), Android Runtime sẽ ném ngoại lệ SuperNotCalledException và ứng dụng sẽ bị sập. Hệ thống yêu cầu nghiêm ngặt rằng mỗi phương thức vòng đời được ghi đè phải gọi phiên bản super của nó — điều này đảm bảo hoạt động chính xác của máy trạng thái nội bộ.

OnCreate trong Activity khác với onCreate trong Fragment như thế nào?

Sự khác biệt chính: onCreate trong Activity tải UI qua setContentView, trong khi onCreate trong Fragment chỉ khởi tạo dữ liệu. Fragment tạo View trong một phương thức riêng onCreateView, có thể được gọi nhiều lần (ví dụ, khi chuyển tab), trong khi onCreate của Fragment được gọi một lần trong suốt vòng đời của thể hiện Fragment.

Làm thế nào để truyền dữ liệu từ onCreate sang các phương thức khác?

Dữ liệu được khởi tạo trong onCreate được lưu trữ trong các trường của lớp Activity hoặc Fragment. Ví dụ, private lateinit var binding: ActivityMainBinding được khai báo ở cấp lớp, được khởi tạo trong onCreate và có sẵn trong tất cả các phương thức tiếp theo. Đối với dữ liệu sống sót qua xoay màn hình, hãy sử dụng ViewModel với LiveData hoặc StateFlow.

Tóm tắt

  • onCreate — một phương thức vòng đời bắt buộc, được gọi một lần khi tạo Activity hoặc Fragment
  • setContentView — một lệnh gọi bắt buộc cho Activity, tải bố cục XML; đối với Fragment, bố cục được tải qua onCreateView
  • savedInstanceState — Bundle với trạng thái đã lưu khi tạo lại; null ở lần khởi chạy đầu
  • Giới hạn thời gian — onCreate nên hoàn thành trong vòng dưới 1 giây, các thao tác dài được chuyển sang coroutines
  • ViewModel — khởi tạo ViewModel trong onCreate giải quyết vấn đề mất dữ liệu khi xoay màn hình
  • Fragment vs Activity — Fragment.onCreate không chứa mã UI, Activity.onCreate tải bố cục qua setContentView
  • Năm lỗi điển hình — làm việc với View trước setContentView, chặn UI, bỏ qua Bundle, rò rỉ bộ nhớ, mã UI trong Fragment.onCreate

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm