Android Fragment onAttach () không dùng nữa


326

Tôi đã cập nhật ứng dụng của mình để sử dụng thư viện hỗ trợ mới nhất (phiên bản 23.0.0), tôi phát hiện ra rằng họ không dùng chức năng onAttach () của lớp Fragment.

Thay vì:

onAttach (Activity activity)

Tuyết rơi:

onAttach (Context context)

Vì ứng dụng của tôi sử dụng hoạt động được thông qua trước khi phản đối, một giải pháp khả thi tôi nghĩ là:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    activity = getActivity();
}

Đó sẽ là cách chính xác để làm điều đó?

CẬP NHẬT:

Nếu tôi chạy một thiết bị có API thấp hơn 23, onAttach () mới thậm chí sẽ không được gọi. Tôi hy vọng rằng đây không phải là những gì họ dự định làm!

CẬP NHẬT 2:

Vấn đề đã được giải quyết với các bản cập nhật mới nhất cho SDK.

Tôi đã thử nghiệm trên thiết bị API 22 của mình và onAttach (Ngữ cảnh) đang được gọi.

Nhấp vào đây để theo dõi báo cáo lỗi tôi đã mở vài tuần trước và câu trả lời từ những người ở Google.


Nếu bạn đang sử dụng các phương thức Hoạt động cụ thể từ phiên bản đã qua của mình thì bạn đã thử chuyển ngữ cảnh sang Hoạt động của mình chưa? Ghi nhớ Hoạt động là một lớp con của Ngữ cảnh. Có lẽ một buổi casting sẽ làm việc.
MarkSkayff

vì một số lý do, onAttach () thậm chí không được gọi! có ý kiến ​​gì không Bạn đã thử cập nhật lên lib hỗ trợ mới nhất chưa?
TareK Khoury

2
Tại sao API được chuyển đến Context? Bạn không cần một Activitythứ để đính kèm và hiển thị một đoạn dù sao? Làm thế nào khác bạn sẽ sử dụng Contexttham số?
Kenny Worden

1
Tôi đã đăng nó dưới dạng một lỗi, xem liên kết code.google.com/p/android/issues/detail?id=183358
TareK Khoury

6
Để onAttach(Context context)được gọi mới, bạn cần sử dụng một thiết bị có ít nhất API 23 HOẶC sử dụng android.support.v4.app.Fragment. Xem tại đây
nevzo

Câu trả lời:


337

Hoạt động là một bối cảnh vì vậy nếu bạn có thể chỉ cần kiểm tra bối cảnh là một Hoạt động và bỏ qua nó nếu cần thiết.

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity a;

    if (context instanceof Activity){
        a=(Activity) context;
    }

}

Cập nhật: Một số người cho rằng Contextghi đè mới không bao giờ được gọi. Tôi đã thực hiện một số thử nghiệm và không thể tìm thấy một kịch bản trong đó điều này là đúng và theo mã nguồn, nó không bao giờ đúng. Trong tất cả các trường hợp tôi đã thử nghiệm, cả SDK trước và sau SDK23, cả phiên bản ActivityContextphiên bản onAttachđều được gọi. Nếu bạn có thể tìm thấy một kịch bản không phải là trường hợp này, tôi sẽ đề nghị bạn tạo một dự án mẫu minh họa vấn đề và báo cáo cho nhóm Android .

Cập nhật 2: Tôi chỉ sử dụng các đoạn Thư viện hỗ trợ Android vì các lỗi được khắc phục nhanh hơn ở đó. Có vẻ như vấn đề ở trên mà phần ghi đè không được gọi chính xác chỉ được đưa ra ánh sáng nếu bạn sử dụng các đoạn khung.


5
Không thực sự là một giải pháp vì onAttach với bối cảnh không được gọi giống như onAttach với hoạt động. Nếu bạn có một số mã khởi tạo trong onAttach với một hoạt động là tham số thì thay đổi này sẽ không hoạt động.
Buddy

2
Không, nó không hoạt động như nhau, ít nhất là trong trường hợp của tôi. Tôi không sử dụng hoạt động cũng như bối cảnh trong onAttach, tôi thực hiện khởi tạo. Tôi đã thử thay thế onAttach bằng hoạt động sang bối cảnh và nó không được gọi theo cùng một cách. Vì vậy, chúng không dễ dàng thay thế cho nhau.
Buddy

7
Những vấn đề tương tự mà Buddy có ... onAttach(Context)thậm chí dường như không được gọi.
Stéphane

2
Tôi đã chuyển qua mã của mình và tôi có thể xác minh rằng có thể onAttach(context)không được gọi.
Chad Bingham

2
Trong trường hợp của tôi, onAttach () sẽ không được gọi nếu chúng tôi khởi động lại hoạt động đã bị xóa bởi hệ thống trước đó. Nhưng nó không phải lúc nào cũng như thế này. Tôi đặt một khởi tạo của WeakReference trong bối cảnh onAttach (Ngữ cảnh), refActivity = new WeakReference <> ((AppCompatActivity)). Và đôi khi nó ném NullPulumException trong onCreateView ().
Kimi Chiu

45

