06 January 2017

Android: Cách thức hoạt động của Activity Stack

Cách thức hoạt động của Activity Stack
  • Khi Activity 1 run nó tạo một Stack mới (Activity 1 nó được đặt trên đỉnh stack và trở thành running activity).
  • Khi Activity 2 run tiếp đè lên Activity 1 (Activity 2 Nó được đặt trên đỉnh stack và trở thành running activity).
  • Khi Activity 2 hủy (Activity 1 nó được đặt trên đỉnh stack và trở thành running activity).
  • .....Nếu Activity 3 run tiếp đè lên Activity 2 thì (Activity 3 nó được đặt trên đỉnh stack và trỏe thành running activity)
  • ....Cứ như thế cho tới activity n+1 full ram máy

Entire Lifetime
Bảy phương thức chuyển trạng thái (Figure 3) xác định toàn bộ cuộc đời của một activity. 
•Toàn bộ cuộc đời của một activity bắt đầu từ lời gọi onCreate() đầu tiên tới một lời gọi onDestroy() duy nhất cuối cùng.
•Một activity thực hiện toàn bộ công việc khởi tạo trạng thái "global" tại onCreate(), và trả lại tất cả các tài nguyên còn giữ tại onDestroy(). 
Visible Lifetime
visible lifetime của một activity kéo dài từ một lời gọi onStart() tới lời gọi tương ứng tới onStop().
  Trong khoảng thời gian này, người dùng có thể nhìn thấy activity đó trên màn hình, tuy nó có thể không nằm tại foreground và tương tác với người dùng.
•Các phương thức onStart() và onStop() có thể được gọi nhiều lần, khi activity chuyển giữa hai trạng thái hiện và bị che đối với người dùng.
•Giữa hai phương thức này, ta có thể giữ các tài nguyên cần thiết cho việc hiển thị activity trên màn hình. 
Foreground Lifetime
foreground lifetime của một activity bắt đầu từ một lời gọi onResume() và kết thúc bởi lời gọi tương ứng tới onPause().
Trong khoảng thời gian này, activity đó đứng trước mọi activity khác trên màn hình và nó tương tác với người dùng.
Một activity có thể thường xuyên chuyển qua lại giữa các trạng thái resumed và paused
Method:  onCreate()
•Được gọi khi activity được tạo.
•Đây là nơi ta nên thực hiện khởi tạo tĩnh thông thường — tạo giao diện người dùng (các view), nối dữ liệu với các danh sách, v.v..
•Tham số được truyền một đối tượng Bundle chứa trạng thái cũ của activity, nếu như trạng thái đã được ghi lại.

•onStart() luôn được gọi sau đó.
Method:  onRestart()
•Được gọi ngay trước khi activity được khởi động lại sau khi đã bị dừng (stopped).
•onStart() luôn được gọi sau đó.
Method:  onStart()
•Được gọi ngay trước khi activity được hiện trên màn hình (visible).

•Tiếp theo là onResume() nếu activity lên foreground, hoặc onStop() nếu nó bị che.
Method:  onResume()
1.Được gọi ngay trước khi activity bắt đầu tương tác với người dùng.
2.Tại thời điểm này, activity nằm trên đỉnh activity stack và nhận input của người dùng.

3.Tiếp theo bao giờ cùng là onPause().
Method:  onPause()
1.Được gọi khi hệ thống chuẩn bị chuyển sang một activity khác.
2.Phương thức này thường dùng để ghi các thay đổi chưa được lưu, dừng hoạt hình và những công việc tốn CPU khác, v.v..
3.Nó nên làm công việc của mình thật nhanh vì activity tiếp theo phải đợi nó kết thúc thì mới resume được.
4.Tiếp theo là onResume() nếu activity quay lại, hoặc onStop() nếu nó không còn được hiển thị đối với người dùng.

5.Activity trong trạng thái này có thể bị hệ thống kill.
Method:  onStop()
1.Được gọi khi activity không còn hiển thị đối với người dùng.
2.Việc này có thể xảy ra khi nó bị hủy (destroyed), hoặc do một activity khác (cũ hoặc mới) đã được resume và che nó.
3.Tiếp theo là onRestart() nếu activity tương tác trở loại với người dùng, hoặc onDestroy() nếu nó không quay lại.

4.Hệ thống có thể kill activity trong trạng thái này.
Method:  onDestroy()
1.Được gọi trước khi activity bị hủy.
2.Đây là lời gọi hàm cuối cùng mà activity nhận được.
3.Nó có thể được gọi vì activity đang kết thúc (hàm finish() của activity được gọi), hoặc vì hệ thống đang tạm thời hủy thực thể hiện tại của activity để tiết kiệm không gian bộ nhớ.
4.Ta có thể phân biệt hai tình huống trên bằng cách dùng phương thức isFinishing().

5.Hệ thống có thể kill activity trong trạng thái này.
Killable States – các trạng thái mà hệ thống kill được
•Activity ở trạng thái killable có thể bị hệ thống kết thúc bất cứ lúc nào sau khi phương thức trả về mà không thực thi thêm một dòng lệnh nào trong mã của activity.
•Ba phương thức onPause(), onStop(), và onDestroy() dẫn đến trạng thái killable.
•onPause() là phương thức duy nhất đảm bảo được gọi trước khi tiến trình bị hủy (killed) — onStop() và onDestroy() có thể không được gọi.

