Hoạt động khởi động lại trên Android xoay


1380

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

  1. Đặt tất cả các thiết lập ban đầu vào một chức năng khác để nó không bị mất khi xoay thiết bị hoặc
  2. Làm cho nó onCreatekhô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ỉ là chân dung để onCreatekhông được gọi.

4
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ộ chạy dài trong quá trình thay đổi cấu hình hoạt động trong bài đăng blog này !
sư Adrian

3
Đây không phải là câu trả lời trực tiếp như những người khác đã trả lời, nhưng tôi mời bạn hãy xem LogLifeCycle để hiểu những gì xảy ra trong ứng dụng Android của bạn liên quan đến vòng đời.
Snicolas

Câu trả lời:


965

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

Tùy thuộc vào những gì bạn đang làm trong quá trình khởi tạo của mình, bạn có thể xem xét việc tạo một lớp mới mở rộng Applicationvà chuyển mã khởi tạo của bạn thành một ghi đèonCreate phương thức được 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 ứng dụng chỉ được gọi khi toàn bộ ứng dụng được tạo, do đó Activity khởi động lại theo hướng hoặc thay đổi mức độ hiển thị của bàn phím sẽ không kích hoạt nó.

Đó là một cách thực hành tốt để hiển thị thể hiện của lớp này dưới dạng một singleton và hiển thị 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 của mình trong bảng kê khai để đăng ký và sử dụng:

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

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

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

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

 <activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

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

<activity android:name=".MyActivity"
      android:configChanges="keyboardHidden|orientation|screenSize"
      android:label="@string/app_name">

Sau đó, trong Hoạt động ghi đè onConfigurationChangedphương thức và 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);
}

17
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 hướng và văn bản đã biến mất / thiết lập lại.
Ted

231
Ở đây hy vọng chúng ta sẽ thấy một phương thức onRotate () trong tương lai. Thậm chí phải lo lắng về những điều như thế này là một cách thẳng thắn.
Kelly Sutton

84
Lưu ý rằng Hướng dẫn dành cho Android Dev cảnh báo không sử dụng điều này: Lưu ý: android:configChangesNên tránh sử dụng ( ) như là phương sách cuối cùng. Vui lòng đọc Xử lý thay đổi thời gian chạy để biết thêm thông tin về cách xử lý khởi động lại đúng cách do thay đổi cấu hình. Thay vào đó, để duy trì dữ liệu qua các sự kiện xoay vòng, họ dường như thích sử dụng onSaveInstanceState Bundle; hoặc như @ Jon-O đề cập , onRetainNonConfigurationInstance.
Jeffro

19
Đó là một giải pháp tồi, bởi vì nó chỉ phản ứng với những thay đổi cấu hình hiện được biết đến . 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 được (vì 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 cứu nhà nước với onRetainNonConfigurationChangeskhả năng chịu lỗi cao hơn và thẳng tiến.
Tuneweizen

16
Tôi nghĩ bạn nên thêm bản cập nhật này vào ngày 3.2 cho câu trả lời của mình, nó khá quan trọng (chỉ gặp phải vấn đề đó) và nó có thể bị bỏ qua.
bigstones

185

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à hướng ngang. Do đó, nếu bạn muốn ngăn khởi động lại thời gian chạy do thay đổi hướng khi phát triển cho cấp API 13 trở lên (như được khai báo bởi các thuộc tính minSdkVersion và targetSdkVersion), bạn phải bao gồm "screenSize"giá trị bên cạnh "orientation"giá trị. Đó 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 API cấp 12 trở xuống, thì hoạt động của bạn luôn tự 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).


1
Cảm ơn đã làm rõ, vì một nhận xét ở trên về điều này gần như đã gửi cho tôi để xem xét 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 cần định hướng lại) trên thiết bị tôi đang chạy ICS.
Carl

