Câu hỏi Khởi động lại hoạt động khi xoay vòng Android


Trong ứng dụng Android của tôi, khi tôi xoay thiết bị (trượt bàn phím ra) thì Activity được khởi động lại (onCreate được gọi là). Bây giờ, đây có lẽ là cách nó được cho là, nhưng tôi làm rất nhiều thiết lập ban đầu trong onCreate phương pháp, vì vậy tôi cần:

  1. Đặt tất cả các thiết lập ban đầu trong một chức năng khác vì vậy nó không phải tất cả bị mất trên xoay thiết bị hoặc
  2. Làm như vậy onCreate không được gọi lại và bố cục chỉ điều chỉnh hoặc
  3. Giới hạn ứng dụng chỉ theo chiều dọc để onCreate không được gọi.

1224
2018-01-19 00:28


gốc


Có một lời giải thích khá đầy đủ về cách giữ lại các tác vụ không đồng bộ dài hạn trong các thay đổi cấu hình hoạt động trong bài đăng trên blog này quá! - Adrian Monk
Đây không phải là câu trả lời trực tiếp vì người khác đã trả lời rồi, nhưng tôi mời bạn xem LogLifeCycle để hiểu điều gì xảy ra trong các ứng dụng Android của bạn liên quan đến vòng đời. - Snicolas
Đây là những gì sẽ xảy ra khi màn hình android quay. - Ajit Singh


Các câu trả lời:


Sử dụng lớp ứng dụng

Tùy thuộc vào những gì bạn đang làm trong khởi tạo của bạn, bạn có thể xem xét việc tạo một lớp mới mở rộng Application và di chuyển mã khởi tạo của bạn vào một ghi đè onCreate trong lớp đó.

public class MyApplicationClass extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    // TODO Put your application initialization code here.
  }
}

Các onCreate trong lớp ứng dụng chỉ được gọi khi toàn bộ ứng dụng được tạo, do đó Hoạt động khởi động lại trên các thay đổi mức độ hiển thị hoặc định hướng bàn phím sẽ không kích hoạt nó.

Đó là thực hành tốt để trưng bày thể hiện của lớp này như là một singleton và phơi bày các biến ứng dụng mà bạn đang khởi tạo bằng cách sử dụng getters và setters.

LƯU Ý: Bạn sẽ cần chỉ định tên của lớp Ứng dụng mới trong tệp kê khai để nó được đăng ký và sử dụng:

<application
    android:name="com.you.yourapp.MyApplicationClass"

Phản ứng với thay đổi cấu hình  [CẬP NHẬT: điều này không còn được dùng nữa kể từ API 13; xem giải pháp thay thế được đề xuất]

Để thay thế thêm, bạn có thể yêu cầu ứng dụng của mình lắng nghe các sự kiện có thể gây ra các thay đổi về khả năng hiển thị và bàn phím khởi động lại - và xử lý chúng trong Hoạt động của bạn.

Bắt đầu bằng cách thêm android:configChanges nút đến nút tệp kê khai của Hoạt động

android:configChanges="keyboardHidden|orientation"

hoặc là Android 3.2 (API cấp 13) và mới hơn:

android:configChanges="keyboardHidden|orientation|screenSize"

Sau đó, trong Hoạt động, hãy ghi đè lên onConfigurationChanged phương pháp và cuộc gọi setContentView để buộc bố cục GUI được thực hiện lại theo hướng mới.

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  setContentView(R.layout.myLayout);
}

897
2018-01-19 08:47