•Do đó, ta nên dùng onPause() để lưu dữ liệu cần giữ lại (chẳng hạn các sửa đổi của người dùng). 
DEMO TỔNG HỢP

  • Ghi log phiên chạy của các method trong một Activity để ta nhìn thấy nó hoạt động onCreate, onStart ...
  • Cách lắng nghe button click hoặc set get textView xem thêm
  • Cách chuyển sang một Activity mới (Chuyển sang màn hình khác) 
  • Cách truyền nhận dữ liệu từ Activity này sang Activity kia (Truyền nhận dữ liệu màn hình a->b hoặc a<b) bằng Inten
  • Cách show dialog bằng Toast
  • Cách tạo class Constant khai báo key word sử dụng nhiều lần (Thủ thuật: Để code luôn đúng không bao giờ lập trình viên nhập sai)
Màn hình 1
activity_main.xml
Java Android 2017

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.lonely.demoapp.MainActivity">

    <TextView
        android:id="@+id/txtHello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:text="Hello World!"
        android:textColor="#ff000d"
        android:textSize="40sp"
        android:textStyle="bold" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerInParent="true"
        android:orientation="horizontal"
        android:weightSum="2">


        <Button
            android:id="@+id/buttonCancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="CANCEL" />

        <Button
            android:id="@+id/buttonScreen"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="SCREEN 2" />
    </LinearLayout>

</RelativeLayout>
MainActivity.java
Java Android 2017
package com.example.lonely.demoapp;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import static com.example.lonely.demoapp.R.id.buttonCancel;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView txtA;
    private static final int REQUEST_CODE = 200;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.v("TAG", "onCreate");

        Button btnCancel = (Button) findViewById(buttonCancel);
        btnCancel.setOnClickListener(this);

        Button btnScreen = (Button) findViewById(R.id.buttonScreen);
        btnScreen.setOnClickListener(this);

        txtA = (TextView) findViewById(R.id.txtHello);
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.v("TAG", "onRestart");

    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.v("TAG", "onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.v("TAG", "onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.v("TAG", "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.v("TAG", "onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.v("TAG", "onDestroy");
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.buttonCancel:
                Toast.makeText(MainActivity.this, "Toat Cancel", Toast.LENGTH_SHORT).show();
                txtA.setText("Click Cancel");
                break;
            case R.id.buttonScreen:
                Toast.makeText(MainActivity.this, "Toat Screen 2", Toast.LENGTH_SHORT).show();
                Intent myIntent=new Intent(MainActivity.this, MainActivity2.class);

                myIntent.putExtra("User", "Antonio");
                myIntent.putExtra("Birth", 1892);

                startActivityForResult(myIntent,REQUEST_CODE); //Chuyen du lieu qua Pags 2, don nhan du lieu tu Page 2 tra ve Page 1 hien thi

//                startActivity(myIntent); //Chi chuyen du lieu qua MainActivity, khong don nhan duoc du lieu tra ve!
                txtA.setText("Click Screen");
                break;
            default:
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE) {
            if (resultCode == Constant.RESULTCODE) {
                String text = data.getStringExtra("PROFILE");
                txtA.setText(text);
            }
        }

    }
}
Màn hình 2
activity_main2.xml
Java Android 2017
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/txtPage2"
        android:text="Profile"
        android:textSize="40dp"
        android:textStyle="bold"
        android:textColor="@color/colorPrimary"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true" />

    <Button
        android:id="@+id/buttonDone"
        android:text="Done"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />
</RelativeLayout>
MainActivity2.java
Java Android 2017
package com.example.lonely.demoapp;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

/**
 * Created by Lonely on 1/6/2017.
 */

public class MainActivity2 extends AppCompatActivity implements View.OnClickListener {

    private Button btDone;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main2);

        Log.v("TAG", "onCreate");

        Intent intent = getIntent();

        String user = intent.getStringExtra("User");
        int birth = intent.getIntExtra("Birth", 0);

        Log.d("TAG", user + " " + birth);

        btDone = (Button) findViewById(R.id.buttonDone);
        btDone.setOnClickListener((View.OnClickListener) this);
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.v("TAG", "onRestart");

    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.v("TAG", "onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.v("TAG", "onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.v("TAG", "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.v("TAG", "onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.v("TAG", "onDestroy");
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.buttonDone:
                onDone();
                break;
            default:
                break;
        }
    }

    private void onDone() {
        Intent intent = new Intent();
        intent.putExtra("PROFILE", "Text From Profile");
        setResult(Constant.RESULTCODE, intent);
        finish();
    }

} 
Constant.java
Java Android 2017
package com.example.lonely.demoapp;

/**
 * Created by Lonely on 1/6/2017.
 */

public class Constant {
    public static String USER = "USER";
    public static  int RESULTCODE = 999;
}
Cấu trúc của project
Run demo
Tìm kiếm key TAG để hiển thị các Log 
Khi chương trình chạy lần đầu tiên sẽ chạy onCreate -> onResume
onCreate chỉ chạy một lần duy nhất
Khi bấm Cancel tôi set textView là Click Cancel và tạo Dialog Toast là Toast Cancel
Ở đây tôi hiển thị dòng Antonio 1892 thông qua Log thay cho set textView
Khi đóng màn hình 2 thứ tự gọi các method sẽ từ onPause -> onDestroy
Khi ẩn ứng dụng onPause->onStop  Hệ thống thường kill nó nếu cần bộ nhớ cho việc khác.

Khi gọi ứng dụng bị ẩn lên trạy nó sẽ bắt đầu từ onRestart-> onResume
Trên đây là toàn bộ demo basic về Activity Stack

 

BACK TO TOP

Xuống cuối trang