Làm cách nào để kiểm tra xem một hoạt động có phải là hoạt động cuối cùng trong ngăn xếp hoạt động cho một ứng dụng hay không?


122

Tôi muốn biết liệu người dùng có quay lại màn hình chính nếu anh ta thoát khỏi hoạt động hiện tại.



43
Chỉ cần phát hiện ra có một chức năng trong Activity được gọi là isTaskRoot mà tôi đoán có thể giúp bạn.
H9kDroid

Câu trả lời:


116

CẬP NHẬT (tháng 7 năm 2015):

Kể từ getRunningTasks () được phản đối, từ API 21 nó tốt hơn để làm theo raukodraug câu trả lời hay Ed Burnette một (Tôi muốn một giây).


Có khả năng kiểm tra các tác vụ hiện tại và ngăn xếp của chúng bằng ActivityManager .

Vì vậy, để xác định xem một hoạt động có phải là hoạt động cuối cùng hay không:

  • yêu cầu quyền android.permission.GET_TASKS trong tệp kê khai.
  • Sử dụng mã sau:

    ActivityManager mngr = (ActivityManager) getSystemService( ACTIVITY_SERVICE );
    
    List<ActivityManager.RunningTaskInfo> taskList = mngr.getRunningTasks(10);
    
    if(taskList.get(0).numActivities == 1 &&
       taskList.get(0).topActivity.getClassName().equals(this.getClass().getName())) {
        Log.i(TAG, "This is last activity in the stack");
    }
    

Xin lưu ý rằng mã trên sẽ chỉ có hiệu lực nếu Bạn có một nhiệm vụ. Nếu có khả năng số lượng tác vụ sẽ tồn tại cho ứng dụng của Bạn - Bạn sẽ cần kiểm tra các phần tử taskList khác. Đọc thêm về nhiệm vụ Nhiệm vụ và Ngăn xếp lùi



25
H9kDroid đã đưa ra một đề xuất chính xác. Câu trả lời được chọn là hack. Người ta nên làm điều đó một cách đúng đắn bằng cách sử dụng isTaskRoot()phương pháp.
Sufian

@Sufian nó bị hack đặc biệt ở đâu? Mã logic và sử dụng các API android mở theo cách mà chúng dự định được sử dụng (ví dụ: getRunningTasks nên được sử dụng để chạy các tác vụ và người ta có thể muốn gọi nó chỉ với mục đích phân tích các tác vụ này). Cách sử dụng get (0) được ghi chép đầy đủ và hợp lý 'Trả lại danh sách các tác vụ hiện đang chạy, với tác vụ gần đây nhất là tác vụ đầu tiên và các tác vụ cũ hơn theo thứ tự'.
sandrstar

2
getRunningTasks () bị phản đối ở mức API 21.
gilchris

Tôi có thể làm điều tương tự cho các mảnh vỡ. Nếu có thì làm thế nào? Vui lòng giúp đỡ
Sagar Devanga

1
@ Mr.Drew xem câu trả lời bình chọn cao nhất từ @ raukodraug
David Wasser

167

Tôi sẽ đăng nhận xét của @ H9kDroid như là câu trả lời tốt nhất ở đây cho những người có câu hỏi tương tự.

Bạn có thể sử dụng isTaskRoot () để biết hoạt động có phải là gốc của một tác vụ hay không.

Tôi hi vọng cái này giúp được


1
bạn có thể vui lòng cung cấp một dòng mã để rõ ràng về cách sử dụng isTaskRoot. Cảm ơn.
Kaveesh Kanwal