Cảm ơn bạn đã chỉ ra điều này, tôi chỉ có bộ android: configChanges = "direction | screenSize" và chuyển đổi định hướng đang tạo lại Hoạt động của tôi và đối với cuộc sống của tôi, tôi không thể hiểu tại sao!
Christopher Perry

5
Thêm android: configChanges chỉ nên được sử dụng như là phương sách cuối cùng . Cân nhắc sử dụng FragmentssetRetainInstancethay vào đó.
Simon Forsberg

Điểm mấu chốt là screenSizedành cho Android 3.2 trở lên, đã giải quyết được vấn đề của tôi, Cảm ơn bạn!
fantouch

127

Thay vì cố gắng ngăn chặn việc onCreate()bị sa thải hoàn toàn, có thể thử kiểm traBundle savedInstanceState được truyền vào sự kiện để xem nó có rỗng hay không.

Chẳng hạn, nếu tôi có một số logic nên được chạy khi Activitythực sự được tạo, không phải trên mỗi thay đổi định hướng, tôi chỉ chạy logic đó onCreate()nếu chỉsavedInstanceState là null.

Nếu không, tôi vẫn muốn bố trí vẽ lại đúng cho định hướng.

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

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

không chắc đây có phải là câu trả lời cuối cùng không, nhưng nó hiệu quả với tôi.


6
và bạn đang thực sự tiết kiệm nhà nước ở đâu?
Ewoks

5
điều này dường như làm việc cho tôi và nó dường như là phương pháp đơn giản nhất. Tôi nhận thấy bạn chỉ có 4 lần cho việc này (5 bao gồm cả của tôi) so với 373 cho ý tưởng về Ứng dụng phân lớp, với tôi có vẻ phức tạp hơn nhiều. Có bất kỳ nhược điểm của phương pháp này?
steveh

4
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);startService(serverintent);tạo một serverSocket = new ServerSocket(0xcff2);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 sẽ được khởi tạo khi tắt hoạt động cuối cùng.
Fred F

3
Tôi không hiểu, cái gì bắt được? Điều này hoạt động rất tốt, và với độ phức tạp ít hơn nhiều so với bất kỳ giải pháp nào khác.
RTF

3
Đây là cách chính xác để làm điều đó trong Android. Các cách khác về cơ bản là bắt một vòng quay với configChanges và tất cả những thứ cồng kềnh, phức tạp và không cần thiết.
LukeWaggoner

99

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

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

android:configChanges="keyboardHidden|orientation"

trong mã cho hoạt động, được thực hiện:

//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();
}

3
để làm rõ: với triển khai của tôi, bây giờ bạn có thể có khởi tạo biến trong onCreate () và onConfigurationChanged () sẽ được gọi đơn giản cho xoay màn hình. Các biến của bạn hiện được cách ly khỏi các vòng quay màn hình ;-) đẹp và ez
Ai đó ở đâu đó vào

2
Tôi đã làm mọi thứ đúng như mô tả ở đây, nhưng tôi nhận được NullPulumException khi tôi cố gắng nhấn nút sau khi thay đổi hướng. điều gì sai?
Finnboy11

5
Hãy nhớ rằng 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.
Ai đó ở đâu đó vào

3
Khi cảnh báo chống lại android: configChanges, @ SimonAndréForsberg thực sự chỉ là diễn giải các tài liệu Android . Xử lý 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

67

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

android:configChanges

vào bảng kê khai của bạn và sau đó là những 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à đối với 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ần tách chúng bằng lệnh pipe như:

android:configChanges="keyboardHidden|orientation"

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

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


2
@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 câu hỏi của câu hỏi này, nó vẫn đang được nhắc đến từ các câu hỏi khác về SO.
Simon Forsberg

48

Tôi mới phát hiện ra truyền thuyết này:

Để giữ cho Hoạt động tồn tại thông qua thay đổi hướng và xử lý thông qua onConfigurationChanged, tài liệumẫu mã ở trên gợi ý điều này trong tệp Bản kê khai:

<activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

có lợi ích thêm mà nó luôn hoạt động.

