【问题标题】:Android: launch a custom Preference from a PreferenceActivityAndroid:从 PreferenceActivity 启动自定义首选项
【发布时间】:2011-07-02 21:59:47
【问题描述】:

我希望能够从我的 PreferenceActivity 启动第二个 Preference 屏幕。在第二个首选项屏幕中,我想使用 xml 中的预定义布局。所以,我有两个问题:

如何使用 xml 布局作为 Preference 的布局视图? 如何将此自定义首选项添加到在点击时启动的 PreferenceActivity?

谢谢

*针对不在场证明进行编辑

我正在尝试通过在 xml 中声明要启动的活动来从首选项屏幕启动活动。这会导致此异常:

 04-01 19:04:37.962: ERROR/AndroidRuntime(8061): android.content.ActivityNotFoundException: Unable to find explicit activity class {com.me/CustomPrefScreen}; have you declared this activity in your AndroidManifest.xml?

*另一个更新。但是,如果我将 settings.xml 中的 PrefrenceScreen 替换为 Preference 的某些扩展名,它会覆盖 onClick() 以启动 CustomPrefScreen,那么一切正常。

主要偏好活动:

public class MyPreferences extends PreferenceActivity 
{
    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.settings);
    }
}

settings.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceScreen  
        android:summary="my summary" 
        android:title="my title">
        <intent android:action="android.intent.action.MAIN"
                    android:targetPackage="com.me"
                    android:targetClass="CustomPrefScreen"/>
    </PreferenceScreen>

</PreferenceScreen>

主文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.me"
    android:versionCode="1"
    android:versionName="1.0">
    <application 
        android:icon="@drawable/icon" 
        android:label="@string/app_name" 
        android:theme="@style/Theme.NoBackground">
        <activity 
            android:name=".MyApp"
            android:label="@string/app_name">
            <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
             </activity>
        <activity 
            android:name=".CustomPrefScreen"
            android:label="@string/app_name">
        </activity>
        <activity 
            android:name=".MyPreferences"
            android:label="@string/app_name">
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="4" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest> 

【问题讨论】:

  • 这两件事都在 Api Demos 示例中得到了很好的解释。有趣的是它在 SDK 目录中,因此您的硬盘中现在就有示例。
  • 您是否绝对需要其他偏好作为第二个活动?如果您只想使用多个屏幕,或许只需使用 PreferenceScreen 工作?
  • @Slund。我想使用 PreferenceScreen,但我不确定如何使用自定义 xml 布局;好像只能添加 Preference 类型的视图?
  • 啊哈。现在我明白了这个问题。您希望有一个使用自定义 UI 而不是标准 FooPreference 视图的首选项屏幕。为此,您很可能希望自己的 MyPreference 扩展 Preference。
  • @Slund。嗯,这就是我想知道该怎么做。我可以为 MyPreference 定义布局,单击它时会启动它吗?或者 MyPreference 是否必须启动一个使用我的自定义布局的新活动?

标签: android preferences


【解决方案1】:

一种解决方案是扩展 DialogPreference,它允许为首选项对话框设置自定义布局。这样您就可以列出一个首选项,当您点击它时,您会看到一个包含自定义设置 UI 的对话框。

 <com.xyz.MyPreference 
           android:dialogLayout="@layout/yourlayout"
           android:dialogTitle="Dialog Title"
            android:dialogMessage="Dialog summary"
            android:key="preference_key"
            android:title="Preference Title"
            android:summary="Preference summary"
            android:defaultValue="Default Value" /> 

还有班级

class MyPreference extends DialogPreference {
// along with constructors, you will want to override
    @Override
    protected void onBindDialogView(View view) {
        super.onBindDialogView(view);
        // view is your layout expanded and added to the dialog
            // find and hang on to your views here, add click listeners etc
            // basically things you would do in onCreate
        mTextView = (TextView)view.findViewById(R.Id.mytextview);
        }

        @Override
        protected void onDialogClosed(boolean positiveResult) {
           super.onDialogClosed(positiveResult);

            if (positiveResult) {
                // deal with persisting your values here
            }
        }
}

显然还有一些其他的细节,但这是基本思想。

【讨论】:

  • 我考虑过这个,但真的不想扩展 DialogPreference。我不想要“确定”和“取消”按钮,也不想要对话框样式。我希望自定义 Preference 具有与启动它的 PreferenceActivity 相似的样式。
  • 你可以对 Preference 做同样的事情,并将 android:layout 设置为你的 xml 布局。这样您的布局就会显示在首选项屏幕中。您也可以使用 android:widgetLayout 覆盖小部件部分。然后你监听 onBindView 将监听器附加到你的控件上。
  • 不难,但是..摘要不显示。我希望在点击首选项时显示标题和摘要,并在新窗口中显示自定义布局。
  • 你并不难,你只是想要你想要的 ;-) 你可以创建一个 Preference 扩展并覆盖 onClick 以触发另一个 PreferenceActivity 的意图。
  • 类似于不在场证明的回答?
【解决方案2】:

alibi 的解决方案 - 在 &lt;PreferenceScreen&gt; 条目中定义意图 - 在对 targetPackagetargetClass 字段进行多次试验和错误之后对我有用。

targetPackage 需要是我的应用程序包名称的完整路径(即 AndroidManifest.xml 文件中的 package= 条目)。 targetClass 需要是 Activity 的完整路径 - 包括包名称,即使 Activity 与应用程序位于同一包中。

应用程序的 AndroidManifest.xml 文件也(当然)需要 Activity 的条目。我没有为这个条目定义&lt;intent-filter&gt;,大概是因为actionMAIN(无论Activity 是在与Application 相同还是不同的包中都是如此)。

