Được PreferenceFragment cố ý loại trừ khỏi gói tương thích?


153

Tôi đang tìm cách viết các tùy chọn có thể được áp dụng cho cả thiết bị 3.0 và trước 3.0. Phát hiện ra PreferenceActivitycó chứa các phương thức không dùng nữa (mặc dù chúng được sử dụng trong mã mẫu đi kèm), tôi đã xem xét PreferenceFragementvà gói tương thích để giải quyết tai ương của mình.

Tuy nhiên, nó PreferenceFragmentkhông xuất hiện trong gói tương thích. Bất cứ ai có thể cho tôi biết nếu điều này là cố ý? Nếu vậy, tôi có thể dễ dàng nhắm mục tiêu một loạt các thiết bị (ví dụ <3.0 và> = 3.0) hay tôi sẽ phải nhảy qua vòng? Nếu nó không được loại trừ có chủ ý, chúng ta có thể mong đợi một bản phát hành mới của gói tương thích không? Hoặc có một cách giải quyết khác là an toàn để sử dụng?

Chúc mừng

James


1
Đây là cách tiếp cận của tôi để giải quyết vấn đề: stackoverflow.com/questions/14076073/ cấp
ecv

Ai đó đã thực hiện một bên thứ ba PreferenceFragmentmà bạn sẽ quên thậm chí còn ở đó. Xem câu trả lời của tôi .
theblang

Chris Banes giải quyết điều này trong một bình luận trên blog của mình . Ông nói rằng lý do là,"Because most of Preferences' implementation is hidden, therefore impossible to backport without lots of hackery."
theblang

Xem câu trả lời cập nhật của tôi . PreferenceFragmentCompatgần đây đã được thêm vào thư viện hỗ trợ.
theblang

Câu trả lời:


90

Khám phá ra rằng PreferenceActivity chứa các phương thức không dùng nữa (mặc dù các phương thức này được sử dụng trong mã mẫu đi kèm)

Các phương thức không dùng nữa bị phản đối kể từ Android 3.0. Chúng hoàn toàn tốt trên tất cả các phiên bản Android, nhưng hướng là sử dụng PreferenceFragmenttrên Android 3.0 trở lên.

Bất cứ ai có thể cho tôi biết nếu điều này là cố ý?

Tôi đoán đó là một câu hỏi về thời gian kỹ thuật, nhưng đó chỉ là một phỏng đoán.

Nếu vậy, tôi có thể dễ dàng nhắm mục tiêu một loạt các thiết bị (ví dụ <3.0 và> = 3.0) hay tôi sẽ phải nhảy qua vòng?

Tôi coi nó được thực hiện "dễ dàng". Có hai cái riêngPreferenceActivity triển khai , một sử dụng các tiêu đề ưu tiên và PreferenceFragmentsmột sử dụng phương pháp ban đầu. Chọn đúng tại điểm bạn cần (ví dụ: khi người dùng nhấp vào mục menu tùy chọn). Đây là một dự án mẫu chứng minh điều này. Hoặc, có một đơn PreferenceActivityxử lý cả hai trường hợp, như trong dự án mẫu này .

Nếu nó không được loại trừ có chủ ý, chúng ta có thể mong đợi một bản phát hành mới của gói tương thích không?

Bạn sẽ tìm ra khi phần còn lại của chúng tôi tìm ra, đó là để nói, nếu và khi nó xuất xưởng.

Hoặc có một cách giải quyết khác là an toàn để sử dụng?

Xem ở trên.


Chúc mừng Mark. Tôi đã thấy rằng bạn đã nhận xét về điều này ở một vài nơi (nhóm google android và blog của bạn) nhưng muốn có câu trả lời dứt khoát (theo như người ta có thể đưa ra hoàn cảnh).
James

@James: Vâng, sự cọ xát sẽ nằm trong định nghĩa XML ưu tiên, nhận được thứ gì đó sẽ hoạt động tốt như các đoạn và cũng được nối với nhau, vì tôi không chắc chắn <include>hoạt động với XML ưu tiên. BTW, nếu bạn là người đăng ký, bản cập nhật sách tham khảo dự án này đã được công bố vài phút trước.
CommonsWare

