Tại sao tôi muốn tránh các hàm tạo không mặc định trong các đoạn?


173

Tôi đang tạo một ứng dụng với Fragmentsvà trong một trong số đó, tôi đã tạo một hàm tạo không mặc định và nhận được cảnh báo này:

Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead

Ai đó có thể cho tôi biết tại sao điều này không phải là một ý tưởng tốt?

Bạn cũng có thể đề nghị làm thế nào tôi sẽ thực hiện điều này:

public static class MenuFragment extends ListFragment {
    public ListView listView1;
    Categories category;

    //this is my "non-default" constructor
    public MenuFragment(Categories category){
        this.category = category;
    }....

Không sử dụng hàm tạo không mặc định?



3
Không, những người không giúp đỡ. Họ đã không trả lời câu hỏi của tôi. Nhưng cảm ơn bạn không kém :)
BlackHatSamurai

31
@BlaineOmega Thật ra cái này nói riêng: stackoverflow.com/a/11602478/321697 chắc chắn trả lời câu hỏi của bạn. Trên một sự thay đổi định hướng hoặc sự kiện khác khiến Fragment được tạo lại, Android sử dụng hàm tạo mặc định cũng như Bundle được truyền làm đối số. Nếu bạn đang sử dụng một hàm tạo tùy chỉnh, thì ngay sau khi đoạn được tạo lại do một trong những sự kiện này, bất cứ điều gì bạn đã làm trong hàm tạo tùy chỉnh sẽ bị mất.
Kevin Coppock

1
Cảm ơn, nhưng điều đó trả lời tại sao, nhưng không phải như thế nào.
BlackHatSamurai

Điều đó được bao phủ bởi các liên kết đầu tiên và thứ hai trong nhận xét ban đầu của tôi.
CommonsWare

Câu trả lời:


110

Tạo một đối tượng bó và chèn dữ liệu của bạn (trong ví dụ này là Categoryđối tượng của bạn ). Hãy cẩn thận, bạn không thể truyền đối tượng này trực tiếp vào gói, trừ khi nó được tuần tự hóa. Tôi nghĩ rằng tốt hơn là xây dựng đối tượng của bạn trong đoạn và chỉ đặt một id hoặc một cái gì đó khác vào gói. Đây là mã để tạo và đính kèm một gói:

Bundle args = new Bundle();
args.putLong("key", value);
yourFragment.setArguments(args);

Sau đó, trong dữ liệu truy cập đoạn của bạn:

Type value = getArguments().getType("key");

Đó là tất cả.


3
Làm thế nào để vượt qua một đối tượng? Tôi muốn vượt qua một Đối tượng bối cảnh hoặc bất kỳ đối tượng nào khác.
Adil Malik

12
Các gói có thể mang các đối tượng Java được tuần tự hóa cũng như Parcelablecác đối tượng. Ngoài ra, bạn không nên vượt qua a Context, vì thông tin đó có thể được truy cập thông qua getActivity()phương thức của đoạn .
krakatoa

Trong mảnh vỡ để làm điều này ở Type value = getArguments().getType("key");đâu?
Muhammad Babar

4
@Muhammad Babar: Nếu tôi là bạn, tôi sẽ thêm nó vào newInstance()phương thức. Ví dụ : public static FragmentName newInstance(your variables){}. Như tài liệu Android khuyến nghị, không tạo một hàm tạo với các tham số, bởi vì tham số mặc định (không có tham số) sẽ được gọi tự động sau khi khởi động lại đoạn của bạn.
nistv4n

@MuhammadBabar onCreateView vẫn ổn
chanjianyi

272

Có vẻ như không có câu trả lời nào thực sự trả lời "tại sao sử dụng gói để truyền tham số thay vì các hàm tạo không mặc định"

Lý do tại sao bạn nên truyền tham số qua gói là vì khi hệ thống khôi phục fragment(ví dụ: khi thay đổi cấu hình), nó sẽ tự động khôi phục lại bundle.

Các cuộc gọi lại thích onCreatehoặc onCreateViewnên đọc các tham số từ bundle- theo cách này bạn được đảm bảo khôi phục trạng thái fragmentchính xác về trạng thái giống như trạng thái fragmentđược khởi tạo với (lưu ý trạng thái này có thể khác với trạng thái được onSaveInstanceState bundletruyền cho onCreate/onCreateView)

Khuyến nghị sử dụng newInstance()phương pháp tĩnh chỉ là một khuyến nghị. Bạn có thể sử dụng một hàm tạo không mặc định nhưng đảm bảo rằng bạn điền các tham số khởi tạo vào bundlebên trong phần thân của hàm tạo đó. Và đọc các tham số trong onCreate()hoặc onCreateView()phương thức.


2
Giải thích tốt. Cảm ơn. Nếu tôi là người đặt câu hỏi, tôi sẽ đánh dấu cho bạn
Karue Benson Karue

5
Bạn không còn có thể sử dụng hàm tạo không mặc định (vì bất kỳ lý do gì) .... nó gây ra lỗi trình biên dịch (được sử dụng để cảnh báo).
MPavlak

51

Bạn Fragmentkhông nên có các nhà xây dựng vì cách FragmentManagerkhởi tạo nó. Bạn nên có một newInstance()phương thức tĩnh được xác định với các tham số bạn cần, sau đó gói chúng và đặt chúng làm đối số của đoạn, sau này bạn có thể truy cập bằng Bundletham số.

Ví dụ:

public static MyFragment newInstance(int title, String message) {
    MyFragment fragment = new MyFragment();
    Bundle bundle = new Bundle(2);
    bundle.putInt(EXTRA_TITLE, title);
    bundle.putString(EXTRA_MESSAGE, message);
    fragment.setArguments(bundle);
    return fragment ;
}

Và đọc những lập luận này tại onCreate:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    title = getArguments().getInt(EXTRA_TITLE);
    message = getArguments().getString(EXTRA_MESSAGE);

    //...
}

Bằng cách này, nếu tách rời và gắn lại, trạng thái đối tượng có thể được lưu trữ thông qua các đối số, giống như được bundlesgắn vào Intents.


9

Nếu bạn sử dụng tham số cho một số lớp. thử cái này

SomeClass mSomeInstance;
public static final MyFragment newInstance(SomeClass someInstance){
    MyFragment f = new MyFragment();
    f.mSomeInstance = someInstance;
    return f;
}

5
Đây thực sự là một gợi ý tồi. Khi Fragment sẽ được tạo lại bởi a FragmentManager, bạn sẽ mất mSomeInstance.
Yaroslav Mytkalyk

Đồng ý, someClass phải có thể phân chia và được lưu trữ trong một gói bằng cách sử dụng setArgument ()
Jake_

1

Tôi nghĩ rằng, không có sự khác biệt giữa hàm tạo tĩnh và hai hàm tạo (trống và tham số hóa lưu trữ các đối số vào gói đối số của Fragment), rất có thể, quy tắc này được tạo ra để giảm xác suất quên thực hiện hàm tạo không có đối số trong Java , mà không được tạo ra ngầm khi quá tải hiện tại.

Trong các dự án của tôi, tôi sử dụng Kotlin và triển khai các đoạn với hàm tạo không có đối số chính và hàm tạo thứ cấp cho các đối số chỉ lưu trữ chúng thành một gói và đặt nó làm đối số Fragment, mọi thứ đều hoạt động tốt.


0

Nếu đoạn sử dụng các hàm tạo không mặc định sau khi thay đổi cấu hình thì đoạn đó sẽ mất tất cả dữ liệu.

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.