Android:阻止首选项的首选项对话框,必须通过网络加载

时间:2011-01-12 00:25:11

标签: android android-preferences

我的应用有一个ListPreference,其条目来自网络API。在我的PreferenceActivity的onCreate()中,我生成了一个后台线程,它进行API调用,然后在一两秒后填充ListPreference的条目。

如果用户在下载选项之前单击首选项屏幕上的ListPreference按钮,我想阻止显示首选项对话框,而是通知用户仍然正在加载选项列表。

我怀疑正确的方法是覆盖OnPreferenceClickListener,如下所示:

ListPreference dpref = (ListPreference) findPreference("debug");
String[] s = {"one", "two", "three"};
dpref.setEntries(s);
dpref.setEntryValues(s);
dpref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
    @Override
    public boolean onPreferenceClick(Preference preference) {
        Toast.makeText(this, "hi there", Toast.LENGTH_SHORT).show();
        return true;
    }
});

显示toast,但也会显示ListPreference选择器对话框。 OnPreferenceClickListener documentation表示如果处理了点击,onPreferenceClick应返回true,但返回false会产生相同的结果。

如何阻止首选项对话框显示?

是否有更好的方法来处理在查看之前必须下载选项的首选项?

7 个答案:

答案 0 :(得分:6)

我遇到了同样的问题,但是在一个更简单的环境中。我的PreferenceScreen在xml文件中定义。我想要处理一个偏好。所以我只是将一个“Preference”对象放入xml文件而不是“ListPreference”或“EditTextPreference”

    <Preference android:title="@string/preloadmaps1" android:summary="@string/preloadmaps2"
        android:key="preloadMaps" />

现在没有更多的编辑器与Preference相关联,我可以在“OnPreferenceClickListener”中自救地处理编辑

答案 1 :(得分:5)

引用android dveloper文档,其中包含showDialog

  

显示与此首选项关联的对话框。 通常会在点击首选项时自动启动。如果您需要在其他某个事件上显示对话框,请调用此方法。

因此,当点击偏好设置会自动调用showDialog()时,如果你想控制以防止在点击偏好设置上显示对话框,你需要实现一个自定义偏好设置,如下所示,

public class MyPreference extends ListPreference {
    private Context context;

    // a flag to control show dialog
    private boolean showDialog = false;

    public MyPreference(Context context) {
        super(context);
        this.context = context;
    }

    public MyPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;       
    }

    @Override
    protected void showDialog(Bundle state) {        
        if (showDialog) {
            // show dialog 
            super.showDialog(state);
        } else {
            // if you don't want to show a dialog when click preference
            return;
        } /* end of if */
    }
}

答案 2 :(得分:1)

我不确定为什么你的方式不起作用,但这是一个快速解决方案:

为每个应下载的首选项添加存根Preference。您可以以任何方式自定义单击操作。不会显示任何对话框。

当您的偏好设置选项准备就绪时,remove旧偏好(按名称)并使用您的选项创建新的ListPreference(与刚删除的名称相同)。

这将使您可以灵活地在任何需要的事件上添加任何类型的自定义首选项。虽然如您所见,但需要一些额外的编码。

答案 3 :(得分:1)

我知道这是一个老问题,但是如何取消这些对话仍然没有答案。 所以在这里你可以取消偏好对话框:

dpref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
    @Override
    public boolean onPreferenceClick(Preference preference) {
        ((ListPreference)preference).getDialog().dismiss();   <<< This will do it
        Toast.makeText(this, "hi there", Toast.LENGTH_SHORT).show();
        return true;
    }
});

但是,当从web加载选项列表时,不要忽略对话框,最好隐藏它以便以后能够显示它。所以:

dpref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
    @Override
    public boolean onPreferenceClick(Preference preference) {
        ((ListPreference)preference).getDialog().hide();   <<< This will just hide the dialog and you still can show it later
        Toast.makeText(this, "hi there", Toast.LENGTH_SHORT).show();
        return true;
    }
});

稍后,当加载选项列表时:

...
dpref.setEntries(<array_of_options_here>);
dpref.getdialog().show();  <<< If you dismiss the dialog earlier and not hide it, then getDialog() returns null here 
...

答案 4 :(得分:0)

我使用代理Activity(设置为对话框)来下载首选项并在完成后启动实际的PreferenceActivity

答案 5 :(得分:0)

您可以在偏好活动的onResume()中执行以下操作:

  • 开始async call到......
    • 将首选项设置为已禁用,并提示正在提取值
    • 网络获取值(无论是没有值还是总是) - 异步,因此它不会停止恢复
    • 使用提取的值更新首选项条目
    • 启用首选项并显示默认提示

缺点是,您的偏好要么经常更新(例如,总是在您的首选项屏幕启动时),但是这样您可以处理网络调用的结果产生列表的情况价值不再存在(例如,向用户显示一个对话框,表示他的选择不再可用)。

此外,这是一项复杂的任务(因为您必须定义Handler,因为异步执行存在于另一个线程中......)

它看起来像这样(假设你在PreferenceActivity中执行此操作)

import android.os.Handler;
import android.os.AsyncTask;
import android.os.Message;

public class xyz extends PreferenceActivity {
    ...
    // define a handler to update the preference state
    final Handler handler = new Handler() {
        public void handleMessage( Message msg ) {
            ListPreference dpref = (ListPreference) getPreferenceManager().findPreference("debug");
            dpref.setEnabled( msg.getData().getBoolean("enabled") );
            dpref.setSummary( msg.getData().getString("summary") );
        }
    };



    private class updatePref extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... arg) {

            Message msg = handler.obtainMessage();
            Bundle data = new Bundle();
            data.putBoolean("enabled", false ); // disable pref
            data.putString("summary", "Getting vals from network..." ); // set summary
            msg.setData( data );
            handler.sendMessage(msg); // send it do the main thread

            ListPreference dpref = (ListPreference) getPreferenceManager().findPreference("debug");


            String values[];
            // call network function and let it fill values[]

            // do things according to the returned values, 
            // eg check if there are any, check if the user has 
            // already selected one, display a message if the 
            // user has selected one before but the values do not
            // contain them anymore, ...

            // set the new values     
            dpref.setEntries(values);
            dpref.setEntryValues(values);

            data.putBoolean("enabled", true ); // enable pref
            data.putString("summary", "Please choose" ); // set summary
            msg.setData( data );
            handler.sendMessage(msg); // send it do the main thread

            return null;
        }
    }

    public void onResume() {
        ....
        new updatePref().execute();

    }

}

当然,您可以在任何地方拨打new updatePref().execute(),因此您也可以将其绑定到ButtononCreate()或其他人(不需要在onResume()中执行此操作)。

答案 6 :(得分:0)

收藏的另一种方式。我相信它只适用于android.support.v7.preference libraryPreferenceFragmentCompat(在我的情况下为27.1.1)。这是一个例子:

public class PrefsFragment extends PreferenceFragmentCompat implements PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {

    private static final int REQUEST_VIEW_PREFERENCE = 1;

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_VIEW_PREFERENCE && resultCode == Activity.RESULT_OK) {
            Preference preference = findPreference("preference_key");
            getPreferenceManager().showDialog(preference)
        }
    }

    @Override
    public Fragment getCallbackFragment() {
        this;
    }

    @Override
    public boolean onPreferenceDisplayDialog(PreferenceFragmentCompat caller, Preference pref) {
        if (pref.getKey().equals("preference_key")) {
            if (canBeOpened(pref)) {
                return false;
            } else {
                // show a fragment loading data with requestCode == REQUEST_VIEW_PREFERENCE
                ...
                return true;
            }
        }
    }

    private boolean canBeOpened(Preference pref) {
        // check whether a preference can be clicked
        ...
    }
}

如果我正确理解Preference.java的源代码,OnPreferenceClickListener返回true仅适用于基于意图的首选项,但如果要显示对话框则会被忽略。

在上面的示例中,OnPreferenceDisplayDialogCallback用于防止显示首选项对话框。从getCallbackFragment()返回实现此接口的片段非常重要。