Truyền thuyết bổ sung là việc bỏ qua keyboardHiddencó vẻ hợp lý, nhưng nó gây ra lỗi trong trình giả lập (ít nhất là cho Android 2.1): chỉ định orientationsẽ khiến trình giả lập gọi cả hai OnCreateonConfigurationChangedđôi khi, và chỉOnCreate những lần khác.

Tôi chưa thấy lỗi trên thiết bị, nhưng tôi đã nghe nói về trình giả lập không thành công cho người khác. Vì vậy, nó đáng để ghi lại.


14
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à hướng ngang. Do đó, nếu bạn muốn ngăn khởi động lại thời gian chạy do thay đổi hướng khi phát triển cho cấp API 13 trở lên: android: configChanges = "direction | keyboardHidden | screenSize"
Geltrude

Vâng, trình giả lập hút thời gian lớn. Bạn không thể dựa vào nó để báo cáo thay đổi cấu hình chính xác.
IgorGanapolsky

Thêm android: configChanges chỉ nên được sử dụng như là phương sách cuối cùng . Cân nhắc sử dụng FragmentssetRetainInstancethay vào đó.
Simon Forsberg

38

Bạn cũng có thể cân nhắc sử dụng cách duy trì dữ liệu của nền tảng Android qua các thay đổi định hướng: onRetainNonConfigurationInstance()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ừ quá trình tìm nạp máy chủ hoặc thứ gì đó được tính toán trong onCreatehoặc kể từ đó, đồng thời cho phép Android bố trí lạiActivity bằng cách sử dụng tệp xml cho định hướng hiện đang sử dụng .

Xem ở đây hoặc ở đây .

Cần lưu ý rằng các phương thức này hiện không được chấp nhận (mặc dù vẫn linh hoạt hơn so với việc xử lý thay đổi định hướng vì hầu hết các giải pháp nêu trên) với khuyến nghị mọi người nên chuyển sang Fragmentsvà thay vào đó sử dụng setRetainInstance(true)cho từng phương thức Fragmentbạn muốn giữ lại.


3
Tôi thực sự nghĩ rằng Fragment và setRetainInstance là cách tốt nhất (và được đề xuất bởi Google) để 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ư là phương sách cuối cùng
Simon Forsberg

32

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

Các mảnh 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 các mảnh vỡ đượ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)


7
Đã đồng ý. Với API Android mới nhất, có vẻ như Fragment là cách chính xác để xử lý việc này. Bản thân tôi chưa thử nó, nhưng từ những gì tôi đã thu thập được khi đọ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 thành một lớp con của Mảnh vỡ, sau đó thêm Đoạn đó vào Hoạt động. Hoạt động vẫn sẽ bị hủy và được tạo lại khi xoay màn hình, nhưng bạn có thể đặc biệt nói với Android không phá hủy Fragment bằng setRetainInstance()phương thức @Abdo đã đề cập.
brianmearn

25

Tôi chỉ cần thêm

     android:configChanges="keyboard|keyboardHidden|orientation"

trong tệp kê khai và không thêm bất kỳ onConfigurationChangedphương thức nào vào 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 .


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 Mayhé

19

Các onCreatephương pháp vẫn được gọi là ngay cả khi bạn thay đổi orientationcủa Android. Vì vậy, chuyển tất cả các chức năng nặng sang phương pháp này sẽ không giúp bạn


18

Đặt mã bên dưới trong <activity>thẻ của bạn vào Manifest.xml:

android:configChanges="screenLayout|screenSize|orientation"

17
 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 bản kê khai nói với nó "đừng gọi onCreate() "?

Ngoài ra, các tài liệu của Google nói tránh sử dụng android:configChanges(ngoại trừ như là phương sách cuối cùng) .... Nhưng sau đó, các phương pháp thay thế mà họ đề xuất tất cả đều sử dụng DOandroid:configChanges .

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


16

Rất đơn giản chỉ cần làm các bước sau:

