0

I have a ListView with custom adapter and it shows list of wifis around me. When one item is clicked, I show a dialog with details. The dialog is a custom class derived from DialogFragment and is shown using this code after Wifi scan is complete:

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

My WifiDetailsDialogFragment class takes care of inflating its xml layout and displaying it correctly on top of app with Ok button.

Now imagine I show the dialog and now I want to run a background task (say fetch some more details from DB on external server) and after I am done, if dialog is still open put the result into its layout (likely manipulate values of some already existing and inflated TextViews). If it is closed by then, do nothing.

How can I access my layout widgets from a process running in background initiated by onItemClick? I tried d.getView() but this returns null. Is the correct way somehow through FragmentManager? I do not want to draw new dialog, rather edit existing one's members.

Thanks!

michnovka
  • 2,880
  • 3
  • 26
  • 58
  • you can't access UI thread views from your back ground thread, once you have values fetch from DB or from server call on runOnUIThread method then do what ever you want to do with you dialogfragment. – dex Oct 21 '15 at 04:12
  • how would I get reference to a TextView inside the dialog from within the runOnUIThread? The layout is inflated from within the onItemClick – michnovka Oct 21 '15 at 04:14
  • you need to pass that inflated to background thread via weak reference I guess. – dex Oct 21 '15 at 04:23

2 Answers2

0

Well, if you just want to access your fragment you could use

getSupportFragmentManager().findFragmentByTag("fir")

This tag has to be defined at the moment of your fragment transaction (in your case show() since it's a DialogFragment.

But I should advise that the code you defined above looks a little weird. How do you expect to have the result of your async call right there? If you continue with the code like this you will get an android.os.NetworkOnMainThreadException

To avoid that you should build an AsyncTask and manipulate your UI on the onPostExecute method, where you will be back to the main loop.

luis.mazoni
  • 1,084
  • 8
  • 13
  • I make the call using AsyncTask, this is just where I execute it, itll have its own methods including onPostExecute method and that is where I will need to address the TextView. So will this solution work under these circumstances? – michnovka Oct 21 '15 at 04:44
  • Also getFragment requires a `Bundle` as a first param. What should I put there? Why does it need it, does it create it from scratch? – michnovka Oct 21 '15 at 04:46
  • sorry, use: findFragmentByTag – luis.mazoni Oct 21 '15 at 04:52
  • I added this code `((WifiDetailsDialogFragment)getSupportFragmentManager().findFragmentByTag("fir")).updateUI();` right after `d.show(getSupportFragmentManager(), "fir");` and I get nullPointerException, meaning that I do not get the correct fragment this way, I get null instead... any idea why? P.S. `updateUI()` is a func defined in my custom fragment that takes care of the necessary change – michnovka Oct 21 '15 at 04:56
-1

I would advise you to use Otto to send events from your background thread to the UI logic. These events may contain whatever information you need. The steps you would have to follow are:

  • Inject your bus both in your background thread and the dialog fragment (may vary according to your dependency manager solution)
  • register() your fragment to the bus
  • Create a method that receives the event and annotate it with @Subscribe
  • post() the event from the background thread (to do so you will have to get to the main looper but that can be easily done by modifying otto bus like the code bellow)

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

This code was suggested in this answer: How to send event from Service to Activity with Otto event bus?

Writing your solution this way you will actually be safer since you can unregister() your fragment on the onPause method, therefore you won't have to check if the fragment is still attached to an activity when manipulating its UI.

Community
  • 1
  • 1
luis.mazoni
  • 1,084
  • 8
  • 13
  • Thanks but seems a bit overhead for such a simple thing. Im looking for sth without 3rd party components – michnovka Oct 21 '15 at 04:29