Đóng ứng dụng và khởi chạy màn hình chính trên Android


76

Tôi có hai hoạt động khác nhau. Chiếc đầu tiên ra mắt chiếc thứ hai. Trong hoạt động thứ hai, tôi gọi System.exit(0)để buộc đóng ứng dụng, nhưng hoạt động đầu tiên sẽ tự động hiển thị thay vì ứng dụng quay lại màn hình chính. Làm cách nào để tránh điều này và đưa ứng dụng quay lại màn hình chính?


Vì có nhiều hơn một Activity trong Stack, nên System.exit (?) Sẽ khởi động lại nó. (Tôi nghĩ)
Yousha Aleayoub

Câu trả lời:


45

Bạn thực sự nên nghĩ đến việc không thoát ứng dụng. Đây không phải là cách các ứng dụng Android thường hoạt động.


2
Vì không có lối ra trong một ứng dụng Android. Có cách nào tôi có thể xem qua tất cả các hoạt động của một ứng dụng để tôi gọi Kết thúc () trên mỗi ứng dụng, tức là kết thúc tất cả các hoạt động đã được bắt đầu?
Arutha

2
Tại sao bạn cần phải làm điều này? Các hoạt động ở trạng thái không phù hợp có phải do bạn đã đăng xuất hay một số điều kiện khác không? Bạn có thể kiểm tra điều này trong onResumevà sau đó finishlà hoạt động.
James

2
Với tư cách là người dùng và nhà phát triển, vấn đề là tính năng tự động dọn dẹp bộ nhớ trong Android không hoạt động tốt. Có rất nhiều ứng dụng "hoạt động kém" trên điện thoại của tôi bắt đầu cạn kiệt bộ nhớ và khi nó gần hết, giao diện người dùng bắt đầu bị giật. Đây là một thông số kỹ thuật tương đối cao (cho thời điểm này) HTC Desire. Tôi nghĩ đây là lý do tại sao tôi và những người khác đôi khi hỏi câu hỏi này.
Richard Le Mesurier

1
@Richard: Không phải giải pháp tốt hơn là dừng mọi hoạt động khi onPause được gọi trên ứng dụng của bạn sao? Cách duy nhất một ứng dụng có thể gây ra sự chậm lại là nếu bạn vẫn có AsyncTasks, v.v. đang chạy khi bạn bị tạm dừng khi chúng không cần thiết. Ví dụ, các trò chơi sẽ thoát khỏi vòng lặp chính sau khi bật Tạm dừng. (Và một sớm thoát khỏi vòng lặp không được tính.)
idbrii

2
@pydave: Tôi đồng ý với bạn. Nhưng dường như có rất nhiều cuộc tranh luận về loại chủ đề này và tôi đã chia sẻ một số trải nghiệm người dùng & nhà phát triển "thế giới thực". Thực tế của vấn đề là tại thời điểm này điện thoại của tôi chậm đi đáng kể do bộ nhớ khả dụng giảm. Có thể nói, có vẻ như tôi có các ứng dụng "ở chế độ nền" đang sử dụng hết bộ nhớ đó. Nếu tôi giết các ứng dụng đó, tôi có kinh nghiệm rằng thiết bị của mình sẽ tăng tốc. Điều này khiến tôi nghĩ rằng sẽ rất tuyệt nếu 1) nhà phát triển có thể viết mã để giết hoàn toàn một quá trình và giải phóng bộ nhớ của nó, hoặc 2) android GC chạy tốt hơn một chút so với hiện tại. YMMV
Richard Le Mesurier

88

Câu trả lời ngắn gọn: hãy gọi moveTaskToBack(true)cho bạnActivity thay vì System.exit(). Thao tác này sẽ ẩn ứng dụng của bạn cho đến khi người dùng muốn sử dụng lại.

Câu trả lời dài hơn bắt đầu với một câu hỏi khác: tại sao bạn muốn hủy ứng dụng của mình?