Tôi không nghĩ rằng cách tiếp cận thứ hai hoạt động. Tôi đã thử nó; một Hoạt động với EditText. Tôi đã viết một số văn bản ở đó, thay đổi định hướng và văn bản đã biến mất / đặt lại. - Ted
Đây là hy vọng chúng ta thấy một phương thức onRotate () trong tương lai. Thậm chí phải lo lắng về những thứ như thế này - thật lòng - bực bội. - Kelly Sutton
Lưu ý rằng Hướng dẫn cho Android Dev cảnh báo chống lại bằng cách sử dụng này: Lưu ý: Sử dụng (android:configChanges) nên tránh và chỉ được sử dụng như một phương sách cuối cùng. Vui lòng đọc Xử lý các thay đổi thời gian chạy để biết thêm thông tin về cách xử lý đúng cách khởi động lại do thay đổi cấu hình.  Thay vào đó, để duy trì dữ liệu trên các sự kiện xoay vòng, chúng dường như thích sử dụng onSaveInstanceState Bundle; hoặc như @ Jon-O đề cập, onRetainNonConfigurationInstance. - Jeffro
Đó là một giải pháp tồi, bởi vì nó chỉ phản ứng với hiện đang được biết đến thay đổi cấu hình. Với các phiên bản Android mới hơn, các thay đổi cấu hình khác có thể xảy ra mà mã này sẽ không bắt (vì nó phải liệt kê tất cả các thay đổi cấu hình trong tệp kê khai). Giải pháp tiết kiệm nhà nước với onRetainNonConfigurationChanges là lỗi hơn và thẳng về phía trước. - Bananeweizen
Tôi nghĩ bạn nên thêm cập nhật này trên 3.2 câu trả lời của bạn, nó khá quan trọng (chỉ cần đối mặt với vấn đề đó) và nó có thể bị bỏ qua. - bigstones


Cập nhật cho Android 3.2 trở lên:

Thận trọng: Bắt đầu với Android 3.2 (API cấp 13), "kích thước màn hình" cũng thay đổi khi thiết bị chuyển giữa hướng dọc và ngang. Do đó, nếu bạn muốn ngăn khởi động lại thời gian chạy do thay đổi định hướng khi phát triển cho API cấp 13 trở lên (như được khai báo bởi thuộc tính minSdkVersion và targetSdkVersion), bạn phải bao gồm "screenSize" giá trị ngoài "orientation" giá trị. Nghĩa là, bạn phải khai báo android:configChanges="orientation|screenSize". Tuy nhiên, nếu ứng dụng của bạn nhắm mục tiêu cấp API 12 trở xuống thì hoạt động của bạn luôn xử lý thay đổi cấu hình này (thay đổi cấu hình này không khởi động lại hoạt động của bạn, ngay cả khi chạy trên thiết bị Android 3.2 trở lên).


175
2018-03-03 21:56



Cảm ơn bạn đã làm rõ, kể từ khi một bình luận ở trên này gần như đã gửi cho tôi đi để nhìn vào nó. Tôi hiện đang nhắm mục tiêu API 8 và mã của tôi không có screenSize trên configChanges và có thể xác nhận rằng nó hoạt động tốt (không định hướng lại) trên thiết bị mà tôi có đang chạy ICS. - Carl
Cảm ơn bạn đã chỉ ra điều này, tôi chỉ có android: configChanges = "orientation | screenSize", và việc chuyển hướng là tái tạo Activity của tôi, và trong cuộc đời tôi, tôi không thể hiểu tại sao! - Christopher Perry
Cảm ơn Grom. bạn đã cứu ngày của tôi. Tôi đang làm việc trên ICS và sử dụng android: configChanges = "orientation | keyboardHidden", đã tái tạo hoạt động của tôi, nhưng đề xuất của bạn hoạt động như ma thuật !! - AndroidGuy
Thêm android: configChanges chỉ nên được sử dụng như một phương sách cuối cùng. Cân nhắc sử dụng Fragments và setRetainInstance thay thế. - Simon Forsberg
Điểm mấu chốt là screenSize cho Android 3.2 trở lên, giải quyết được vấn đề của tôi, Cảm ơn bạn! - fantouch


Thay vì cố gắng dừng onCreate() bị sa thải hoàn toàn, có thể thử kiểm tra Bundle  savedInstanceState được thông qua vào sự kiện để xem liệu nó có bị vô hiệu hay không.