7
Tôi xin lỗi nhưng tôi không thực sự chắc chắn về điểm mà bạn đang cố gắng thực hiện ở đây. Bạn hoàn toàn không trả lời bất cứ điều gì, chỉ bình luận / đoán / đề cập đến các liên kết bên ngoài không liên quan không liên quan đến vấn đề. Câu hỏi đặt ra là có thiếu sót hay không, không có phiên bản tương thích của PreferenceFragment, không có cách nào mở rộng PreferenceActivity theo cách bạn đã mô tả bởi vì nếu PreferenceFragment không tồn tại thì cũng không có phương thức getSupportFragmentManager () hoặc bất kỳ phương thức nào khác bắt buộc phải sử dụng các mảnh vỡ ở nơi đầu tiên.
Justin Buser

8
@JustinBuser: "Câu hỏi đặt ra là có thiếu sót hay không có chủ ý" - những người duy nhất có thể trả lời công việc đó cho Google. Bạn được chào đón để có một công việc tại Google để cố gắng tìm hiểu. "Không có cách nào để mở rộng PreferenceActivity theo cách bạn đã mô tả" - rất mong bạn tải xuống mã mà tôi đã liên kết đến.
CommonsWare

9
@JustinBuser Đối với hồ sơ, Mark đã trả lời câu hỏi của tôi. Đó là điều hiển nhiên từ tôi chấp nhận câu trả lời của anh ấy.
James

21

Hàm ý tinh tế của câu trả lời từ @CommonsWare là - ứng dụng của bạn phải chọn giữa API tương thích hoặc API phân đoạn tích hợp (kể từ SDK 11 trở lên). Trong thực tế đó là những gì khuyến nghị "dễ dàng" đã làm. Nói cách khác, nếu bạn muốn sử dụng PreferenceFragment, ứng dụng của bạn cần sử dụng API phân đoạn tích hợp và xử lý các phương thức không dùng nữa trên PreferenceActivity. Ngược lại, nếu điều quan trọng là ứng dụng của bạn sử dụng compat. API bạn sẽ phải đối mặt với việc không có lớp PreferenceFragment nào cả. Do đó, các thiết bị nhắm mục tiêu không phải là một vấn đề, nhưng việc nhảy vòng xảy ra khi bạn phải chọn một hoặc API khác và do đó gửi thiết kế của bạn tới các cách giải quyết không lường trước được. Tôi cần compat. API vì vậy tôi sẽ tạo lớp PreferenceFragment của riêng mình và xem cách nó hoạt động. Trong trường hợp xấu nhất tôi '

EDIT: Sau khi thử và xem mã tại http://grepcode.com/file/reposective.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceFragment.java? av = h - tạo PreferenceFragment của riêng tôi sẽ không xảy ra. Có vẻ như việc sử dụng gói riêng tư trong PreferenceManager thay vì 'được bảo vệ' là trình chặn chính. Nó thực sự không giống như có bất kỳ bảo mật hoặc động lực thực sự tốt để làm điều đó và nó không tuyệt vời để kiểm tra đơn vị nhưng ồ ... tôi đoán ít gõ hơn ...

EDIT v2: Thật ra nó đã xảy ra và nó đã hoạt động. Điều chắc chắn là đau đầu để làm cho mã hoạt động với JAR API tương thích. Tôi đã phải sao chép khoảng 70% gói com.android.preference từ SDK sang ứng dụng của mình và sau đó vật lộn với mã Java chất lượng tầm thường trong Android. Tôi đã sử dụng v14 của SDK. Một kỹ sư Goog sẽ dễ dàng hơn nhiều khi làm những gì tôi đã làm, trái với những gì tôi đã nghe một số kỹ sư Android chính nói về chủ đề này.