<activity
    android:name=".Test"
    android:configChanges="orientation|screenSize"
    android:screenOrientation="landscape" >
</activity>

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

Lưu ý: định hướng phụ thuộc vào yêu cầu của bạn


15

Những thay đổi được thực hiện trong bảng kê khai Android là:

android:configChanges="keyboardHidden|orientation" 

Bổ sung được thực hiện trong hoạt động là:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

15

Thêm dòng này vào bảng 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);
    }

14

Có nhiều hướng khác nhau để làm điều đó:

Lưu trạng thái hoạt động

Bạn có thể lưu trạng thái hoạt động trong onSaveInstanceState.

@Override
public void onSaveInstanceState(Bundle outState) {
    /*Save your data to be restored here
    Example : outState.putLong("time_state", time); , time is a long variable*/
    super.onSaveInstanceState(outState);
}

và sau đó sử dụng bundleđể khôi phục lại trạng thái.

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

    if(savedInstanceState!= null){
       /*When rotation occurs
        Example : time = savedInstanceState.getLong("time_state", 0); */
    } else {
      //When onCreate is called for the first time
    }
}

Tự xử lý thay đổi định hướng

Một cách khác là tự mình xử lý các thay đổi định hướng. Nhưng đây không được coi là một thực hành tốt.

Thêm phần này vào tệp kê khai của bạn.

android:configChanges="keyboardHidden|orientation"

cho Android 3.2 trở lên:

android:configChanges="keyboardHidden|orientation|screenSize"

@Override
public void onConfigurationChanged(Configuration config) {
    super.onConfigurationChanged(config);

if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        //Handle rotation from landscape to portarit mode here
    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
        //Handle rotation from portrait to landscape mode here
    }
}

Hạn chế xoay

Bạn cũng có thể giới hạn hoạt động của mình ở chế độ dọc hoặc ngang để tránh xoay.

Thêm phần này vào thẻ hoạt động trong tệp kê khai của bạn:

        android:screenOrientation="portrait"

Hoặc thực hiện chương trình này trong hoạt động của bạn:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

11

Cách tôi đã tìm thấy để làm điều này là sử dụng onRestoreInstanceStatevà các onSaveInstanceStatesự kiện để lưu một cái gì đó vào Bundle(ngay cả khi bạn không cần bất kỳ biến nào được lưu, chỉ cần đặt một cái gì đó vào đó để Bundlekhông bị trống). Sau đó, trên onCreatephương thức, kiểm tra xem nếu Bundletrống, và nếu có, sau đó thực hiện khởi tạo, nếu không, sau đó làm điều đó.


11

Mặc dù đó không phải là "cách Android" nhưng tôi đã thu được kết quả rất tốt bằng cách tự xử lý thay đổi định hướng và chỉ cần định vị lại các vật dụng trong chế độ xem để xem xét hướng thay đổi. Cách này nhanh hơn bất kỳ cách tiếp cận nào khác, vì quan điểm của bạn không cần phải được lưu và khôi phục. Nó cũng cung cấp trải nghiệm liền mạch hơn cho người dùng, bởi vì các widget được định vị chính xác là cùng các widget, chỉ cần di chuyển và / hoặc thay đổi kích thước. Không chỉ trạng thái mô hình, mà còn xem trạng thái, có thể được bảo tồn theo cách này.

RelativeLayoutđôi khi có thể là một lựa chọn tốt cho một quan điểm phải định hướng lại theo thời gian. Bạn chỉ cần cung cấp một tập hợp các tham số bố cục dọc và một tập các tham số bố cục được tạo cảnh, với các quy tắc định vị tương đối khác nhau trên mỗi, cho mỗi tiện ích con. Sau đó, trong onConfigurationChanged()phương pháp của bạn , bạn chuyển một setLayoutParams()cuộc gọi thích hợp cho mỗi cuộc gọi. Nếu bất kỳ đứa trẻ nào tự kiểm soát cần phải định hướng lại nội bộ , bạn chỉ cần gọi một phương thức trên đứa trẻ đó để thực hiện định hướng lại. Đứa trẻ đó tương tự gọi phương pháp trên bất kỳ của nó con điều khiển cần tái định hướng nội, và vân vân.


