从preferences.xml启动活动并在onActivityResult中获取结果

17
这是对 这个问题 的补充。
我可以启动Activity,但也需要能够获取结果。我该怎么做?
我尝试在PreferencesActivity中重写onActivityResult,但没有成功。
我是否在preferences.xml中漏掉了一些额外的属性?

1
可能是重复问题:https://dev59.com/g0_Ta4cB1Zd3GeqPBHte - Jason Robinson
4个回答

17

我所知道的最干净的解决方案是监听preferences上的点击事件并显式地启动intent。这样,onActivityResult将像往常一样被调用。

假设您的intent-preference在XML中定义,您可以像这样附加一个监听器(其中1234onActivityResult的请求代码):

Preference pref = (Preference) findPreference("prefKey");
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
  @Override
  public boolean onPreferenceClick(Preference preference) {
    startActivityForResult(preference.getIntent(), 1234);
    return true;
  }
});

14
尝试在您的 PreferencesActivity 类中重写 startActivity() 方法,并在检查意图是我们感兴趣的之后,改为调用 startActivityForResult(),类似于以下示例(使用 1234 作为请求代码):
public class PreferencesActivity {
    // ...

    @Override
    public void startActivity(Intent intent) {
        if (thisIsTheExpected(intent)) {
            super.startActivityForResult(intent, 1234);
        } else {
            super.startActivity(intent);
        }
    }

    @Override
    protected void onActivityResult(int reqCode, int resCode, Intent data) {
        if (reqCode == 1234) {
            // should be getting called now
        }
    }

    // ...
}

根据您的需求,这可能比在代码中添加多个OnPreferenceClickListener更简单 :)


不错的想法,尽管我担心它可能会在未来的Android版本中出现问题,因为它假设startActivity(Intent)总是在单击首选项项时调用。此外,thisIsTheExpected(intent)似乎不太直观,因此更容易出错,而与首选项键匹配则更为简单明了。因此,目前我将采用自己的解决方案。 - Kaarel

3
如果您想从偏好设置活动传递数据到主活动,请使用以下代码:
在您的主活动类(启动)中:
startActivityForResult(new Intent(main.this, preferences.class), 0);

在您的首选项活动类中(设置结果):
Intent i;
i.putStringExtra("name", "tom");
setResult(RESULT_OK, i);
finish();

在你的主活动类中(获取结果):
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 0) {
        if (resultCode == RESULT_OK){
            Log.d("test", data.getExtraString("name");
        }
    }
}

你可以添加任意数量的附加项,不仅限于字符串,而是所有标准数据类型。
希望我做得没错 ;)
编辑:
正如Kaarel告诉我的那样,我可能误解了问题。 这是在首选项活动中接收来自主活动数据的方法:
在您的主活动中:启动首选项活动并附加数据。
String foo = "hello";
Intent i = new Intent();
i.putExtra("testString", foo);//You can also add other types of variables here, see [1] for reference
i.setClass(main.this, preferences.class);
startActivity(i);

在您的偏好设置活动中:接收附加到意图的数据。
Bundle b = this.getIntent().getExtras();//[2]
if (b!=null){
    String recievedString = b.getString("testString");
    //The recievedString variable contains the String "hello" now, see [3]
}

[1] https://developer.android.com/reference/android/content/Intent.html意图是一个抽象的描述,用于请求操作或传递消息到另一个组件(如活动、服务、广播接收器等)。

[2] https://developer.android.com/reference/android/content/Intent.html#getExtras%28%29getExtras()方法返回与此意图关联的额外数据包。

[3] https://developer.android.com/reference/android/os/Bundle.htmlBundle类是一种存储映射,其中所有键和值都是字符串类型。它们通常用于在不同组件之间传递数据。


你没有回答OP提出的问题。问题是:如何处理从首选项活动启动的意图的结果,即onActivityResult应该在PreferencesActivity中。 - Kaarel
这个问题让我感到困惑...你的答案似乎是正确的。 - MazeChaZer

1

如果您查看平台源代码中的PreferenceActivity.java此处的第1000行,您可以看到您的意图通过startActivity startActivity(header.intent); 而不是通过startActivityForResult调用,因此我认为这是不可能的。

但是,您可以尝试覆盖PreferenceActivity的 onHeaderClick 函数以及 onActivityResult ,然后查看会发生什么。我自己没有尝试过,所以我不知道,并且很有可能这种方法在未来的版本中会失效。

但是也许还有另一种适合您的方法。从您的参考问题中,我可以看出您正在通过意图启动一个活动。如果此活动用于设置编辑,则这不是正确的方法,因为Android仅使用此意图来启动活动而已。我认为最好通过扩展任何可用的类来创建特定的首选项活动以进行自定义。这是我自定义的ListPreference,我用它来让用户选择应用程序:

public class CustomSelectAppPreference extends ListPreference {

//----- Constructor -----
public CustomSelectAppPreference(Context context, AttributeSet attrs) {
    super(context, attrs);
}
//----- Constructor END -----



//----- Public Code -----
public void SetResult(String packageName) {
    if(this.callChangeListener(packageName)) {
        Editor edit = this.getSharedPreferences().edit();
        edit.putString(this.getKey(), packageName);
        edit.commit();
    }

    this.getDialog().dismiss();
}
//----- Public Code END -----



//----- ListPreference Overrides -----
@Override
protected void onPrepareDialogBuilder(Builder builder) {
    Log.d("CustomSelectAppPreference", "onPrepareDialogBuilder");

    super.onPrepareDialogBuilder(builder);

    String selectedPackage = this.getSharedPreferences().getString(this.getKey(), "");

    ListAdapter listAdapter = (ListAdapter) new ApplicationsArrayAdapter(this.getContext(), Utilities.getInstalledApplications(this.getContext(), selectedPackage), this);

    builder.setAdapter(listAdapter, this);
}   
//----- ListPreference Overrides END -----
} 

而且我现在是这样在我的preferences.xml中使用它的:

<PreferenceScreen android:key="connection_screen"
        android:title="@string/wpref_Connection_Screen_title"
        android:summary="@string/wpref_Connection_Screen_summary"
        android:shouldDisableView="true">

    <com.test.app.CustomSelectAppPreference android:key="userSelectedApplication"
            android:title="@string/wpref_userSelectedApplication_title"
            android:summary="@string/wpref_userSelectedApplication_summary"
            android:dialogTitle="@string/userselectedApplication_dialogTitle"
            android:entries="@array/selectedapps_dummy_actions"
            android:entryValues="@array/selectedapps_dummy_actionsvalues"           
            android:defaultValue=""
            android:shouldDisableView="true"/>
</PreferenceScreen>

通过使用这种方法,我可以在不违反Android有关首选项的规则的情况下控制用户在此活动中所做的一切。

希望这可以帮到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接