How to instantiate interface in fragment?

2019-05-26 08:06发布

In my Android application, I have a fragment activity which it has a progressbar. This progress bar set to visible when any fragment invoke the interface. Therefore, the code for fragment class is like this:

public class MainScreen extends FragmentActivity {

    public interface OnConnectingToInternet {
        public void showProgressbar(boolean flag);
    }

    // rest of codes
    .
    .
    .

    // Implementing Interface
    public void showProgressbar(boolean flag) {
        if(flag){
            myProgressbar.showProgressBar();
        } else {
            myProgressbar.hideProgressBar();
        }
    }

}

Each fragment should connect to Internet and get data, however before that they should invoke interface. I have written following code for one class (the code for other fragments is like this).

public class TopRecipesFragment extends Fragment {

    private OnConnectingToInternet onConnectingToInternet;


    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // onConnectingToInternet = (OnConnectingToInternet) activity;

        Log.i(TAG, "Fragment attached to activity.");
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        New MyAsyncTask.execute();
    }

    public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {       

        @Override
            protected void onPreExecute() {
            Log.i(TAG, "myAsyncTask is about to start...");

            onConnectingToInternet.showProgressbar(true);
            }

        @Override
            protected Boolean doInBackground(Void... params) {
            ...
            }

        @Override
            protected void onPostExecute(Boolean result) {
            Log.i(TAG, "myAsyncTask is about to start...");

            onConnectingToInternet.showProgressbar(false);
            }

} 

The problem is I don't know how to instantiate this interface. If I don't put onConnectingToInternet = (OnConnectingToInternet) activity;, then, after running application, it will crash in a NullPointerException.

But, if I instantiate like that, then application crashes because of casting problem. I cannot instantiate it in normal way either, like onConnectingToInternet = new MainScreen();.

What is the solution? Any suggestion would be appreciated. Thanks

2条回答
Anthone
2楼-- · 2019-05-26 08:27

The problem is that sometimes a Fragment lives longer than its Activity, for example, if the Activity has a config change (e.g. rotated) then the Activity is destroyed, but the Fragment can be kept alive and then reattached to the new (rotated) Activity. See this post: Android Fragment lifecycle over orientation changes

So you might have a problem with the proposed solution using the WeakReference, because after a rotation you would have a reference to the old Activity (or maybe nothing).

Though I’m not sure why the line crashed in onAttach(), that should have been ok.

What seems to work for me:

1) When I need a ref to the Activity, call getActivity(). Do this right in onPostExecute().

2) Check the result for null (this can happen: Fragments can live longer than their Activities)

3) Check if activity isFinishing() – you don’t want to do certain UI things in that state.

4) Cast activity to your interface type.

5) Call showProgressBar().

查看更多
forever°为你锁心
3楼-- · 2019-05-26 08:40

I would write that You're trying to do the following way:

OnConnectingToInternet.java:

public interface OnConnectingToInternet {
        public void showProgressbar(boolean flag);
    }

MainScreen.java:

public class MainScreen extends FragmentActivity implements OnConnectingToInternet {


// rest of codes
.
.
.

// Implementing Interface
@Override
public void showProgressbar(boolean flag) {
    if(flag){
        myProgressbar.showProgressBar();
    } else {
        myProgressbar.hideProgressBar();
    }
}
}

TopRecipesFragment.java:

public class TopRecipesFragment extends Fragment {

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        Log.i(TAG, "Fragment attached to activity.");
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        new MyAsyncTask((OnConnectingToInternet)getActivity()).execute();
    }

    // Make class static to avoid memory leaks
    public static class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {

        // Keep WeakReference to the interface to avoid memory leaks
        private final WeakReference<OnConnectingToInternet> connectionRef;       

        MyAsyncTask(OnConnectingToInternet connection) {
            connectionRef = new WeakReference<OnConnectingToInternet>(connection);
        }

        @Override
        protected void onPreExecute() {
            Log.i(TAG, "myAsyncTask is about to start...");

            OnConnectingToInternet connection = connectionRef.get();

            if (null != connection) {
               connection.showProgressbar(true);
            }
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            ...
        }

        @Override
        protected void onPostExecute(Boolean result) {
            Log.i(TAG, "myAsyncTask is about to start...");

            OnConnectingToInternet connection = connectionRef.get();

            if (null != connection) {
               connection.showProgressbar(false);
            }
       }
} 
查看更多
登录 后发表回答