How to inject an anonymous inner class with dagger? - java

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!";
}
}

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.

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!";
}
}

Related

Update UI element from non-activity class

I have an Activity which creates a class that does some work. What is the typical Android method of having this class report back to the Activity in order to update the UI?
My activity, which creates the class:
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyClass obj = new MyClass(this);
obj.DoWork();
}
}
The class that does the work, and wants to report back some
public class MyClass(Context context) {
private Context context;
public void DoWork() {
//Do some work with a countdown timer
//Report back some values
}
}
You can create your own interface like this:
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyClass obj = new MyClass(this);
obj.setOnWorkDoneListener(new MyClass.OnWorkDoneListener(){
#Override
public void onDone(Values values) {
//Work done, use values
updateUI(values);
}
});
obj.DoWork();
}
}
public class MyClass(Context context) {
private Context context;
public interface OnWorkDoneListener{
void onDone(Values values);
}
private OnWorkDoneListener listener;
public void setOnWorkDoneListener(OnWorkDoneListener listener){
this.listener = listener;
}
public void DoWork() {
//Do some work with a countdown timer
when(workEnded) listener.onDone(backValues);
}
}

How to reuse the code Intent intent=new Intent(context,Activity.class) from a superclass to a subclass?

How the code Intent intent=new Intent(context,Activity.class) which is in the superclass can be reused by its subclasses given that the subclasses have different context and different activities to start after on click listener is called. Is it possible?
This is the superclass:
public class CommonPost extends AppCompatActivity {
public void on_create(final Context context, final Class aclass) {
post.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CommonPost commonPost = new CommonPost();
MyTask task = commonPost.new MyTask(context, aclass);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
task.execute();
}
});
}
class MyTask extends AsyncTask<Void,Void,Void> {
Context context;
Class aclass;
public MyTask(Context context,Class aclass){
this.context=context;
this.aclass=aclass;
}
#Override
protected void onPreExecute() {
// do something
}
#Override
protected Void doInBackground(Void... voids) {
// do something
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
Intent intent = new Intent(context, aclass);
startActivity(intent);
}
}
One of the subclass:
public class PlacementPost extends CommonPost {
Context context=PlacementPost.this;
Class aclass=Placements.class;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
on_create(context,aclass);
}
}
I am getting the following error when I try the above code:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.ActivityThread$ApplicationThread android.app.ActivityThread.getApplicationThread()' on a null object reference
at android.app.Activity.startActivityForResult(Activity.java:4266)
at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:50)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:79)
at android.app.Activity.startActivityForResult(Activity.java:4224)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:859)
at android.app.Activity.startActivity(Activity.java:4548)
at android.app.Activity.startActivity(Activity.java:4516)
at studentapp.notefi.CommonPost$PlaceTask.onPostExecute(CommonPost.java:240)
at studentapp.notefi.CommonPost$PlaceTask.onPostExecute(CommonPost.java:177)
at android.os.AsyncTask.finish(AsyncTask.java:660)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:677)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
I am not sure where I am wrong or what I am missing. I just tried out whatever logically I felt correct. Please do correct me out where I am wrong!
for the starters you should never initialize your Activity using new, it has it's own life cycle and context should be of the class where you are actually starting intent, change you code to
on_create
public void on_create(final Context context, final Class aclass) {
post.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MyTask task = new MyTask(stor_root, mProgress, editTextplace, post, ninfo, imageUri,
mstorage, mDatabase, context, aclass);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
task.execute();
}
});
}
MyTask - Stop passing context from child
class MyTask extends AsyncTask<Void,Void,Void> {
Class aclass;
public MyTask(Class aclass){
this.aclass=aclass;
}
#Override
protected void onPreExecute() {
// do something
}
#Override
protected Void doInBackground(Void... voids) {
// do something
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
Intent intent = new Intent(CommonPost.this, aclass);
startActivity(intent);
}
}
SubClass
public class PlacementPost extends CommonPost {
Context context=PlacementPost.this;
Class aclass=Placements.class;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
on_create(aclass);
}
}
You need to make the variable a class scope not an inner class scope.
This is an inner class scope variables:
public class CommonPost extends AppCompatActivity {
...
class MyTask extends AsyncTask<Void,Void,Void> {
Context context;
Class aclass;
...
}
}
You can't access the Context context and Class aclass; from the child class.
You need to make it a class scope:
public class CommonPost extends AppCompatActivity {
// set to protected to only allow child class access.
protected Context context;
protected Class aclass;
...
class MyTask extends AsyncTask<Void,Void,Void> {
}
}
Then, in your child class, change the variables to:
public class PlacementPost extends CommonPost {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set the value to the base class.
context = PlacementPost.this;
aclass = Placements.class;
on_create(context,aclass);
}
}