BTW - tôi có nói "thiết bị nhắm mục tiêu không phải là vấn đề" không? Đó hoàn toàn là ... nếu bạn sử dụng com.android.preference, bạn sẽ không thể trao đổi với API Tương thích mà không cần tái cấu trúc chính. Đăng nhập vui vẻ!


Hãy để tôi trực tiếp hơn. Nếu tất cả những gì bạn quan tâm là nhắm mục tiêu Honeycomb và cao hơn (có bao nhiêu thị phần?) Thì hãy bỏ phiếu cho câu trả lời từ @Commonsware! Nếu bạn quan tâm đến phần lớn các thiết bị Android trên thị trường hiện nay, bạn nên đọc qua phản hồi của tôi.
ngoan cường

4
bạn có sẵn sàng chia sẻ bạn đã làm điều này như thế nào không? Tôi đang gặp vấn đề chính xác như nhau, chỉ PreferenceActivity của tôi phải sử dụng Trình tải và do đó tôi phải sử dụng thư viện tương thích.
Karakuri

3
@Tenility Tôi thích cuộc điều tra của bạn - cũng được thực hiện. Tuy nhiên, tôi cảm thấy ai đó nên lập kỷ lục ngay trên bình luận đầu tiên của bạn ở đó - Mã của Commonsware sẽ hoạt động trên các thiết bị HC trước & sau - thử trước khi đưa ra nhận xét như vậy. Điều bạn cần nhận ra là ràng buộc muộn được sử dụng trong thời gian chạy để hỗ trợ các thiết bị trước đó. Kiểm tra phiên bản trong thời gian chạy đảm nhiệm việc hỗ trợ cả hai họ HĐH - đây là mẫu Android phổ biến (không phải mẫu tôi thích - nhưng là mẫu quan trọng để các nhà phát triển Android tìm hiểu và làm quen) ... Vì vậy, với những người đọc tương lai - đừng Tôi sẽ bỏ qua một trong hai cách tiếp cận.
Richard Le Mesurier

@RichardLeMesurier nhưng phương pháp của Commonsware là không phù hợp nếu bạn cần các tùy chọn bên trong DrawerLayout
newworld

16

Dựa trên câu trả lời của CommonsWare cũng như các quan sát của Ten ngoan, tôi đã đưa ra một giải pháp lớp con cháu duy nhất có khả năng nhắm mục tiêu tất cả các phiên bản API Android hiện tại với sự lộn xộn tối thiểu và không có mã hoặc tài nguyên. Vui lòng xem câu trả lời của tôi cho câu hỏi liên quan ở đây: PreferenceActivity Android 4.0 trở về trước

hoặc trên blog của tôi: http://www.blackmoonit.com/2012/07/all_api_prefsactivity/

Đã thử nghiệm trên hai máy tính bảng chạy 4.0.3 và 4.0.4 cũng như điện thoại chạy 4.0.4 và 2.3.3 và cũng là trình giả lập chạy 1.6.



10

Vào tháng 8 năm 2015 Google đã phát hành Thư viện hỗ trợ ưu tiên mới v7 .

Bây giờ bạn có thể sử dụng PreferenceFragmentCompat với bất kỳ ActivityhoặcAppCompatActivity

public static class PrefsFragment extends PreferenceFragmentCompat {

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

        // Load the preferences from an XML resource
        addPreferencesFromResource(R.xml.preferences);
    }
}

Bạn phải thiết lập preferenceThemetrong chủ đề của bạn:

<style name="AppTheme" parent="@style/Theme.AppCompat.Light">
  ...
  <item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>

Theo cách này, bạn có thể tùy chỉnh preferenceThemekiểu dáng các bố cục được sử dụng cho từng loại tùy chọn mà không ảnh hưởng đến các phần khác trong Hoạt động của bạn.


1
Tôi nghĩ rằng bạn bỏ lỡ một chức năng: onCreatePreferences
nhà phát triển Android