Tôi rất thích nhìn thấy một số mã mẫu này, có vẻ tuyệt vời!
Henrique de Sousa

8

Mỗi khi màn hình được xoay, hoạt động đã mở sẽ kết thúc và onCreate () được gọi lại.

1. Bạn có thể thực hiện một thao tác lưu trạng thái hoạt động khi màn hình được xoay để, Bạn có thể khôi phục tất cả nội dung cũ khi onCreate () của hoạt động được gọi lại. Tham khảo liên kết này

2. Nếu bạn muốn ngăn khởi động lại hoạt động, chỉ cần đặt các dòng sau trong tệp manifest.xml của bạn.

  <activity android:name=".Youractivity"
  android:configChanges="orientation|screenSize"/>

7

bạn cần sử dụng phương thức onSattedInstanceState để lưu trữ tất cả giá trị cho tham số của nó có đó là gói

@Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        outPersistentState.putBoolean("key",value);
    }

Và sử dụng

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.getBoolean("key");
    } 

để khởi động lại và đặt giá trị để xem các đối tượng, nó sẽ xử lý các xoay màn hình


Điều này cần API cấp 22.
Mohammad Afrashteh

6

Lưu ý: Tôi đăng câu trả lời này nếu ai đó trong tương lai đối mặt với cùng một vấn đề như tôi. Đối với tôi dòng sau đây không đủ:

android:configChanges="orientation"

