3

It's posible inject an anonymous class? I'm having the following error:

java.lang.IllegalArgumentException: No inject registered for members/com.acme.MyFragment$1. You must explicitly add it to the 'injects' option in one of your modules.

Example:

public class MyFragment extends Fragment {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        new MyTrask(getActivity()) {
            protected void onPostExecute(String result) {
                // Stuff
            }
        }.execute();
    }
}

public class MyTask extends AsyncTask<Void, Void, String> {

    @Inject
    UserApi userApi;

    public MyTask(Context context) {
        App.getInstance().inject(this);
    }

    @Override
    protected String doInBackground(Void... params) {
        return "Hello World!";
    }
}
Brais Gabin
  • 5,827
  • 6
  • 57
  • 92

2 Answers2

8

You should inject the AsyncTask into MyFragment rather than using "new MyTask(..)". The MyTask constructor should take an UserApi instance and a Context object which can be provided by the module with code akin to;

  /**
   * The application module.
   *
   * @param context The context.
   */
  public MyModule(final Context context) {
    this.context = context.getApplicationContext();
  }

  /**
   * Provides context.
   *
   * @return the application context.
   */
  @Provides @Singleton Context provideContext() {
    return context;
  }

Your fragment code should then look like;

public class MyFragment extends Fragment {
    @Inject Provider<MyTask> myTaskProvider;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        inject(this);
        myTaskProvider.get().execute();
    }
}

And your AsyncTask API should be;

@Inject 
public MyTask(Context context, UserApi userApi) { }

Notice I used a Provider for the injection of the AsyncTask. This is necessary to avoid exceptions akin to "You can only execute a task once" that you would get if you called execute against the same AsyncTask object more than once. You then register MyFragment under your module injects = { } annotation arguments.

BrantApps
  • 6,362
  • 2
  • 27
  • 60
  • 3
    This will work. You could also just inject the `UserApi` into the fragment and pass it into the constructor of `MyTask`. – Jake Wharton Jan 23 '14 at 07:02
  • OceanLife thanks for your answer but it doesn't allow me to use anonymous class. I guess it's not possible, is it? I'll try your solution and the @JakeWharton solution. – Brais Gabin Jan 23 '14 at 09:28
  • That warm feeling when Jake agrees. Yep, either will work. The reason why I made it a "named" class is just personal preference- I prefer to make all my dependencies explicit so I can mock them out when I unit test. (Although binding Testing Modules is an alternative mocking solution) Cheers. – BrantApps Jan 23 '14 at 11:15
  • Exactly what I was looking for. Surprisingly example like this is hard to find. – TheLibrarian Dec 19 '18 at 18:02
0

You can't inject into an anonymous class. But you can do inject into the Fragment and it will be visible for the anonymous class, the AsyncTask in this case.

public class MyFragment extends Fragment {

 @Inject
 UserApi userApi;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    App.getInstance().inject(this);

    new MyTrask() {
        protected void onPostExecute(String result) {
            // Stuff
        }
    }.execute();
  }
}

 public class MyTask extends AsyncTask<Void, Void, String> {

 @Override
 protected String doInBackground(Void... params) {
    userApi.callAnyMethod(); // use userApi here
    return "Hello World!";
 }
}
Alécio Carvalho
  • 13,481
  • 5
  • 68
  • 74