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>
Не забудьте зарегистрировать свою активность в манифесте!