Điều này đã cứu ngày của tôi! Tôi tự hỏi tại sao điều này không hiển thị trong Cấu trúc dự án của Android Studio ... ?? BTW bạn có một lỗi đánh máy trong mã của bạn. Nên là "mở rộng PreferenceFragmentCompat"
Grzegorz D.

7

Câu trả lời của Ten ngoan là đúng, nhưng đây là một số chi tiết.

Lý do bạn không thể "tạo bố cục bình thường và liên kết các thành phần xem với chia sẻ thủ công" là có một số thiếu sót đáng ngạc nhiên trong API android.preferences. Cả PreferenceActivity và PreferenceFragment đều có quyền truy cập vào các phương thức PreferenceManager không công khai quan trọng, mà bạn không thể thực hiện UI tùy chọn của riêng mình.

Cụ thể, để xây dựng hệ thống phân cấp Tùy chọn từ tệp XML, bạn cần sử dụng PreferenceManager, nhưng tất cả các hàm tạo của PreferenceManager đều ở chế độ riêng tư hoặc ẩn. Phương pháp đính kèm Trình nghe tùy chọn trên Click vào hoạt động của bạn cũng là gói riêng tư.

Và bạn không thể giải quyết vấn đề này bằng cách lén lút triển khai trong gói android.preferences, bởi vì các phương thức không công khai trong API Android thực sự bị bỏ qua khỏi SDK. Với một chút sáng tạo liên quan đến sự phản chiếu và proxy năng động, bạn vẫn có thể có được chúng. Cách thay thế duy nhất, như Tenacity nói, là chia rẽ toàn bộ gói android.preference, bao gồm ít nhất 15 lớp, 5 bố cục và một số phần tử style.xml và attrs.xml tương tự.

Vì vậy, để trả lời câu hỏi ban đầu, lý do Google không đưa PreferenceFragment vào gói tương thích là vì họ sẽ gặp khó khăn chính xác như Ten ngoan và tôi. Ngay cả Google cũng không thể quay ngược thời gian và công khai các phương thức đó trong các nền tảng cũ (mặc dù tôi hy vọng họ sẽ làm điều đó trong các bản phát hành trong tương lai).


2

Mục tiêu ứng dụng của tôi là API +14 nhưng do sử dụng thư viện hỗ trợ cho một số điều hướng ưa thích, tôi không thể sử dụng android.app.Fragmentvà phải sử dụng android.support.v4.app.Fragment, nhưng tôi cũng cần phải có PreferenceFragmenttại chỗ mà không có thay đổi lớn đối với mã phía sau.

Vì vậy, sửa chữa dễ dàng của tôi để có cả hai thế giới của thư viện hỗ trợ và PreferenceFragment:

private android.support.v4.app.Fragment fragment;
private android.app.Fragment nativeFragment = null;

private void selectItem(int position) {
    fragment = null;
    boolean useNativeFragment = false;
    switch (position) {
    case 0:
        fragment = new SampleSupprtFragment1();
        break;
    case 1:
        fragment = new SampleSupprtFragment2();
        break;
    case 2:
        nativeFragment = new SettingsFragment();
        useNativeFragment = true;
        break;
    }
    if (useNativeFragment) {
        android.app.FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction()
            .replace(R.id.content_frame, nativeFragment).commit();
    } else {
        if (nativeFragment != null) {
            getFragmentManager().beginTransaction().remove(nativeFragment)
                .commit();
            nativeFragment = null;
        }
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
            .replace(R.id.content_frame, fragment).commit();
    }
}

2

Tôi cần tích hợp Tùy chọn vào thiết kế của ứng dụng và tiếp tục hỗ trợ cho 2.3 android. Vì vậy, tôi vẫn cần PreferencesFragment.

Sau một số tìm kiếm, tôi tìm thấy lib hỗ trợ android-v4- preferfragment. Lib này tiết kiệm rất nhiều thời gian để sao chép và tái cấu trúc PreferencesFragment ban đầu như Tenacity đã nói. Hoạt động tốt và người dùng được hưởng ưu đãi.

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.