示例:应用程序的包是com.thissocialworld。我想从PreferencesScreen 启动的活动位于名为com.coolcommon 的包中,活动类为com.thissocialworld.SpecialPreferences&lt;PreferenceScreen&gt; 中的条目如下所示:

<intent android:action="android.intent.action.MAIN"
 android:targetPackage="com.thissocialworld"
 android:targetClass="com.thissocialworld.SpecialPreferences"/>

如果似乎有必要访问PreferencesManager,我可以尝试将action.MAIN 更改为action.PREFERENCES

(PS 我在这里的第一篇文章,我不知道如何将其发布为对不在犯罪现场发起的讨论的评论。)

【讨论】:

    【解决方案3】:

    您可能想要类似于我从图库或相机上传照片的操作。

    package com.atClass.lmt;
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.ContentValues;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.preference.PreferenceActivity;
    import android.preference.Preference;
    import android.preference.Preference.OnPreferenceClickListener;
    import android.provider.MediaStore;
    import android.util.Log;
    
    
    public class Prefs extends PreferenceActivity{
        //public static final int FLAG_ACTIVITY_CLEAR_TOP = 1;
        private static final int MEDIA_IMAGE_REQUEST_CODE = 1;
        private static final int CAMERA_IMAGE_REQUEST_CODE = 2;
        public static Uri cImageUri;
    
        public static Context cContext;
        public static Activity cActivity;
    
        @Override
        protected void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.settings);
    
            this.cContext = (Context)this;
            this.cActivity = (Activity)this;
    
            Preference customPref = (Preference) findPreference("user_display_picture");
            customPref.setOnPreferenceClickListener(
                    new OnPreferenceClickListener() {
                        public boolean onPreferenceClick(Preference preference) {
                            return imageUploadDialog();
                        }
                    });
        }
    
        protected void onStop(){
            super.onStop();
            MapTools.createMapView(false);
            Lmt.serviceBinder.serviceThread("loginDevice");
        }
    
        public boolean imageUploadDialog(){
            final CharSequence[] items = {"Take picture now","Upload from gallery"};
            AlertDialog.Builder lAlertDialog = new AlertDialog.Builder(cContext);
            lAlertDialog.setTitle("Upload action");
            lAlertDialog.setCancelable(true);
            lAlertDialog.setItems(items,
                    new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialogInterface, int i){
                    //Toast.makeText(getApplicationContext(), "Selected item: " +i,  Toast.LENGTH_SHORT).show();
                    if (i == 0){
                        attachCameraImage();
                    }
                    if (i == 1){
                        attachGalleryImage();
                    }
                }
            });
            lAlertDialog.setIcon(R.drawable.click_to_url);
            lAlertDialog.show();
            return true;
        }
    
        public void attachGalleryImage(){
            Intent getImageFromGalleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
            startActivityForResult(getImageFromGalleryIntent, MEDIA_IMAGE_REQUEST_CODE);
        }
    
        public void attachCameraImage(){
            String fileName = "testphoto.jpg";
            ContentValues values = new ContentValues();
            values.put(MediaStore.Images.Media.TITLE, fileName);
            values.put(MediaStore.Images.Media.DESCRIPTION,"Image capture by camera");
            values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
            cImageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cImageUri);
            intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
            startActivityForResult(intent, CAMERA_IMAGE_REQUEST_CODE);
        }
    
        protected final void onActivityResult(final int requestCode, final int resultCode, final Intent i) {
            Log.d(Global.TAG,"--> Received callback with:" + resultCode);
            super.onActivityResult(requestCode, resultCode, i);
            if(resultCode == RESULT_OK) {
                Log.d(Global.TAG,"--> Result OK with:" + requestCode);
                switch(requestCode) {
                case MEDIA_IMAGE_REQUEST_CODE:
                    Log.d(Global.TAG,"--> MEDIA_IMAGE_REQUEST_CODE");
                    Gui.GuiProgressDialog.showLoadingSpinner(cActivity);
                    cImageUri = i.getData();
                    if (cImageUri == null){Log.d(Global.TAG,"--> ImageURI is null!");}
                    Lmt.serviceBinder.serviceThread("uploadMemberPicture");
                    break;
                case CAMERA_IMAGE_REQUEST_CODE:
                    Log.d(Global.TAG,"--> CAMERA_IMAGE_REQUEST_CODE");
                    //cImageUri = i.getData();
                    if (cImageUri == null){Log.d(Global.TAG,"--> ImageURI is null!");}
                    Lmt.serviceBinder.serviceThread("uploadMemberPicture");
                    break;
                }
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      您可以为此使用自定义活动。只需设计活动并将其作为 PreferenceScreen 包含在您的首选项中。

      <PreferenceScreen  android:summary="@string/pref_summary" android:title="@string/title_summary">
        <intent android:action="android.intent.action.MAIN"
           android:targetPackage="targetPackage"
           android:targetClass="targetClass"/>
      </PreferenceScreen>
      

      不要忘记在清单中注册您的活动!

      【讨论】:

      • 谢谢,这是有道理的。但是,它失败并出现以下异常,即使我绝对确定我在清单中注册了该活动。知道为什么吗? “android.content.ActivityNotFoundException:无法找到显式活动类 {com.me.CustomPreference};您是否在 AndroidManifest.xml 中声明了此活动?”
      • 并非如此。我无法让这个建议发挥作用,在 xml 中定义新意图。如果我扩展 Prefence 并覆盖 onClick() 以启动新意图,它确实可以正常工作。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-13
      • 2011-10-05
      • 1970-01-01
      相关资源
      最近更新 更多