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);
Related
I have a video player app where I need to access the lifecycle of an abstract activity from another class in Android. In my abstract activity, I've tried using LifecycleRegistry, but this is getting me the lifecycle owner not the actually lifecycle of the abstract class. How can I access the lifecycle of an abstract activity from another class?
Here is my abstract activity:
abstract public class MainActivity extends AppCompatActivity {
private LifecycleRegistry lifecycleRegistry;
VideoPlayer videoPlayer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lifecycleRegistry = new LifecycleRegistry(this);
lifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
setContentView(R.layout.activity_main);
videoPlayer = new VideoPlayer();
playVideo();
}
public void playVideo(){
videoPlayer.init();
//calls function in VideoPlayer class
}
#Override
protected void onResume() {
super.onResume();
lifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED);
}
#Override
protected void onDestroy() {
super.onDestroy();
lifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
}
}
Here is the class where I need to get the lifecycle of my abstract MainActivity:
public class VideoPlayer {
public void init() {
playVideo();
}
public void playVideo() {
//async call happens here, I need getLifeCycle() from MainActivity
}
}
Don't know a know about the context of you feature, but you You can do smth
public class VideoPlayer {
private Lifecycle mLifecycle;
public VideoPlayer(Lifecycle lifecycle) {
mLifecycle = lifecycle;
}
public void init() {
playVideo();
}
public void playVideo() {
//you have mLifecycle now
}
}
In Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
videoPlayer = new VideoPlayer(getLifecycle());
}
I'm trying to execute AsyncTask from a fragment class (e.g MyFragment.java) from another Activity class (e.g MyActivity.java).
the fragment class MyFragment.java is updating UI on it's elements :
public class MyFragment extends Fragment {
private SwipeRefreshLayout myRefreshLayout;
private ArrayAdapter myListAdapter;
#Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
myListAdapter = new myCustomAdapter(getContext(), myDataArray);
myRefreshLayout = myView.findViewById(R.id.myRefreshLayout);
}
public class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// UI...
myRefreshLayout.setRefreshing(true);
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// UI...
myRefreshLayout.setRefreshing(false);
myListAdapter.notifyDataSetChanged();
}
#Override
protected Void doInBackground(Void... params) {
// code...
return null;
}
}
}
I'm trying to Execute AsyncTask from MyActivity.java
MyFragment myfragment = new MyFragment();
myfragment.new MyTask.execute();
The Application crashes at onPreExecute :
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.swiperefreshlayout.widget.SwipeRefreshLayout.setRefreshing(boolean)' on a null object reference.
I'm assuming this is because it couldn't access myRefreshLayout to perform setRefreshing(true) on it, because i'm running the task from another thread MyActivity.java
How can i execute the AsyncTask on the Fragment .. from the Activity and change the UI?
Thanks.
Idk if this would be a nice solution. But I think you can make MainActivity implements this custom interface. It'd be a callback that should be execute after the swipe action done.
public class MainActivity extends AppCompatActivity implements MyAsyncCallback {
....
....
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyFragment myfragment = new MyFragment();
myfragment.new MyTask(this).execute();
}
#Override
public void onPreExecute(Boolean isRefreshing) {
if(isRefreshing){
// UPDATE MAIN UI
}
}
#Override
public void onPostExecute(Boolean isRefreshing) {
if(isRefreshing){
// UPDATE MAIN UI
}
}
}
interface MyAsyncCallback {
void onPreExecute(Boolean isRefreshing);
void onPostExecute(Boolean isRefreshing);
}
in your fragment
public class MyTask extends AsyncTask<Void, Void, Void> {
WeakReference<MyAsyncCallback> myListener;
public MyTask(MyAsyncCallback listener){
this.myListener = listener
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// don't forget to return view
}
#Override
protected void onPreExecute() {
super.onPreExecute();
MyAsyncCallback myListener = this.myListener.get();
if (myListener != null) {
myListener.onPreExecute(true);
}
myRefreshLayout.setRefreshing(true);
}
//same for onPostExecute()
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);
}
}
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()
}
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!";
}
}