Android: запуск пользовательских настроек из PreferenceActivity

Я хотел бы запустить второй экран настроек из моей PreferenceActivity. И во втором экране "Предпочтения" я хотел бы использовать предопределенный макет из xml. Итак, у меня есть два вопроса:

Как использовать макет xml в качестве вида макета предпочтения? Как добавить это пользовательское предпочтение к PreferenceActivity, которое запускается при нажатии?

Спасибо

* EDIT в ответ на alibi

Я пытаюсь запустить действие с экрана предпочтений, объявив, что действие будет запущено в 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?

* Еще одно обновление. Однако, если я заменил PrefrenceScreen в settings.xml с некоторым расширением 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>

файл mainfest

<?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> 

Ответ 1

Одним из решений было бы расширить DialogPreference, который позволяет настроить настраиваемый макет для диалога настроек. Таким образом, у вас есть предпочтение, и когда вы нажимаете его, вы получаете диалог с пользовательским интерфейсом пользовательских настроек.

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

Очевидно, есть некоторые другие детали, но это основная идея.

Ответ 2

alibi solution - определение намерения внутри записи <PreferenceScreen> - работал у меня после много проб и ошибок полей targetPackage и targetClass.

targetPackage должен быть полный путь к имени пакета моего приложения (т.е. записи package= в файле AndroidManifest.xml). targetClass должен быть полным путем для Activity - ВКЛЮЧАЯ имя пакета, даже если Activity находится в том же пакете, что и приложение.

Файл AndroidManifest.xml для приложения также (конечно) нуждается в записи для Activity. Я не определял <intent-filter> для этой записи, предположительно потому, что action равен MAIN (это было верно, была ли активность в том же или другом пакете, кроме приложения).

Пример: пакет приложений com.thissocialworld. Активность, которую я хотел бы начать с PreferencesScreen, находится в пакете с именем com.coolcommon, а класс Activity - com.thissocialworld.SpecialPreferences. Запись в <PreferenceScreen> выглядит следующим образом:

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

Я могу попробовать изменить action.MAIN на action.PREFERENCES, если кажется необходимым получить доступ к PreferencesManager.

(PS мой первый пост здесь, я не мог понять, как опубликовать это как комментарий к обсуждению, начатому alibi.)

Ответ 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  android:summary="@string/pref_summary" android:title="@string/title_summary">
  <intent android:action="android.intent.action.MAIN"
     android:targetPackage="targetPackage"
     android:targetClass="targetClass"/>
</PreferenceScreen>

Не забудьте зарегистрировать свою активность в манифесте!