我怎么可以用同一套preference屏幕从2.X所有的Andr​​oid版本4.x的?有的、可以用、屏幕、版本

2023-09-12 23:57:30 作者:陪我9一点

说明:请保存自己的一些时间,指的是接受的答案,没有必要阅读所有的quesiton 您可以阅读问题的其余部分,我提供了另一种答案(虽然不太复杂的)方法。 此外,您可能想在安卓2.X后台故障修复的优势,通过增加相关一张code到你的preference活动类。

NOTICE: Please save yourself some time and refer to the accepted answer, no need to read all the quesiton. You may read the rest of the question and the answer I provided for an alternative (although less sophisticated) method. Also, you may want to take advantage of the fix for the background glitch in Android 2.X, by adding the related piece of code to your preference activity class.

背景 作为一个新手到Android代码,但在其他编程语言/框架有所经历,我期待我步行到Android应用程序编码将是一个相当愉快。就这样,直到我偶然发现了这个问题:

Background Being a newbie to Android coding, but somewhat experienced in other programming languages/frameworks, I was expecting my walk to Android application coding would be a rather pleasant one. It was so, until I stumbled upon this problem:

Eclipse的向导建议我可以达到95%的设备,如果我把我的最小的API 8(Android 2.2的)。我并不需要做任何花哨的东西与我的应用程序反正,所以我想,当然,为什么不呢?。一切都还好,只是偶尔我会找到一些方法/类是pcated在最新的API版本去$ P $,所以我不得不想方设法继续使用旧的方式对旧设备,并尝试使用尽可能多尽可能为较新的Andr​​oid版本的新途径。这是一个这样的机会。

Eclipse wizard for Android projects suggested I could reach a 95% of devices if I set my minimum API to 8 (Android 2.2). I didn't need to do any fancy things with my app anyways, so I thought, "sure, why not?". Everything was okay, except occasionally I'd find several methods/classes that were deprecated in most recent API versions, and so I had to devise ways to keep using the old ways for old devices, and try to use as much as possible the new ways for newer Android versions. This is one such occasion.

使用Eclipse向导创建一个preference活动后,我意识到了Eclipse precompiler /解析器/校验器(或任何它被称为)林特,会抱怨不能够利用的新途径创建/管理preferences老年人的API版本。所以我想,没事,螺丝新的途径。让我们做旧的方式,并因为新的API的版本应该是向后兼容的,它应该是好的,但事实并非如此。用老方式方法/标记为德precated班;其中,对我来说,这意味着,尽管他们还是会努力在目前的API,他们会在未来的版本中某些时候停止工作。

After using the Eclipse wizard for creating a preference activity, I realized that the Eclipse precompiler/parser/checker(or whatever it's called) Lint, would complain about not being able to use the new ways of creating/managing preferences in older API versions. So I thought, "all right, screw the new ways. Let's do it old way and since new API versions are supposed to be backward-compatible, it should be okay", but it wasn't. Old way used methods/classes that are marked as deprecated; which, to me, means, even though they'd still work in current API, they'd stop working at some point in future releases.

所以我开始寻找合适的方式来做到这一点,终于命中本页面:What使用而不是"新增preferencesFromResource"在preferenceActivity?哪里阁楼威尔逊解释的方式来使用旧preference屏幕资源的方式与新的办法相兼容。这是伟大的,终于有感觉,我可以和我的应用程序代码继续前进,但它不会针对老年API时,因为它是用新的API code工作。所以,我不得不想出一个办法,使之成为老API和新的工作。与它摆弄了一会儿后,我设法找到一种方法,通过使用precompiler(或任何它被称为)注解和伟大的getClass()。伴随着异常GetMethod的()。

So I started searching for the right way to do this, and finally hit this page: What to use instead of "addPreferencesFromResource" in a PreferenceActivity? where Garret Wilson, explains a way to use old preference screen resources in a way compatible with the new ways. It was great, and finally had the feeling I could move on with my app coding, except it wouldn't work when targeting older APIs, as it was using newer APIs code. So I had to devise a way to make it work for both old APIs and newer. After tinkering with it for a while I managed to find a way, by using precompiler(or whatever it's called) annotations and the great getClass().getMethod() along with exceptions.