Khi tôi xoay màn hình, phương thức `onConfigurationChanged (Cấu hình newConfig) không được gọi.

Giải pháp: Tôi cũng đã phải thêm "screenSize" ngay cả khi vấn đề phải làm với định hướng. Vì vậy, trong tệp AndroidManifest.xml -, hãy thêm tệp này:

android:configChanges="keyboardHidden|orientation|screenSize"

Sau đó thực hiện phương pháp onConfigurationChanged(Configuration newConfig)


5

Trong phần hoạt động của manifest, thêm:

android:configChanges="keyboardHidden|orientation"


4

Mọi người đang nói rằng bạn nên sử dụng

android:configChanges="keyboardHidden|orientation"

Nhưng cách tốt nhất và chuyên nghiệp nhất để xử lý xoay vòng trong Android là sử dụng lớp Loader. Đây không phải là một lớp học nổi tiếng (tôi không biết tại sao), nhưng nó tốt hơn AsyncTask. Để biết thêm thông tin, bạn có thể đọc các hướng dẫn về Android được tìm thấy trong các khóa học Android của Udacity.

Tất nhiên, như một cách khác, bạn có thể lưu trữ các giá trị hoặc chế độ xem với onSaveInstanceState và đọc chúng với onRestoreInstanceState. Điều đó tùy thuộc vào bạn.


Vâng, hãy thêm gobs của mã bổ sung để trông "chuyên nghiệp". Hoặc làm thế nào về việc chỉ cần tuân theo cách nhanh chóng, dễ dàng, chân thực và đã thử với thuộc tính configureChanges.
AndroidDev

3

Sau một thời gian dùng thử và lỗi, tôi đã tìm thấy một giải pháp phù hợp với nhu cầu của mình trong hầu hết các tình huống. Đây là mã:

Cấu hình rõ ràng:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.pepperonas.myapplication">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

Hoạt động chính:

import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Fragment mFragment;

    private int mSelected = -1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate  " + "");

        // null check not realy needed - but just in case...
        if (savedInstanceState == null) {

            initUi();

            // get an instance of FragmentTransaction from your Activity
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

            /*IMPORTANT: Do the INITIAL(!) transaction only once!
            * If we call this everytime the layout changes orientation,
            * we will end with a messy, half-working UI.
            * */
            mFragment = FragmentOne.newInstance(mSelected = 0);
            fragmentTransaction.add(R.id.frame, mFragment);
            fragmentTransaction.commit();
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged  " +
                   (newConfig.orientation
                    == Configuration.ORIENTATION_LANDSCAPE
                    ? "landscape" : "portrait"));

        initUi();

        Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
        makeFragmentTransaction(mSelected);
    }


    /**
     * Called from {@link #onCreate} and {@link #onConfigurationChanged}
     */
    private void initUi() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate  instanceState == null / reinitializing..." + "");
        Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
        Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
        btnFragmentOne.setOnClickListener(this);
        btnFragmentTwo.setOnClickListener(this);
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME!!!");
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME, AS WELL!!!");
    }


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


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


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


    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_fragment_one:
                Log.d(TAG, "onClick btn_fragment_one " + "");
                makeFragmentTransaction(0);
                break;

            case R.id.btn_fragment_two:
                Log.d(TAG, "onClick btn_fragment_two " + "");
                makeFragmentTransaction(1);
                break;

            default:
                Log.d(TAG, "onClick  null - wtf?!" + "");
        }
    }


    /**
     * We replace the current Fragment with the selected one.
     * Note: It's called from {@link #onConfigurationChanged} as well.
     */
    private void makeFragmentTransaction(int selection) {

        switch (selection) {
            case 0:
                mFragment = FragmentOne.newInstance(mSelected = 0);
                break;
            case 1:
                mFragment = FragmentTwo.newInstance(mSelected = 1);
                break;
        }

        // Create new transaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frame, mFragment);

        /*This would add the Fragment to the backstack...
        * But right now we comment it out.*/
        //        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

}

Và mẫu mảnh:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * @author Martin Pfeffer (pepperonas)
 */
public class FragmentOne extends Fragment {

    private static final String TAG = "FragmentOne";


    public static Fragment newInstance(int i) {
        Fragment fragment = new FragmentOne();
        Bundle args = new Bundle();
        args.putInt("the_id", i);
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView  " + "");
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

}

Có thể được tìm thấy trên github .


3

Sử dụng trình orientationnghe để thực hiện các nhiệm vụ khác nhau trên các định hướng khác nhau.

@Override
public void onConfigurationChanged(Configuration myConfig) 
{
    super.onConfigurationChanged(myConfig);
    int orient = getResources().getConfiguration().orientation; 
    switch(orient) 
    {
       case Configuration.ORIENTATION_LANDSCAPE:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    break;
       case Configuration.ORIENTATION_PORTRAIT:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
       default:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
}

3

Đặt mã dưới đây trong của bạn Activitytrong Android Manifest.

android:configChanges="orientation"

Điều này sẽ không khởi động lại hoạt động của bạn khi bạn sẽ thay đổi hướng.


2
@Mavamaarten Có lẽ bởi vì như những người khác đã chỉ ra, đó là hành động xấu và mười câu trả lời khác đã bao gồm điều này.
MikkoP

3

Sửa hướng màn hình (ngang hoặc dọc) trong AndroidManifest.xml

android:screenOrientation="portrait" hoặc là android:screenOrientation="landscape"

Đối với điều này onResume()phương pháp của bạn không được gọi.


5
Làm thế quái nào sửa một cái gì đó là một câu trả lời? Tại sao thiết bị của chúng tôi có thể xoay nếu chúng tôi khóa người dùng bằng cách sử dụng nó?
Reinherd

3

Một trong những thành phần tốt nhất của kiến ​​trúc android được giới thiệu bởi google sẽ đáp ứng tất cả các yêu cầu của bạn đó là ViewModel.

Điều đó được thiết kế để lưu trữ và quản lý dữ liệu liên quan đến giao diện người dùng theo cách vòng đời cộng với việc sẽ cho phép dữ liệu tồn tại khi xoay màn hình

class MyViewModel : ViewModel() {

Vui lòng tham khảo điều này: https://developer.android.com/topic/lologists/arch architecture / viewmodel


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.