18
@TheHunterif (isTaskRoot()) { // do something }
howettl

3
Vấn đề duy nhất là trên <= 4.4, tôi thấy nó thực hiện hành vi khác với trong> = 5.x. Nó dường như luôn trả về false.
chubbsondubs

Tôi nghĩ bạn nên cân nhắc kết hợp mã mẫu được cung cấp trong phần nhận xét vào câu trả lời, để giúp người đọc trong tương lai dễ dàng hơn.
Isac

câu trả lời xuất sắc. trong trường hợp của tôi sau khi người dùng nhấp vào một thông báo, hoạt động có thể là gốc nếu họ đóng ứng dụng trước đó
dave o grady

19

Hy vọng điều này sẽ giúp ích cho người mới bắt đầu, Dựa trên các câu trả lời ở trên phù hợp với tôi, tôi cũng đang chia sẻ đoạn mã nên nó sẽ dễ dàng thực hiện.

giải pháp: tôi đã sử dụng câu isTaskRoot()trả về true nếu hoạt động hiện tại chỉ là hoạt động trong ngăn xếp của bạn và khác với tôi cũng xử lý trường hợp nếu tôi có một số hoạt động trong ngăn xếp, hãy chuyển đến hoạt động cuối cùng trong ngăn xếp thay vì mở hoạt động tùy chỉnh mới .

Trong hoạt động của bạn

   @Override
    public void onBackPressed() {

        if(isTaskRoot()){
            startActivity(new Intent(currentActivityName.this,ActivityNameYouWantToOpen.class));
            // using finish() is optional, use it if you do not want to keep currentActivity in stack
            finish();
        }else{
            super.onBackPressed();
        }

    }


5

Mặc dù có thể có một cách để đạt được điều này (xem các câu trả lời khác), tôi khuyên bạn không nên làm điều đó. Các ứng dụng Android thông thường không cần biết Màn hình chính có hiển thị hay không.

Nếu bạn đang cố gắng lưu dữ liệu, hãy đặt mã lưu dữ liệu vào phương thức onPause () của bạn. Nếu bạn đang cố gắng cung cấp cho người dùng cách thay đổi ý định của họ về ứng dụng hiện có, bạn có thể chặn phím lên / xuống cho phím Quay lại và phương thức onBackPressed () và trình bày cho họ câu "Bạn có chắc không?" lời nhắc.


1
Còn nếu tôi cần một dịch vụ đang chạy miễn là người dùng chưa rời khỏi hoạt động? Tôi không thể bẫy bất kỳ chức năng nào như onStop vì chúng có thể được gọi sau khi màn hình tắt.
Michael

2
Nếu một dịch vụ nền khởi chạy Hoạt động, có lẽ bạn muốn biết liệu đó có phải là Hoạt động duy nhất trên ngăn xếp hay không.
Matt W

4

Một cách để theo dõi điều này là bao gồm một điểm đánh dấu khi bạn bắt đầu một hoạt động mới và kiểm tra xem điểm đánh dấu có tồn tại hay không.

Bất cứ khi nào bạn bắt đầu một hoạt động mới, hãy chèn điểm đánh dấu:

newIntent=new Intent(this, NextOne.class);
newIntent.putExtra(this.getPackageName()+"myself", 0);
startActivity(newIntent);

Và sau đó bạn có thể kiểm tra nó như sau:

boolean islast=!getIntent().hasExtra(this.getPackageName()+"myself")

1
Không hoạt động nếu hoạt động bị hủy và ngăn xếp hoạt động được tạo lại - mỗi hoạt động theo yêu cầu.
AlikElzin-kilaka

3

Vấn đề với giải pháp của sandrstar khi sử dụng ActivityManagerlà: bạn cần có quyền để thực hiện các nhiệm vụ theo cách này. Tôi đã tìm thấy một cách tốt hơn:

getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)

Activityphía dưới cùng của Ngăn xếp sẽ luôn nhận được danh mục này theo mặc định trong khi các Hoạt động khác sẽ không nhận được danh mục này.
Nhưng ngay cả khi điều này không thành công trên một số thiết bị, bạn có thể đặt nó trong khi khởi động Activity:

Intent intent = new Intent(startingActivity, SomeActivityClass.class);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
activity.startActivity(intent);

Điều gì sẽ xảy ra nếu hoạt động được mở từ thông báo đẩy? Họ không có
MÁY KHỞI ĐỘNG DANH