一切似乎都工作得很好,直到我创建了一个preference子画面。它是在新的Andr​​oid版本中正确显示,但是当我试图在旧的,我只看到一个黑色的屏幕。一番搜索之后,我发现这个网页,其中说明了这个问题:http://$c$c.google.com/p/android/issues/detail?id=4611这显然​​是这一直是各地的几款Android版本了好一会儿一个已知的干扰。我读了整个线程,并发现了一些问题提出了解决办法,但我真的不喜欢完全是他们中的任何。就我个人来说,preFER,以避免许多静态的东西,我可以做的事情编程。我preFER自动化了重复性的工作。一些解决方案建议创建子屏幕为母屏,然后将其添加到清单文件,并从父屏幕通过一个意图调用它们。我真的很讨厌不得不保持这些东西的轨道:在清单中,分隔屏幕资源文件条目,意图......所以这是一个没有没有我。我一直在寻找,发现一个纲领性的方法,我喜欢好多了......才发现它没有工作。它包括通过preference画面的整体视图树遍历和分配适当的背景preference子屏幕,但它只是没有工作,因为我后来发现,经过多次调试,preference分屏视图是不是preference屏视图的孩子。我必须找到一个方法来做到这一点我自己。我想,我能想到的,研究和研究都没有用尽可能多的东西。我在抛弃在多个场合的边缘,但在约两周不断努力和许多调试后,我发现了一个解决办法,这是我张贴在评论#35。

Everything seemed to work flawlessly until I created a preference sub-screen. It was displaying correctly in newer Android versions, but when I tried in older ones, I could merely see a black screen. After much searching, I found this page which explains the issue: http://code.google.com/p/android/issues/detail?id=4611 This is apparently a known glitch that's been around several Android versions for a good while. I read the whole thread and found several proposed solutions to the problem, but I really didn't like entirely any of them. I, for one, prefer to avoid as much static stuff as I can, and do things programmatically. I prefer automation over repetitive work. Some solutions suggested to create sub-screens as parent screens, then adding them onto the manifest file, and calling them from the parent screen through an intent. I'd really hate having to keep track of those things: entries in manifest, separated screen resource file, intents... So that was a no-no for me. I kept looking and found a programmatic approach I liked much better... only to find that it didn't work. It consisted of iterating through the whole view tree of the preference screen and assigning a proper background to preference sub-screens, but it just didn't work because, as I later found out after much debugging, preference sub-screens views are not a child of preference screen views. I had to find a way to achieve this myself. I tried as many things as I could think of, researched and researched to no avail. I was at the verge of abandoning at several occasions, but after some two weeks of continued effort and much debugging I found a workaround, which I posted in comment #35.

意见 这真的不是完美的解决方案/方法,我知道它的一些缺点,但它是一个工程,所以我决定,我会分享。但愿我不是太可笑了我的热情来分享花了我什么,我会考虑相当多的努力,因为我知道这是不是很大的问题,即有经验的codeR可以解决。但是,嘿,我想分享的知识让我好一点,不管我多么吹牛,不是一个有经验的codeR谁使一切自己。只是分享我的意见,因为我不相信没有人之前曾经有过这个问题,但我相信很多有过,并没有刻意去分享自己的知识。

Opinion It really isn't the perfect solution/approach, and I'm aware of several of its drawbacks, but it's one that works, so I decided I would share it. Hopefully I'm not being too ridiculous in my enthusiasm to share what has taken me what I'd consider quite a lot of effort, as I'm aware it's not that great of an issue, that any experienced coder could solve. But hey, I think sharing knowledge makes me a bit better, no matter how much I brag, than an experienced coder who keeps everything to himself. Just sharing my opinion, because I can't believe nobody ever had this problem before, but I do believe many have had it and didn't bother to share their knowledge.

在与提议的类使用过几个版本的Andr​​oid,并在其使用的一些建议,答案我present你。我愿意讨论和贡献,使之成为较好的一类。

I present you in the answer with a proposed class to use over several versions of Android, and some suggestions on its usage. I'm open to discussion and contributions to make it a better class.

已知问题:

父屏幕装饰看法的背景是克隆到子屏幕装饰背景来看,这显然是不正常的行为。 状态:驳回,直到有人来了一个很好的理由来解决这个问题的 在崩溃后,屏幕旋转 状态:固定式 可能与较新的API实现(内部类PF)资源可见性 从preferenceFragment显然继承类需要有所有成员静态的。我想这是有道理的,如果你应该继承每次你需要使用一个新的片段的时间 Parent screen Decor view background is cloned onto child screen Decor view background, which apparently isn't the normal behavior. Status: dismissed until somebody comes up with a good reason to fix this Crashes upon screen rotation Status: Fixed. Probably related to resource visibility by newer API implementation (inner class PF) Apparently inherited classes from preferenceFragment need to have all their members static. I guess it makes sense if you're supposed to inherit every time you need to use a new fragment