Ví dụ, nếu tôi có một số logic nên được chạy khi Activity thực sự được tạo ra, không phải trên mọi thay đổi định hướng, tôi chỉ chạy logic đó trong onCreate()chỉ khi savedInstanceState là null.

Nếu không, tôi vẫn muốn bố cục vẽ lại đúng cách cho hướng.

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

không chắc chắn nếu đây là câu trả lời cuối cùng, nhưng nó làm việc cho tôi.


110
2017-08-04 21:04



và bạn đang thực sự tiết kiệm nhà nước ở đâu? - Ewoks
điều này dường như làm việc cho tôi và nó có vẻ là phương pháp đơn giản nhất. Tôi nhận thấy bạn chỉ có 4 up cho điều này (5 bao gồm cả tôi) so với 373 cho ý tưởng về ứng dụng phân lớp, mà với tôi có vẻ phức tạp hơn nhiều. là có bất kỳ nhược điểm này phương pháp này? - steveh
Giải pháp này làm việc tuyệt vời cho tôi. Tôi đã có thể Intent serverintent = new Intent(MainActivity.this, MessageListener.class); và startService(serverintent); để tạo ra một serverSocket = new ServerSocket(0xcff2); và Socket client = serverSocket.accept(); với một BufferedReader(new InputStreamReader(client.getInputStream())); và có thể xoay android của tôi và giữ cho kết nối máy khách / máy chủ hoạt động, nhưng vẫn có GUI xoay. Theo hướng dẫn, saveInstanceState được khởi tạo khi hoạt động cuối cùng bị tắt. - Fred F
Tôi không hiểu, bắt là gì? Điều này làm việc tuyệt vời và ít phức tạp hơn bất kỳ giải pháp nào khác. - RTF
Đây là cách chính xác để làm điều đó trong Android. Những cách khác về cơ bản bắt một xoay với configChanges và tất cả những cồng kềnh, phức tạp, và không cần thiết. - LukeWaggoner


tôi đã làm gì...

trong tệp kê khai, đến phần hoạt động, đã thêm:

android:configChanges="keyboardHidden|orientation"

trong mã cho hoạt động, được triển khai:

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}

93
2018-01-04 01:26



để làm rõ: với việc thực hiện của tôi bây giờ bạn có thể khởi tạo biến trong onCreate () và onConfigurationChanged () đơn giản sẽ được gọi cho xoay màn hình. Các biến của bạn hiện được cách ly từ xoay màn hình ;-) đẹp và ez - Someone Somewhere
Tôi đã làm tất cả mọi thứ chỉ như mô tả ở đây, nhưng tôi nhận được NullPointerException khi tôi cố gắng nhấn một nút sau khi thay đổi định hướng. Điều gì có thể sai? - Finnboy11
Thêm android: configChanges chỉ nên được sử dụng như một phương sách cuối cùng. Cân nhắc sử dụng Fragments và setRetainInstance thay thế. - Simon Forsberg
hãy ghi nhớ câu trả lời của tôi giống như 3 tuổi và Android tiếp tục phát triển ... Simon - bạn có liên kết đến mã mẫu không? Đó là những gì mọi người cần. - Someone Somewhere
Khi cảnh báo chống lại android: configChanges, @ SimonAndréForsberg thực sự chỉ là diễn giải Tài liệu Android. Xử lý các thay đổi thời gian chạy có thông tin chi tiết hơn về các lựa chọn thay thế (bao gồm cả mã mẫu). - Leif Arne Storset


Những gì bạn mô tả là hành vi mặc định. Bạn phải tự mình phát hiện và xử lý các sự kiện này bằng cách thêm:

android:configChanges

vào tệp kê khai của bạn và sau đó thay đổi mà bạn muốn xử lý. Vì vậy, để định hướng, bạn sẽ sử dụng:

android:configChanges="orientation"

và để bàn phím được mở hoặc đóng, bạn sẽ sử dụng:

android:configChanges="keyboardHidden"

Nếu bạn muốn xử lý cả hai bạn chỉ có thể tách chúng bằng lệnh đường ống như:

android:configChanges="keyboardHidden|orientation"

Điều này sẽ kích hoạt phương thức onConfigurationChanged trong bất cứ Activity nào bạn gọi. Nếu bạn ghi đè phương thức, bạn có thể chuyển các giá trị mới.

Hi vọng điêu nay co ich.


57
2018-01-19 02:28



Xem câu trả lời của tôi dưới đây để ý rằng android:configChanges="orientation" chỉ dường như kích hoạt các lỗi trong trình mô phỏng, ít nhất là cho Android 2.1. - Liudvikas Bukys
Thêm android: configChanges chỉ nên được sử dụng như một phương sách cuối cùng. Cân nhắc sử dụng Fragments và setRetainInstance thay thế. - Simon Forsberg
@ GregD Tôi biết, đó là lý do tại sao bây giờ là thời điểm tốt để cập nhật nó để phản ánh tình hình của ngày hôm nay. Với số lượng upvotes câu hỏi này có, nó vẫn đang được nhắc đến từ các câu hỏi khác trên SO. - Simon Forsberg


Tôi vừa phát hiện ra truyền thuyết này:

Để giữ cho Activity hoạt động thông qua một sự thay đổi định hướng, và xử lý nó thông qua onConfigurationChanged, tài liệu và mẫu mã ở trên đề xuất điều này trong tệp kê khai:

android:configChanges="keyboardHidden|orientation"

có lợi ích bổ sung mà nó luôn hoạt động.

Số tiền thưởng là bỏ qua keyboardHidden có vẻ hợp lý, nhưng nó gây ra lỗi trong trình giả lập (cho Android 2.1 ít nhất): chỉ xác định orientation sẽ làm cho trình giả lập gọi cả hai OnCreate và onConfigurationChanged đôi khi, và chỉ OnCreate lần khác.

Tôi đã không nhìn thấy sự thất bại trên một thiết bị, nhưng tôi đã nghe nói về giả lập không cho người khác. Vì vậy, nó có giá trị tài liệu.


39
2017-12-22 21:50



Tôi có thể xác nhận rằng trình giả lập hoàn toàn bị lỗi chỉ với "định hướng". Tôi đã trải qua đêm xé tóc của tôi ra khỏi này và chỉ cần đi qua sửa chữa của bạn mà hoạt động. - locka
Thận trọng: Bắt đầu với Android 3.2 (API cấp 13), "kích thước màn hình" cũng thay đổi khi thiết bị chuyển đổi giữa hướng dọc và ngang. Do đó, nếu bạn muốn ngăn thời gian khởi động lại do thay đổi định hướng khi phát triển cho API cấp 13 trở lên: android: configChanges = "orientation | keyboardHidden | screenSize" - Geltrude
Vâng, bộ mô phỏng sẽ mất nhiều thời gian. Bạn không thể dựa vào nó để báo cáo chính xác thay đổi cấu hình. - Igor Ganapolsky
Thêm android: configChanges chỉ nên được sử dụng như một phương sách cuối cùng. Cân nhắc sử dụng Fragments và setRetainInstance thay thế. - Simon Forsberg


Bạn cũng có thể xem xét sử dụng cách lưu trữ dữ liệu của nền tảng Android trong các thay đổi định hướng: onRetainNonConfigurationInstance() và getLastNonConfigurationInstance().

Điều này cho phép bạn duy trì dữ liệu qua các thay đổi cấu hình, chẳng hạn như thông tin bạn có thể nhận được từ việc tìm nạp máy chủ hoặc một thứ khác được tính toán onCreate hoặc từ đó, đồng thời cho phép Android sắp xếp lại Activity sử dụng tệp xml để định hướng hiện đang được sử dụng.

Xem đây hoặc là đây.

Cần lưu ý rằng các phương pháp này hiện không được chấp nhận (mặc dù vẫn linh hoạt hơn việc tự thay đổi định hướng khi hầu hết các giải pháp trên đề xuất) với đề xuất mà mọi người chuyển sang Fragments và thay vào đó sử dụng setRetainInstance(true) trên mỗi Fragment bạn muốn giữ lại.