Tôi khá chắc chắn rằng phần thứ hai của câu trả lời của tôi vẫn được áp dụng. Bạn có thể đặt danh mục như một gợi ý trong ý định. Trong trường hợp này, có thể trong ngữ cảnh thông báo của bạn. Ngoài ra, bạn cũng có thể sử dụng cờ cho việc này. nhìn thấy liên kết này cho một sáng tạo thông báo với mục đích: stackoverflow.com/questions/13716723/...
A. Binzxxxxxx

Tuy nhiên, nếu hoạt động cũ nhất của bạn là MainActivity và bây giờ nó được tiếp tục, sau đó bạn nhận được thông báo đẩy và bạn đặt PendingIntent để mở với CATEGORY_LAUNCHER, thì bạn sẽ có 2 hoạt động với danh mục này. Có thể là các nhiệm vụ khác nhau
nbtk

Tôi không chắc chính xác nó hoạt động như thế nào với các thông báo. Tôi chưa bao giờ sử dụng chúng như bạn làm ở đây. Tôi khá chắc chắn có một cách dễ dàng để thực hiện với cách tiếp cận này nhưng tôi đã không chạm vào mã android kể từ quý 1 năm 2014. Có lẽ bạn muốn sử dụng danh mục thứ hai cho trường hợp này? Hay một số lá cờ? Nhưng tôi đoán tâm lý của nó hoạt động như thế này. Làm thế nào về việc bắt đầu hoạt động chính và thêm một số loại thông tin meta để mở hoạt động chính xác sau đó?
A. Binzxxxxxx

2

Tôi đã tạo một lớp cơ sở cho tất cả các hoạt động của mình, mở rộng AppCompatActivity và có một bộ đếm tĩnh:

public abstract class BasicActivity extends AppCompatActivity {
    private static int activityCounter = 0;

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        --activityCounter;
        if(activityCounter==0) {
            // Last instance code...
        }
    }

    public boolean isLastInstance() { return (activityCounter==1); }
}

Điều này đã hoạt động đủ tốt, cho đến nay; và bất kể phiên bản API nào. Tất nhiên, nó yêu cầu tất cả các hoạt động mở rộng lớp cơ sở này - điều mà chúng làm, trong trường hợp của tôi.

Chỉnh sửa: Tôi đã nhận thấy một trường hợp khi bộ đếm giảm xuống 0 trước khi ứng dụng hoàn toàn thoát, đó là khi hướng được thay đổi và chỉ một hoạt động được mở. Khi hướng thay đổi, hoạt động được đóng lại và một hoạt động khác được tạo ra, như vậy onDestroyedđược gọi cho hoạt động cuối cùng và sau đó onCreateđược gọi khi hoạt động tương tự được tạo với hướng đã thay đổi. Hành vi này phải được tính đến; Có thể sử dụng OrientationEventListener .


0

Android triển khai ngăn xếp Hoạt động, tôi khuyên bạn nên đọc về nó ở đây . Dường như tất cả các bạn muốn làm dù là lấy hoạt động gọi điện thoại: getCallingActivity(). Nếu hoạt động hiện tại là hoạt động đầu tiên trong ứng dụng của bạn và ứng dụng được khởi chạy từ màn hình chính thì (tôi cho là) ​​sẽ quay trở lại null.


9
Điều đó sẽ không hoạt động vì getCallingActivity () sẽ trả về null nếu hoạt động không được bắt đầu thông qua startActivityForResult ().
H9kDroid

0

Một điều bị bỏ lỡ ở đây, đó là lần nhấp "Phím Trang chủ", khi được kích hoạt, bạn không thể phát hiện điều này từ hoạt động của mình, vì vậy tốt hơn nên kiểm soát ngăn xếp hoạt động theo chương trình bằng cách xử lý nhấn "Phím Quay lại" và di chuyển đến hoạt động cần thiết hoặc chỉ làm các bước cần thiết.

Ngoài ra, bạn không thể chắc chắn rằng việc bắt đầu hoạt động của bạn từ danh sách "Hoạt động gần đây" có thể được phát hiện bằng cách đặt trước một số dữ liệu bổ sung cho mục đích mở hoạt động, vì nó được sử dụng lại trong trường hợp đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.