Đây là một thay đổi lớn khác từ Google ... Sửa đổi được đề xuất: thay thế onAttach(Activity activity)bằng onAttach(Context context)các ứng dụng của tôi bị lỗi trên các API cũ hơn vì onAttach(Context context)sẽ không được gọi trên các đoạn gốc.

Tôi đang sử dụng các đoạn gốc (android.app.Fragment) vì vậy tôi phải làm như sau để làm cho nó hoạt động trở lại trên các API cũ hơn (<23).

Đây là những gì tôi đã làm:

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    // Code here
}

@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        // Code here
    }
}

Thưa ông, ông Hannouet support.v4.app.FragmentManagerImpl.moveToState, tại android.support.v4.app.FragmentManagerImpl.execSingleAction. Ở đây tôi đã đăng những dòng cần thiết mà bạn sẽ biết lỗi của mình.
MohanRaj S

@MohanRajS Tương tự như API 24 (cái tôi đã sử dụng), theo đoạn mã của bạn, vấn đề của bạn dường như không phải làm gì với điều này.
Yoann Hercouet

@YoannHercouet, Cảm ơn bạn đã trả lời, hãy để tôi kiểm tra và cập nhật.
MohanRaj S

1
Bạn không hài lòng với Google về điều này vì khó nhắm mục tiêu các API cũ hơn. Chà, hãy xem xét phước lành mà bạn CÓ THỂ nhắm mục tiêu các API cũ hơn, trong khi đó, chẳng hạn như Apple, sẽ làm tê liệt bạn rất nhiều và buộc bạn chỉ hỗ trợ những API mới nhất.
Stan

39

Nếu bạn sử dụng các đoạn khung và phiên bản SDK của thiết bị thấp hơn 23, OnAttach(Context context)sẽ không được gọi.

Tôi sử dụng các đoạn hỗ trợ thay thế, vì vậy sự phản đối được cố định và onAttach(Context context)luôn được gọi.


11

Hiện tại từ onAttachmã Fragment, không rõ liệu đây có phải Contextlà hoạt động hiện tại không: Mã nguồn

public void onAttach(Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}

Nếu bạn nhìn vào getActivitybạn sẽ thấy cuộc gọi tương tự

/**
 * Return the Activity this fragment is currently associated with.
 */
final public Activity getActivity() {
    return mHost == null ? null : mHost.getActivity();
}

Vì vậy, nếu bạn muốn chắc chắn rằng bạn đang nhận Hoạt động thì hãy sử dụng getActivity()( onAttachtrong của bạn Fragment) nhưng đừng quên kiểm tra nullvì nếu đó mHostnullhoạt động của bạn sẽnull


6
@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity activity = context instanceof Activity ? (Activity) context : null;
}

5

Mặc dù trong hầu hết các trường hợp dường như là đủ onAttach(Context), nhưng có một số điện thoại (ví dụ: Xiaomi Redme Note 2) không được gọi, do đó, nó gây ra NullPulumExceptions. Vì vậy, để an toàn, tôi cũng đề nghị bỏ phương thức không dùng nữa:

// onAttach(Activity) is necessary in some Xiaomi phones
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    _onAttach(activity);
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    _onAttach(context);
}

private void _onAttach(Context context) {
    // do your real stuff here
}

3

Tải xuống thư viện Hỗ trợ mới nhất với trình quản lý sdk và bao gồm

compile 'com.android.support:appcompat-v7:23.1.1'

trong gradle.app và đặt phiên bản biên dịch thành api 23


1

Câu trả lời dưới đây có liên quan đến cảnh báo phản đối này xảy ra trong hướng dẫn Fragment trên trang web của nhà phát triển Android và có thể không liên quan đến các bài đăng ở trên.

Tôi đã sử dụng mã này trong bài học hướng dẫn và nó đã làm việc.

public void onAttach(Context context){
    super.onAttach(context);

    Activity activity = getActivity();

Tôi đã lo lắng rằng hoạt động có thể vô hiệu như những gì tài liệu nêu.

có được

FragmentActivity getActivity () Trả về FragmentActivity mà đoạn này hiện được liên kết với. Có thể trả về null nếu đoạn được liên kết với Ngữ cảnh thay thế.

Nhưng onCreate trên main_activity cho thấy rõ ràng đoạn đó đã được tải và vì vậy sau phương thức này, việc gọi hoạt động get từ đoạn sẽ trả về lớp main_activity.

getSupportFragmentManager (). startedTransaction () .add (R.id.fragment_container, FirstFragment) .commit ();

Tôi hy vọng tôi đúng với điều này. Tôi là một người mới tuyệt đối.


1

có thể bạn đang sử dụng android.support.v4.app.Fragment. Đối với điều này thay vì onAttachphương thức, chỉ cần sử dụng getActivity()để có được đoạn FragmentActivitymà liên kết với đoạn. Khác, bạn có thể sử dụng onAttach(Context context)phương pháp.


0

Điều này làm việc cho tôi khi tôi có Giao diện được xác định bởi người dùng 'TopSectionListener', hoạt động đối tượng của nó:

  //This method gets called whenever we attach fragment to the activity
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    Activity a=getActivity();
    try {
        if(context instanceof Activity)
           this.activitycommander=(TopSectionListener)a;
    }catch (ClassCastException e){
        throw new ClassCastException(a.toString());}

}
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.