33
2017-09-22 03:03



Tôi thực sự nghĩ rằng Fragments và setRetainInstance là cách tốt nhất (và được Google khuyên dùng) để làm điều này, +1 cho bạn và -1 cho tất cả những người khác. Thêm android: configChanges chỉ nên được sử dụng như một phương sách cuối cùng - Simon Forsberg


Cách tiếp cận này hữu ích nhưng không đầy đủ khi sử dụng Phân đoạn.

Các mảnh vỡ thường được tạo lại khi thay đổi cấu hình. Nếu bạn không muốn điều này xảy ra, hãy sử dụng

setRetainInstance(true); trong (các) hàm tạo của Fragment

Điều này sẽ khiến cho các mảnh được giữ lại trong quá trình thay đổi cấu hình.

http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance (boolean)


28
2017-09-21 09:09



Đã đồng ý. Với API Android mới nhất, có vẻ như Phân đoạn là cách chính xác để xử lý việc này. Tôi chưa thử nó, nhưng từ những gì tôi đã thu thập được trang này, về cơ bản, bạn di chuyển 99% những gì bạn đã sử dụng để triển khai trong một Hoạt động vào một phân lớp của Phân đoạn, sau đó thêm Phân đoạn đó vào Hoạt động. Hoạt động này sẽ vẫn bị hủy và tái tạo trên xoay màn hình, nhưng bạn có thể nói cụ thể cho android không phải phá hủy Fragment bằng cách sử dụng setRetainInstance() phương thức @Abdo được đề cập. - brianmearns


Tôi chỉ cần thêm vào

     android:configChanges="keyboard|keyboardHidden|orientation"

trong tệp kê khai và không thêm bất kì onConfigurationChanged phương pháp trong hoạt động của tôi.

Vì vậy, mỗi khi bàn phím trượt ra hoặc không có gì xảy ra.


21
2017-08-09 09:58



thêm vào <application ...android:configChanges="keyboard|keyboardHidden|orientation"> và nó đang hoạt động. Cài đặt của tôi trong build.gradle: minSdkVersion 15, compileSdkVersion 23, buildToolsVersion "23.0.2" - Junior M


 onConfigurationChanged is called when the screen rotates. 
 (onCreate is no longer called when screen rotates due to manifest, see:  
 android:configChanges)

Phần nào của tệp kê khai cho biết "không gọi onCreate()"?

Cũng thế, Tài liệu của Google nói để tránh sử dụng android:configChanges(ngoại trừ như một phương sách cuối cùng) .... Nhưng sau đó các phương pháp thay thế họ đề nghị tất cả LÀM sử dụng android:configChanges.

Đó là kinh nghiệm của tôi mà giả lập LUÔN gọi onCreate() khi xoay vòng.
Nhưng các thiết bị 1-2 mà tôi chạy cùng một mã trên ... thì không. (Không chắc tại sao sẽ có bất kỳ sự khác biệt nào.)


13
2018-02-01 15:55



Bộ giả lập quá chậm chạp và thiếu tính thực tế, tôi đã nhanh chóng quyết định mua một số thiết bị (cho đến nay ba điện thoại và hai máy tính bảng - rất rẻ được sử dụng trên một trang web như swappa hoặc ebay) với kích thước màn hình khác nhau, với bàn phím và không có, chạy các phiên bản hệ điều hành khác nhau (chủ yếu là bắt nguồn), v.v.). Điều này hoạt động thực sự tốt và cũng đáng để đầu tư. - Carl


Thêm dòng này vào tệp kê khai của bạn: -

android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

và đoạn trích này cho hoạt động: -

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

13
2017-07-23 10:00



Việc thêm đoạn mã đầu tiên là đủ để giải quyết vấn đề. +1 - 030
Lưu ý rằng đoạn đầu tiên cần được thêm vào application đoạn trích của AndroidManifest.xml - 030