Hệ điều hành Android xử lý các quy trình và quản lý bộ nhớ, v.v. vì vậy lời khuyên của tôi là hãy để Android lo việc này cho bạn. Nếu người dùng muốn rời khỏi ứng dụng của bạn, họ có thể nhấn nút Trang chủ và ứng dụng của bạn sẽ biến mất một cách hiệu quả. Nếu sau này điện thoại cần thêm bộ nhớ thì hệ điều hành sẽ chấm dứt ứng dụng của bạn.

Miễn là bạn đang phản hồi các sự kiện vòng đời một cách thích hợp , cả bạn và người dùng đều không cần quan tâm đến việc ứng dụng của bạn có còn đang chạy hay không.

Vì vậy, nếu bạn muốn ẩn cuộc gọi ứng dụng của mình moveTaskToBack()và để Android quyết định khi nào sẽ giết nó.


4
Để biết thêm thông tin về lập luận của Dave, hãy nhìn vào stackoverflow.com/questions/2033914/...
CommonsWare

Có những cách sử dụng hợp pháp để giết ứng dụng - ví dụ: tôi đang thực hiện phiên bản beta kín và cần phải đóng ứng dụng của mình nếu người dùng không có mật khẩu thích hợp.
Matt Lyons

4
@Matt: Tại sao bạn không chỉ dừng người dùng ở màn hình mật khẩu? Nếu họ không thể vượt qua thời điểm đó, thì tại sao bạn cần buộc ứng dụng phải tắt?
idbrii

Một trường hợp đặc biệt sẽ là khi người dùng nhấn nút quay lại để thoát ứng dụng. Trình xử lý onKeyUp () mặc định cho việc này thực hiện kết thúc () trong tình huống này. Nhưng kinh nghiệm của tôi là finish () không phải lúc nào cũng dọn dẹp đầy đủ bộ nhớ, trong khi System.exit (0) thì có. Vì vậy, trong tình huống cụ thể mà người dùng về cơ bản đã nói lời tạm biệt với ứng dụng của bạn và ngầm nói rằng cô ấy không muốn duy trì bất kỳ trạng thái nào, tôi thấy rằng việc gọi System.exit (0) thực hiện công việc dọn dẹp tốt hơn nhiều lên.
Carl

53

Cách dễ nhất để đạt được điều này được đưa ra dưới đây (mà không ảnh hưởng đến việc quản lý bộ nhớ gốc của Android. Không có quá trình giết chết liên quan).

  1. Khởi chạy một hoạt động bằng Intent này:

    Intent intent = new Intent(this, FinActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(intent);
    finish();
    
  2. Trong hoạt động đích FinActivity.class, hãy gọi finish () trong onCreate.

Các bước được giải thích:

  1. Bạn tạo một ý định xóa tất cả các hoạt động khác (FLAG_ACTIVITY_CLEAR_TOP)và xóa hoạt động hiện tại.

  2. Hoạt động phá hủy chính nó. Một cách khác là bạn có thể tạo một màn hình giật gân trong finActivity. Đây là tùy chọn.


3
bạn không muốn startActivity () trước kết thúc ()?
Ai đó ở đâu đó vào

FinActivityphải là RootActivity của bạn phải không? Sử dụng cờ này sẽ khởi động lại của bạn FinActivity.classnhư đã đề cập trong tài liệu developer.android.com/reference/android/content/… Tôi đã cung cấp một ví dụ trong câu trả lời của mình bên dưới để khắc phục điều này.
Darpan

Làm việc như một nét duyên dáng :)
Radhey

Thao tác này sẽ thoát khỏi các hoạt động và dịch vụ, nhưng trình gỡ lỗi vẫn hiển thị các luồng chạy trong nền và nó vẫn hiển thị ứng dụng của tôi đang nhấn nút đa nhiệm.
Stephen M -on đình công-

20

Android có sẵn một cơ chế để đóng ứng dụng một cách an toàn theo tài liệu của nó. Trong Activity cuối cùng được thoát (thường là Activity chính xuất hiện đầu tiên khi ứng dụng khởi động), chỉ cần đặt một vài dòng trong phương thức onDestroy (). Lời gọi đến System.runFinalizersOnExit (true) đảm bảo rằng tất cả các đối tượng sẽ được hoàn thiện và thu gom rác khi ứng dụng thoát. Ví dụ:

public void onDestroy() {
    super.onDestroy();

    /*
     * Notify the system to finalize and collect all objects of the
     * application on exit so that the process running the application can
     * be killed by the system without causing issues. NOTE: If this is set
     * to true then the process will not be killed until all of its threads
     * have closed.
     */
    System.runFinalizersOnExit(true);

    /*
     * Force the system to close the application down completely instead of
     * retaining it in the background. The process that runs the application
     * will be killed. The application will be completely created as a new
     * application in a new process if the user starts the application
     * again.
     */
    System.exit(0);
}

Cuối cùng Android sẽ không thông báo cho một ứng dụng về sự kiện phím HOME , vì vậy bạn không thể đóng ứng dụng khi nhấn phím HOME . Android bảo lưu sự kiện khóa HOME cho chính nó để nhà phát triển không thể ngăn người dùng rời khỏi ứng dụng của họ.


4
Nhìn vào mã nguồn AOSP, phương pháp này hiện không được dùng nữa: @deprecated phương pháp này không an toàn.
Artem Russakovskii

9

Bạn cũng có thể chỉ định noHistory = "true" trong thẻ cho hoạt động đầu tiên hoặc kết thúc hoạt động đầu tiên ngay sau khi bạn bắt đầu hoạt động thứ hai (như David đã nói).

AFAIK, "buộc đóng" sẽ giết quá trình lưu trữ JVM trong đó ứng dụng của bạn chạy và System.exit () chấm dứt JVM đang chạy phiên bản ứng dụng của bạn. Cả hai đều là hình thức chấm dứt đột ngột và không được khuyến khích cho dòng ứng dụng thông thường.

Cũng như việc bắt các ngoại lệ để bao gồm các luồng logic mà một chương trình có thể thực hiện, là không nên.


Không có cách nào để đóng ứng dụng đúng cách và mọi hoạt động vẫn mở?
Arutha

2
Không, không thực sự có khái niệm "ứng dụng" trong Android; ứng dụng của bạn là một tập hợp các Hoạt động. Nếu bạn không muốn quay lại hoạt động đầu tiên sau khi kết thúc hoạt động thứ hai, thì bạn nên sử dụng noHistorythuộc tính như đã đề cập.
Christopher Orr

Thông tin thêm về các hoạt động và Nhiệm vụ ... developer.android.com/guide/topics/fundamentals.html#acttask
Samuh

9

Tôi sử dụng phương pháp này để đóng các Hoạt động!

public static void closeAllBelowActivities(Activity current) {
    boolean flag = true;
    Activity below = current.getParent();
    if (below == null)
        return;
    System.out.println("Below Parent: " + below.getClass());
    while (flag) {
        Activity temp = below;
        try {
            below = temp.getParent();
            temp.finish();
        } catch (Exception e) {
            flag = false;
        }
    }
}

8

Khi bạn khởi chạy hoạt động thứ hai, hoạt động finish()đầu tiên ngay lập tức:

startActivity(new Intent(...));
finish();

1
Tôi không muốn kết thúc hoạt động đầu tiên một cách có hệ thống, chỉ khi tôi gọi System.exit (0). Đó là một tính năng bình thường? Nút buộc đóng trong Trình quản lý ứng dụng hoạt động như thế nào?
Arutha

1
Oh. Tôi đã đọc nhầm câu hỏi của bạn, xin lỗi. đó không phải là giao diện của vòng đời ứng dụng android tiêu chuẩn. nút FC sử dụng một cái gì đó tương tự android.os.Process.killProcess(android.os.Process.myPid());mà không phải là cách bạn thường muốn các ứng dụng của mình thoát. nhưng bạn có thể sử dụng, hoặc bạn có thể xem xét nhìn vào startActivityForResultfinishActivity, và xây dựng một cái gì đó mà hoạt động đầu tiên kết thúc chỉ khi thứ hai kết thúc với một mã phản hồi nhất định.
David Hedlund

6

