Tóm Tắt
Dẫn nhập
Ở bài INTENT & MANIFEST, chúng ta đã có một cái nhìn tổng quan về các thành phần của một ứng dụng Android như Service, Broadcast Receiver, và không thể thiếu… Activity.
Về cơ bản, các bạn có thể hiểu Activity là một “màn hình” trong ứng dụng Android. Nhưng thật sự có phải chỉ như vậy? Và cái mà người ta hay nói là “vòng đời” của activity thật sự nó là gì?
Chúng ta sẽ cùng nhau tìm hiểu trong bài viết này nhé!
Bạn đang đọc: Vòng đời của Activity trong Android | How Kteam
Nội dung
Để đọc hiểu bài này tốt nhất những bạn nên có kiến thức và kỹ năng cơ bản về những phần :
- Android Manifest (xem lại bài trước – INTENT & MANIFEST để biết thêm chi tiết).
- Cách viết một ứng dụng Android cơ bản (xem lại bài GIỚI THIỆU LẬP TRÌNH ANDROID để biết thêm chi tiết).
- Một suy nghĩ đơn giản. Thật vậy đó, vì bản chất của Activity khá đơn giản, các bạn không nên chỉ trông mấy cái sơ đồ mà thấy sợ.
Trong bài học kinh nghiệm này, tất cả chúng ta sẽ cùng khám phá những yếu tố :
- Activity là gì.
- Vòng đời của một Activity.
- Các trạng thái của một Activity.
- Tùy chỉnh trạng thái của Activity.
- Đố vui… không có thưởng (nhưng có lời giải) về Activity.
Biên niên sử về vòng đời ứng dụng
Trong trường hợp lý tưởng nhất hoàn toàn có thể, toàn bộ những ứng dụng Android sau khi chạy đều được lưu lại trong bộ nhớ ( đơn cử là RAM ), để sau này ứng dụng hoàn toàn có thể khởi động lại nhanh hơn .
Tuy nhiên trên thực tiễn, những thiết bị di động có tài nguyên phần cứng khá hạn chế, về cả RAM, vận tốc giải quyết và xử lý, … và vì thế ứng dụng nào ít được sử dụng sẽ bị hủy tiến trình chạy nhằm mục đích tịch thu bộ nhớ .
Quy tắc tịch thu bộ nhớ của Android rất đơn thuần : Các tiến trình ứng dụng sẽ được tịch thu theo một thứ tự ưu tiên nhất định. Và thứ tự ưu tiên đó là :
Tất cả những ứng dụng trong danh sách “Rỗng” sẽ được đưa vào danh sách LRU (Least-Recently Used – Ít sử dụng gần đây nhất) và các tiến trình ở đầu danh sách này sẽ bị hủy nếu được yêu cầu từ hệ thống. Nếu ứng dụng được gọi lại bởi người dùng, chúng sẽ lại được đưa xuống cuối danh sách LRU.
Vòng đời của Activity
Trạng thái của Activity
Vừa rồi chúng ta đã có cái nhìn tổng thể về vòng đời của ứng dụng (xin nhắc lại là cả ứng dụng – Application nhé, không chỉ bao gồm Activity). Và bây giờ là đến món chính: Activity.
Một Activity hoàn toàn có thể trong những trạng thái khác nhau tùy vào cách người dùng đang tương tác với nó. Các trạng thái đó được liệt kê trong bảng sau :
Các phương thức trạng thái của Activity
Android phân phối 1 số ít những phương pháp để điều khiển và tinh chỉnh tiến trình thao tác trong vòng đời của Activity. Các phương pháp quan trọng hoàn toàn có thể kể đến là :
Vòng đời của Activity với 1 số ít phương pháp quan trọng chính được miêu tả bằng biểu đồ sau :
savedInstanceState
savedInstanceState cũng là một trong các thành phần của trạng thái trong vòng đời của một Activity. Đây là…
- Một loại dữ liệu không bền vững.
- Không được lưu trữ cụ thể trong đâu ngoài bộ nhớ RAM.
- Nó được sử dụng để truyền, phục hồi, lưu trạng thái của một Activity.
Vậy nó dùng làm gì?
Các bạn có biết rằng, một Activity, khi đổi chiều xoay màn hình và Activity đó có hỗ trợ chế độ ngang (landscape) thì cả Activity đó sẽ bị destroy.
Xin nhắc lại: Cả Activity sẽ bị destroy khi bị xoay màn hình.
- Lấy ví dụ đơn giản: Bạn viết một app máy tính bỏ túi đơn giản, chỉ có cộng trừ. Sau khi tính xong phép tính 2+3=5, bạn xoay màn hình, phép tính biến mất.
- Dữ liệu trong savedInstanceState được lưu dưới dạng Bundle.
- Được phục hồi khi phương thức onCreate và onRestoreSavedInstanceState được gọi.
- Được lưu trước onStop, với phương thức onSaveInstanceState.
Thực hành: Làm quen với vòng đời của Activity
Để thực hiện phần thực hành này, chúng ta sẽ tạo một project mới, với package name giống như project HelloWorld trong bài GIỚI THIỆU LẬP TRÌNH ANDROID, nhưng với tên ứng dụng là ActivityLifecycle. Các bạn chưa rõ hay đã quên cách tạo ứng dụng vui lòng xem lại bài GIỚI THIỆU LẬP TRÌNH ANDROID.
Bước 1: Tạo project với các thông tin như sau:
- API: Như project HelloWorld, chúng ta sẽ đặt API ở mức 13 (Android 3.2)
- Activity: Chọn Empty Activity và nhấn Finish.
- Đợi một lúc và chúng ta có được project ban đầu như hình:
Bước 2: Việc chúng ta cần làm là điều tra xem ứng dụng của mình trong quá trình thao tác sẽ rơi vào những trạng thái nào: Running / Paused / Stop,…. Chúng ta sẽ sửa code của MainActivity thành như sau:
public class MainActivity extends AppCompatActivity {
private static final String STATE = "Trang thai";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(STATE, "onCreate");
}
@Override
protected void onPause() {
super.onPause();
Log.e(STATE, "onPause");
}
@Override
protected void onResume() {
super.onResume();
Log.e(STATE, "onResume");
}
@Override
protected void onStop() {
super.onStop();
Log.e(STATE, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e(STATE, "onDestroy");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.e(STATE, "onRestoreInstanceState");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.e(STATE, "onSaveInstanceState");
}
}
Sau đó bấm Run để chạy chương trình trên máy. Chúng ta thấy gì?
Vậy là theo đúng thứ tự : Ứng dụng khi khởi chạy sẽ mở màn từ onCreate ( ) đến onResume ( ). Như những bạn đã nhìn thấy trong Log .
Bước 3: Bây giờ các bạn hãy bấm nút Home để tạm ra khỏi app và kiểm tra log:
Như những bạn thấy, Activity đi tiếp từ onPause đến onSaveInstanceState rồi đến onStop .
Bước 4: Mở lại ứng dụng và xem Log tiếp nào…
Ồ, ứng dụng đã quay trở lại với việc hàm onResume được gọi .
Bước 5: Nào, tiếp theo chúng ta hãy xoay ngang màn hình, như ở ví dụ trên là máy ảo AVD thì icon là . Và…
Phần khung đỏ là những gì đã xảy ra khi chúng ta xoay màn hình. Cụ thể ở đây là Activity bị tiêu hủy hoàn toàn (onDestroy) và được tái tạo lại (onCreate).
Câu đố
Câu đố của phần này là : Một Activity luôn có vòng đời từ onCreate đến onDestroy. Giữa những bước vòng đời này có onPause và onStop. Có cách nào đi thẳng từ onCreate đến onDestroy mà không cần qua onPause và onStop không ?
Xem đáp án ở cuối bài viết !
Thực hành : Làm quen với savedInstanceState
Ví dụ sau đây sử dụng tiếp code ở phần Activity ngay trên .
Chúng ta sẽ làm một máy tính cá nhân nhỏ, chỉ có chức năng cộng số.
Mục tiêu là khi xoay ngang xoay dọc màn hình thì số hiển thị vẫn được lưu lại màn hình chứ không bị mất đi.
Bước 1: Tạo một file Java Activity mới. Chỉ cần tạo lại file Java thôi để sau này các bạn xem lại code đỡ nhầm lẫn với phần Activity ở trên. Vào File > New > Java Class:
Bước 2: Đặt tên file là SavedInstanceActivity:
Bước 3: Sửa nội dung file /res/layout/activity_main.xml thành như sau:
- Và sửa lại file AndroidManifest. xml như sau:
- Class SavedInstanceActivity có nội dung như sau:
package com.howkteam.activitylifecycle;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class SavedInstanceActivity extends AppCompatActivity implements View.OnClickListener {
private EditText etFirstNumber;
private EditText etSecondNumber;
private TextView tvResult;
private Button btnTinhTong;
private int firstNumber;
private int secondNumber;
private int result;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etFirstNumber = (EditText) findViewById(R.id.et_first_number);
etSecondNumber = (EditText) findViewById(R.id.et_second_number);
tvResult = (TextView) findViewById(R.id.tv_result);
btnTinhTong = (Button) findViewById(R.id.btn_tinh_tong);
btnTinhTong.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if (view == btnTinhTong) {
if (etFirstNumber.getText().toString().isEmpty() || etSecondNumber.getText().toString().isEmpty()) {
Toast.makeText(this, "Vui long nhap so", Toast.LENGTH_SHORT).show();
} else {
firstNumber = Integer.parseInt(etFirstNumber.getText().toString());
secondNumber = Integer.parseInt(etSecondNumber.getText().toString());
result = firstNumber + secondNumber;
tvResult.setText(String.valueOf(result));
}
}
}
}
Chạy thử, và tính thử một phép tính đơn thuần :
Nhưng khi xoay ngang màn hình hiển thị thì tác dụng đã biến mất do Activity bị Destroy :
Bước 4: Nếu bạn đã thí nghiệm xong về trạng thái của Activity ở Bước 3 và muốn giữ thông tin ở các ô nhập thì hãy thực hiện tiếp bước này. Sửa code của class SavedInstanceActivity thành như sau:
package com.howkteam.activitylifecycle;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class SavedInstanceActivity extends AppCompatActivity implements View.OnClickListener {
private EditText etFirstNumber;
private EditText etSecondNumber;
private TextView tvResult;
private Button btnTinhTong;
private int firstNumber;
private int secondNumber;
private int result;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etFirstNumber = (EditText) findViewById(R.id.et_first_number);
etSecondNumber = (EditText) findViewById(R.id.et_second_number);
tvResult = (TextView) findViewById(R.id.tv_result);
if (savedInstanceState != null) {
etFirstNumber.setText(String.valueOf(savedInstanceState.getInt("SO_THU_NHAT")));
etSecondNumber.setText(String.valueOf(savedInstanceState.getInt("SO_THU_HAI")));
tvResult.setText(String.valueOf(savedInstanceState.getInt("KET_QUA")));
}
btnTinhTong = (Button) findViewById(R.id.btn_tinh_tong);
btnTinhTong.setOnClickListener(this);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
if (!tvResult.getText().toString().isEmpty()) {
outState.putInt("SO_THU_NHAT", Integer.parseInt(etFirstNumber.getText().toString()));
outState.putInt("SO_THU_HAI", Integer.parseInt(etSecondNumber.getText().toString()));
outState.putInt("KET_QUA", Integer.parseInt(tvResult.getText().toString()));
}
}
@Override
public void onClick(View view) {
if (view == btnTinhTong) {
if (etFirstNumber.getText().toString().isEmpty() || etSecondNumber.getText().toString().isEmpty()) {
Toast.makeText(this, "Vui long nhap so", Toast.LENGTH_SHORT).show();
} else {
firstNumber = Integer.parseInt(etFirstNumber.getText().toString());
secondNumber = Integer.parseInt(etSecondNumber.getText().toString());
result = firstNumber + secondNumber;
tvResult.setText(String.valueOf(result));
}
}
}
}
Ở đây mình xin lý giải code một chút ít :
- Trong hàm onCreate, mình check xem savedInstanceStatecó null không, nếu null thì tức là nó không có dữ liệu, còn không null thì tức là đã có số được lưu ở trước đó. Và nếu không null thì chúng ta lấy các số đó ra đưa lên hiển thị:
- SO_THU_NHAT là key để lấy ra giá trị của số thứ nhất trong savedInstanceState.
- SO_THU_HAI là key để lấy ra giá trị của số thứ hai trong savedInstanceState.
- KET_QUA là key để lấy ra giá trị của kết quả trong savedInstanceState.
- Trong hàm onSaveInstanceState, mình lưu các giá trị đã nhập ở các ô cũng theo đúng 3 key ở trên. Trước khi lưu có kiểm tra xem phép tính đã có kết quả hay chưa.
Và giờ đây xoay kiểu gì thì xoay, tác dụng vẫn được lưu lại .
Đáp án câu đố
Rất đơn thuần, chỉ việc gọi hàm finish ( ) ngay trong onCreate ( ). Lúc này Activity sẽ bị destroy ngay lúc khởi tạo. Kiểu kiểu như này này :
package com.howkteam.fragmentexample;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
finish();
}
}
Kết luận
Qua bài này tất cả chúng ta đã nắm được về vòng đời của một Activity và hiểu về chính sách của savedInstanceState .
Bài sau chúng ta sẽ tìm hiểu về Fragment, vòng đời của một FRAGMENT VÀ CƠ CHẾ BACKSTACK
Cảm ơn các bạn đã theo dõi bài viết. Hãy để lại bình luận hoặc góp ý của mình để phát triển bài viết tốt hơn. Đừng quên “Luyện tập – Thử thách – Không ngại khó”.
Thảo luận
Nếu bạn có bất kể khó khăn vất vả hay vướng mắc gì về khóa học, đừng ngần ngại đặt câu hỏi trong phần bên dưới hoặc trong mục HỎI và ĐÁP trên thư viện Howkteam. com để nhận được sự tương hỗ từ hội đồng .
Source: https://final-blade.com
Category: Kiến thức Internet