【问题标题】:How to access dialog from background process?如何从后台进程访问对话框?
【发布时间】:2015-10-21 04:02:51
【问题描述】:

我有一个带有自定义适配器的ListView,它显示了我周围的 wifi 列表。单击一个项目时,我会显示一个包含详细信息的对话框。该对话框是从DialogFragment 派生的自定义类,并在 Wifi 扫描完成后使用此代码显示:

private class WifiScanReceiver extends BroadcastReceiver {
        public void onReceive(Context c, Intent intent) {
            List<ScanResult> wifiScanList = wifi.getScanResults();
            Log.i("WifiAnal", "rec");

            lv.setAdapter(new WifiListAdapter(getApplicationContext(), R.layout.itemlistrow, wifiScanList));
            lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    ScanResult listItem = (ScanResult)lv.getItemAtPosition(position);
                    WifiDetailsDialogFragment d = new WifiDetailsDialogFragment();

                    // Supply num input as an argument.
                    Bundle args = new Bundle();
                    args.putString("ssid", listItem.SSID);

                    d.setArguments(args);

                    d.show(getSupportFragmentManager(), "fir");

                    // TODO: PUT ASYNC CALL HERE AND PROCESS FETCHED DATA.
                    // TODO: SHOW ASYNC RESULT ON OPEN DIALOG

                }

            });

            mSwipeRefreshLayout.setRefreshing(false);
        }
    }

我的 WifiDetailsDialogFragment 类负责扩展其 xml 布局并使用 Ok 按钮将其正确显示在应用程序顶部。

现在想象一下我显示对话框,现在我想运行一个后台任务(比如从外部服务器上的数据库中获取更多详细信息),完成后,如果对话框仍然打开,则将结果放入其布局中(可能操纵一些已经存在和膨胀的 TextViews 的值)。如果到那时它已关闭,则什么也不做。

如何从 onItemClick 启动的后台运行进程访问我的布局小部件?我试过d.getView(),但这会返回null。以某种方式通过FragmentManager 是正确的方法吗?我不想绘制新的对话框,而是编辑现有的成员。

谢谢!

【问题讨论】:

  • 您无法从后台线程访问 UI 线程视图,一旦您从数据库或服务器调用 runOnUIThread 方法获取值,然后对对话框片段执行您想做的任何事情。跨度>
  • 如何从 runOnUIThread 中获取对对话框内的 TextView 的引用?布局从 onItemClick 内部膨胀
  • 我猜你需要通过弱引用将膨胀的内容传递给后台线程。

标签: android android-layout android-fragments android-dialogfragment android-dialog


【解决方案1】:

好吧,如果你只是想访问你的片段,你可以使用

getSupportFragmentManager().findFragmentByTag("fir")

必须在您的片段交易时定义此标签(在您的情况下为show(),因为它是DialogFragment

但我应该建议您在上面定义的代码看起来有点奇怪。您如何期望在那里获得异步调用的结果?如果你继续使用这样的代码,你会得到一个android.os.NetworkOnMainThreadException

为避免这种情况,您应该构建一个 AsyncTask 并在 onPostExecute 方法上操作您的 UI,您将返回主循环。

【讨论】:

  • 我使用 AsyncTask 进行调用,这就是我执行它的地方,它有自己的方法,包括 onPostExecute 方法,这就是我需要处理 TextView 的地方。那么这个解决方案在这些情况下会起作用吗?
  • getFragment 还需要 Bundle 作为第一个参数。我应该放什么?它为什么需要它,它是从头开始创建的吗?
  • 对不起,使用:findFragmentByTag
  • 我在d.show(getSupportFragmentManager(), "fir"); 之后添加了这段代码((WifiDetailsDialogFragment)getSupportFragmentManager().findFragmentByTag("fir")).updateUI();,我得到了nullPointerException,这意味着我没有通过这种方式得到正确的片段,而是得到了null……知道为什么吗?附言updateUI() 是在我的自定义片段中定义的一个函数,它负责必要的更改
【解决方案2】:

我建议您使用Otto 将事件从后台线程发送到 UI 逻辑。这些事件可能包含您需要的任何信息。您必须遵循的步骤是:

  • 在后台线程和对话框片段中注入总线(可能因依赖管理器解决方案而异)
  • register()你的片段到公共汽车
  • 创建一个接收事件的方法并用@Subscribe注解
  • post() 来自后台线程的事件(为此,您必须进入主循环器,但这可以通过修改 otto 总线轻松完成,如下面的代码)

    public class MainThreadBus extends Bus {
     private final Handler handler = new Handler(Looper.getMainLooper());
    
     @Override public void post(final Object event) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.post(event);
        } else {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    MainThreadBus.super.post(event);
                }
            });
        }
    }
    

此答案中建议使用此代码:How to send event from Service to Activity with Otto event bus?

以这种方式编写您的解决方案实际上会更安全,因为您可以在onPause 方法上unregister() 您的片段,因此您在操作其 UI 时不必检查片段是否仍附加到活动。

【讨论】:

  • 谢谢,但对于这么简单的事情似乎有点开销。我正在寻找没有 3rd 方组件的东西
猜你喜欢
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-15
  • 1970-01-01
相关资源
最近更新 更多