android.os.Process.killProcess(android.os.Process.myPid()); hoạt động tốt, nhưng bạn nên để nền tảng Android lo lắng về việc quản lý bộ nhớ :-)


4

Bạn không thể thực hiện System.exit (), nó không an toàn.

Bạn có thể làm điều này: Process.killProcess (Process.myPid ());


Bạn cần có quyền chính xác - <use-allow android: name = "android.permission.KILL_BACKGROUND_PROCESSES" />
Kevin Parker

Hoạt động cho ứng dụng của tôi, đang chạy với tư cách là chủ sở hữu thiết bị. Không cần quyền mới. Vẫn còn lại là chế độ xem đa tác vụ.
Stephen M -on đình công-

4

Tôi sử dụng cái này:

1) Hoạt động chính gọi hoạt động phụ với phương thức "startActivityForResult"

2) Trong hoạt động phụ khi kết thúc:

int exitCode = 1; // Select the number you want
setResult(exitCode);
finish();

3) Và trong hoạt động mẹ ghi đè phương thức "onActivityResult":

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    int exitCode = 1;
    if(resultCode == exitCode) {
        super.setResult(exitCode); // use this if you have more than 2 activities
        finish();
    }
}

Cái này làm việc tốt cho tôi.


4

Sử dụng finishphương pháp. Đây là phương pháp đơn giản và dễ dàng hơn.

this.finish();

2

Hãy nhớ rằng khi làm việc với các ứng dụng sử dụng kết nối ổ cắm liên tục, finish()phương pháp này không giải phóng kết nối. Trong những trường hợp bình thường, finish()là lựa chọn tốt nhất, nhưng nếu bạn thực sự cần thoát khỏi một ứng dụng và giải phóng tất cả tài nguyên mà nó đang sử dụng thì hãy sử dụng killProcess. Tôi không gặp vấn đề gì khi sử dụng nó.


2

Bắt đầu hoạt động thứ hai với startActivityForResult và trong hoạt động thứ hai trả về một giá trị, mà một khi trong phương thức onActivityResult của hoạt động đầu tiên sẽ đóng ứng dụng chính. Tôi nghĩ đây là cách chính xác của Android.


2

Bạn sai rồi. Có một cách để hủy một ứng dụng. Trong một lớp có Ứng dụng siêu lớp, chúng ta sử dụng một số trường, chẳng hạn killApp. Khi chúng tôi bắt đầu màn hình giật gân (hoạt động đầu tiên) trong onResume(), chúng tôi đặt một tham số là false cho trường killApp. Trong mọi hoạt động mà chúng ta có khi onResume()cuối cùng được gọi, chúng ta gọi một cái gì đó như thế:

if(AppClass.killApp())
    finish();

Mọi hoạt động được hiển thị trên màn hình đều phải gọi onResume(). Khi nó được gọi, chúng ta phải kiểm tra xem trường của chúng ta killAppcó đúng không. Nếu nó là đúng, các hoạt động hiện tại sẽ gọi finish(). Để gọi toàn bộ hành động, chúng tôi sử dụng cấu trúc tiếp theo. Ví dụ: trong hành động cho một nút:

AppClass.setkillApplication(true);
   finish();
   return;

hệ thống android sẽ không giết hoạt động trên các trạng thái như onStart (), onRestart () và onResume () theo tài liệu. đề nghị của bạn là hoàn toàn sai!
anonim

2

Hãy thử những điều sau đây. Nó làm việc cho tôi.

ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1); 
ComponentName componentInfo = taskInfo.get(0).topActivity;
am.restartPackage(componentInfo.getPackageName());

2

Giả sử bạn có ngăn xếp hoạt động như A> B> C> D> E. Bạn đang ở hoạt động D và bạn muốn đóng ứng dụng của mình. Đây là những gì bạn sẽ làm -

Trong Hoạt động từ nơi bạn muốn đóng (Hoạt động D) -

Intent intent = new Intent(D.this,A.class);
intent.putExtra("exit", "exit");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

Trong RootActivity của bạn (tức là hoạt động cơ sở của bạn, ở đây là Hoạt động A) -

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if (intent.hasExtra("exit")) {
            setIntent(intent);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (getIntent() != null) {
            if (("exit").equalsIgnoreCase(getIntent().getStringExtra(("exit")))) {
                onBackPressed();
            }
        }
    }