Error in implementation of interface between activity and view

I'm trying to get in my MyActivity an int from a View MyView. In my activity I have the following:
public class MyActivity extends AppCompatActivity implements MyView.GetCallBack {
final MyActivity context = this;
private AsyncTask<Void, Void, Void> task;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_act);
task = new myTask();
task.execute();
}
#Override
public void onPercentageReceived(int msg){
// you have got your msg here.
}
public class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
}
#Override
protected void onPostExecute(Void result) {
LinearLayout surface = (LinearLayout) findViewById(R.id.surfaceView);
surface.addView(new MyView(getApplicationContext()));
surface.setBackgroundColor(Color.BLACK);
}
}
Now MyView contains the following code:
public class MyView extends View {
final MyView context = this;
private GetCallBack callback;
// Constructor
public PlacingBoxView(Context context) {
super(context);
callback = (GetCallBack) context;
}
#Override
protected void onDraw(Canvas canvas) {
dataPercentage(Percentage);
}
public void dataPercentage(int Percentage){
callback.onPercentageReceived(Percentage);
}
public interface GetCallBack{
void onPercentageReceived(int msg);
}
I can compile the code without problems, but in the LogCat I get the following mistake:
FATAL EXCEPTION: main
Process: com.example.ex, PID: 8035
java.lang.ClassCastException: android.app.Application cannot be cast
to com.example.ex.myView$GetCallBack
at com.example.ex.myView.(myView.java:49)
I know the error is related with the Context, but I still haven't found out a way to correct it,
Any idea will be really appreciated! :)
You have implemented the interface in myActivity but you are passing application context. That's why you are getting ClassCastException. Pass myActivity.this, so try like this:
surface.addView(new MyView(MyActivity.this);

Send string variable from Activity to AsyncTask Class

I need to send a string variable from my main activity class to the AsyncTask Class and use that string as part of the url to make the api call.
I tried using Intent and share preferences but neither can seem to be accessed in the AsyncTask Class. Can I use Singleton pattern, and if yes, how would I go about it?
If you declare a global variable:
public class MainActivity extends Activity {
private String url = "http://url.com";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new DownloadFilesTask().execute();
}
private class DownloadFilesTask extends AsyncTask<Void, Void, Void> {
protected Long doInBackground(Void... params) {
// You can use your 'url' variable here
return null;
}
protected void onProgressUpdate(Void... result) {
return null;
}
protected void onPostExecute(Void result) {
}
}
}
if you work in seperate classes:
new MyAsyncTask("Your_String").execute();
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
public MyAsyncTask(String url) {
super();
// do stuff
}
// doInBackground()
}

Using ProgressDialog in AsyncTack being called from class extending Application

I extended to Application class with my own data class. It is used to store global objects in my app and make them accessible by all Acitivites. I would like this class, when initialized on application run, to download data from the internet via AsyncTask. How can I show/hide a ProgressDialog within AsyncTask, which requires me to pass the correct Context/Activity to it?
public class DataSource extends Application{
private int userid;
private Object[] orders;
//initialize
#Override
public void onCreate() {
// Pull data from the internet and store it in orders
super.onCreate();
}
public void beginDataLoad(Activity callingActivity) {
// HOW DO I PASS THE CORRECT ACTIVITY TO MY NEW downloadData OBJECT?
downloadData task = new downloadData(callingActivity);
task.execute(new String[] { "http://www.myurl.com" });
}
private class downloadData extends AsyncTask<String, Void, String>{
private ProgressDialog progressDialog;
private MainActivity activity;
public downloadData(MainActivity activity) {
this.activity = activity;
this.progressDialog = new ProgressDialog(activity);
}
protected void onPreExecute() {
progressDialog.setMessage("Downloading events...");
progressDialog.show();
}
protected String doInBackgroun(String... params) {
// Do AsyncTask download functions in background...
}
protected void onPostExecute() {
progressDialog.dismiss();
//Callback function in MainActivity to indicate data is loaded
activity.dataIsLoaded();
}
}
}
I ended up calling the datasource load from my MainActivity this way.
public class MainActivity extends Activity {
//onclick function...
myDataSource = (DataSource)getApplicationContext();
myDataSource.beginDataLoad(MainActivity.this);
//Callback for AsyncTask to call when its completed
public void dataIsLoaded() {
//Do stuff once data has been loaded
}
}

Categories