推荐答案

如果你是最新的ADT插件,有一个选项可以轻松地创建支持大多数较旧的Andr​​oid版本preference活动,以及所有的新的。

If you are on the latest ADT plugin, there is an option to easily create a preference Activity that supports most older Android versions as well as all the new ones.

右键点击你的项目 - >其他 - > Android的活动

Right click on your project -> Other -> Android Activity

然后选择SettingsActivity

Then choose SettingsActivity

创建将采取与高和低的API版本工作的关心,因为它使用if语句来选择显示preferences的适当方法的活动。

The Activity created will take take care of working with both high and low API versions since it uses if statements to choose the appropriate method of displaying the preferences.

修改 好点被带到了:手机大小的设备,无论API版本使用旧 preferenceActivity 的方法。

EDIT A good point was brought up: Phone-Sized devices, regardless of API version use the old PreferenceActivity methods.

要获得API 11+设备使用片段最快的方法是删除 isXLargeTablet(上下文);! isSimple preferences()

The quickest way to get API 11+ devices to use Fragments is to remove !isXLargeTablet(context); from isSimplePreferences()

private static boolean isSimplePreferences(Context context) {
    return ALWAYS_SIMPLE_PREFS
            || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
}

不过,现在的用户有更多的导航做的。照片

However, now the user has more navigation to do.

这是因为 onBuildHeaders()之称。

要摆脱这一点,我们需要使我们自己的preferenceFragment,增加了每个XML资源。

To get rid of this, we will need to make our own PreferenceFragment that adds each xml resource.

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class AllPreferencesFragment extends PreferenceFragment{
        @Override
        public void onCreate (Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_general);

            // Add 'notifications' preferences, and a corresponding header.
            PreferenceCategory fakeHeader = new PreferenceCategory(getActivity());
            fakeHeader.setTitle(R.string.pref_header_notifications);
            getPreferenceScreen().addPreference(fakeHeader);
            addPreferencesFromResource(R.xml.pref_notification);

            // Add 'data and sync' preferences, and a corresponding header.
            fakeHeader = new PreferenceCategory(getActivity());
            fakeHeader.setTitle(R.string.pref_header_data_sync);
            getPreferenceScreen().addPreference(fakeHeader);
            addPreferencesFromResource(R.xml.pref_data_sync);

            // Bind the summaries of EditText/List/Dialog/Ringtone preferences to
            // their values. When their values change, their summaries are updated
            // to reflect the new value, per the Android Design guidelines.
            bindPreferenceSummaryToValue(findPreference("example_text"));
            bindPreferenceSummaryToValue(findPreference("example_list"));
            bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
            bindPreferenceSummaryToValue(findPreference("sync_frequency"));
        }
    }

如果你能确定从活动的启动设置外屏幕尺寸,你可以指定一个片段,它通过 EXTRA_SHOW_FRAGMENT

If you can determine the screen size from outside the Activity that launches the settings, you can specify a fragment for it to launch via EXTRA_SHOW_FRAGMENT

i.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, "com.example.test.SettingsActivity$AllPreferencesFragment");

或者你可以有 SettingsActivity 决定是否显示该片段(假设你满意的 isXLargeTablet()方法。

Or you can have the SettingsActivity determine whether or not to show this Fragment (assuming you're happy with the isXLargeTablet() method.

修改 onBuildHeaders()来:

@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
    if (!isSimplePreferences(this) && isXLargeTablet(this)) {
        loadHeadersFromResource(R.xml.pref_headers, target);
    }
}

添加此方法:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setupNewApiPhoneSizePreferences() {
    if (!isXLargeTablet(this) && Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB){
            getFragmentManager().beginTransaction().replace(android.R.id.content, new AllPreferencesFragment()).commit();
    }
}

而在 onPostCreate()添加方法调用。

setupNewApiPhoneSizePreferences();

这个现在应该使用非德precated从API调用11起。

This should now use non-deprecated calls from API 11 onwards.