onNewIntent được sử dụng vì nếu hoạt động còn tồn tại, nó sẽ nhận được ý định đầu tiên bắt đầu nó. Không phải cái mới. Để biết thêm chi tiết - Tài liệu


1

Nó thực sự yên tĩnh dễ dàng.

Cách tôi làm điều này là lưu một cờ trong một biến tĩnh có sẵn cho tất cả. Sau đó, khi tôi thoát ra, tôi đặt cờ này và mọi hoạt động của tôi sẽ kiểm tra cờ này onResume. Nếu cờ được đặt thì tôi sẽ phát hànhSystem.exit cho hoạt động đó.

Bằng cách đó, tất cả các hoạt động sẽ kiểm tra cờ và sẽ đóng một cách duyên dáng nếu cờ được đặt.


1

Đây là những gì tôi đã làm để đóng ứng dụng: Trong ứng dụng của tôi, tôi có một lớp hoạt động cơ sở, tôi đã thêm một cờ tĩnh có tên "applicationShutDown". Khi tôi cần đóng ứng dụng, tôi đặt nó thành true.

Trong hoạt động cơ sở onCreate và onResume sau khi gọi các lệnh gọi siêu tôi kiểm tra cờ này. Nếu "applicationShutDown" là true, tôi gọi là kết thúc Hoạt động hiện tại.

Điều này đã làm việc cho tôi:

protected void onResume() {
    super.onResume();
    if(BaseActivity.shutDownApp)
    {
        finish();
        return;

    }}

0

Chạy hoạt động thứ hai bằng cách sử dụng hoạt động bắt đầu để có kết quả:

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);

//This line is important
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

startActivityForResult(intent, REQUEST_CODE);

Thêm chức năng này vào Hoạt động đầu tiên:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(rquestCode == REQUEST_CODE)
        if(resultCode == RESULT_CANCELED)
            finish();
}

Và thêm điều này vào Hoạt động thứ hai:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event)  {
    if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {

        Log.i(TAG, "Back key pressed");
        setResult(RESULT_CANCELED);
        finish();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

0

Nó không được khuyến khích, nhưng bạn vẫn có thể sử dụng cái này. Tốt hơn nên sử dụng giải pháp này trong trường hợp bạn cần thoát ứng dụng.

Theo tôi, giải pháp tốt nhất là hoàn thành mọi hoạt động trong ứng dụng của bạn như bên dưới.

Bước 1. Duy trì một biến tĩnh trong mainactivity. Nói,

public static boolean isQuit = false;

Bước 2. Khi nhấp vào sự kiện của một nút, hãy đặt biến này thành true.

mainactivity.isQuit = true;
finish();

Bước 3. Và trong mọi hoạt động của ứng dụng của bạn, có onrestartphương pháp như bên dưới.

@Override
protected void onRestart() {
    // TODO Auto-generated method stub
    super.onRestart();
    if(mainactivity.isQuit)
        finish();
}

0

Tôi đã giải quyết một vấn đề tương tự: MainActivity khởi động BrowserActivity và tôi cần đóng ứng dụng khi người dùng nhấn Quay lại trong BrowserActivity - không quay lại trong MainActivity. Vì vậy, trong MainActivity:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "sm500_Rmt.MainActivity";
    private boolean m_IsBrowserStarted = false;

và sau đó, trong OnResume:

    @Override
protected void onResume() {
    super.onResume();
    if(m_IsBrowserStarted) {
        Log.w(TAG, "onResume, but it's return from browser, just exit!");
        finish();
        return;
    }
    Log.w(TAG, "onResume");

... sau đó tiếp tục OnResume. Và, khi khởi động BrowserActivity:

    Intent intent = new Intent(this, BrowserActivity.class);
    intent.putExtra(getString(R.string.IPAddr), ip);
    startActivity(intent);
    m_IsBrowserStarted = true;

Và có vẻ như nó hoạt động tốt! :-)

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.