Using ProgressDialog in AsyncTack being called from class extending Application - java

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

Related

Unable to addReactInstanceEventListener to React InstanceManager

I am trying to use a fix from this GitHub issue, but when using the solution in my code, this is not available. How can I pass this to the function?
´´´java
public class MainActivity extends ReactActivity {
#Override
protected String getMainComponentName() {
return "fleeting";
}
private ReactContext mReactContext;
private PowerManager.WakeLock sCpuWakeLock;
private Activity activity;
private static final String TAG = "MainActivity";
public void onReactContextInitialized(ReactContext context) {
Log.d(TAG, "Here's your valid ReactContext");
mReactContext = context;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
getReactInstanceManager().addReactInstanceEventListener(this); // Throws error, can´t find "this"
Replace you first line with below code. You were not implemented the ReactInstanceEventListener interface.
public class MainActivity extends ReactActivity implements ReactInstanceManager.ReactInstanceEventListener{
Then add this method inside your mainActivity.
#Override
public void onReactContextInitialized(ReactContext context) {
Log.d(TAG, "Here's your valid ReactContext");
}

Constructor of worker it doen't called?

I try to implement a timer using Work Manager.
"Timer button was hit" is appear in logcat, but nothing comes from worker. What I do wrong?
This is my ViewModel class:
public class MainViewModel extends ViewModel {
public static final String LOG_TAG = "MainActivity";
private final WorkManager workManager;
public MainViewModel(WorkManager workManager) {
this.workManager = workManager;
}
public void count() {
Log.d(LOG_TAG, "Timer button was hit!");
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(MainWorker.class).build();
workManager.beginUniqueWork("count-work", ExistingWorkPolicy.APPEND, request).enqueue();
}
}
This is my worker. Nothing appear in logcat from here. I don't know why.
public class MainWorker extends Worker {
public MainWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
Log.d(MainViewModel.LOG_TAG, "Created");
}
#NonNull
#Override
public Result doWork() {
Log.d(MainViewModel.LOG_TAG, "Work start");
return Result.success();
}
}
This is my activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainViewModel viewModel = new MainViewModel(WorkManager.getInstance(this));
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setMainViewModel(viewModel);
}
}
ViewModels are not initialized the way you did. If you have to pass something to ViewModel constructor, you should probably consider using ViewModelProvider.Factory().
You can make your own ViewModelProvider.Factory()
Refer this, https://medium.com/koderlabs/viewmodel-with-viewmodelprovider-factory-the-creator-of-viewmodel-8fabfec1aa4f#:~:text=And%20it%20is%20because%20you,it%20will%20create%20your%20ViewModel.

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

java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View .MainActivity.findViewById(int)' on a null object reference

I have a class called MainActivity.java that call an AsyncTask class. The last class have a findViewById() that in execution return this error:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View <mypackage>.MainActivity.findViewById(int)' on a null object reference
I don't understand how can I edit an ImageView positioned in R.layout.activity_main after that an AsyncTask finish to work.
MainActivity.java
public class MainActivity extends Activity {
public MainActivity() {}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Connection().execute();
}
}
Connection.java
public class Connection extends AsyncTask<String, Void, String> {
public String result;
//I know, this isn't correct, how can i do?
public MainActivity MainActivity;
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
//...
return "a string";
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
//...
// Where the error is generated
ImageView image = (ImageView) MainActivity.findViewById(R.id.image);
//...
}
}
The error is that
public MainActivity MainActivity;
is never initialized, thus pointing to null.
To make your code work the minimum step is
in MainActivity
new Connection(this).execute();
In Connection
public class Connection extends AsyncTask<String, Void, String> {
public MainActivity MainActivity;
public Connection(MainActivity activity) {
MainActivity = activity;
}
But creating a task in onCreate and passing an Activity is not the best idea anyway.
Also, field names should always start with a lowercase letter.
The best way is passing an ImageView to the AsyncTask.
Don't start a task until the Activity is started and also, don't forget to cancel the task when the Activity is stopped.
public final class MainActivity extends Activity {
public MainActivity() {}
private Connection connection;
private ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.image);
}
#Override
protected void onStart() {
super.onStart();
if (connection == null || connection.getStatus() != AsyncTask.Status.RUNNING) {
connection = new Connection(imageView);
connection.execute();
}
}
#Override
protected void onStop() {
super.onStop();
if (connection != null && connection.getStatus() == AsyncTask.Status.RUNNING) {
connection.cancel(true);
}
}
}
In Connection.java, store an ImageView as a WeakReference to avoid leaks.
public final class Connection extends AsyncTask<String, Void, String> {
private final WeakReference<ImageView> imageViewRef;
public Connection(ImageView view) {
imageViewRef = new WeakReference<ImageView>(view);
}
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
//...
return "a string";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//...
final ImageView imageView = imageViewRef.get();
// if the Activity is still alive, the ImageView will not be null
if (imageView != null) {
// set an image or whatever you need
image.setImageResource(666);
}
}
put imageview as a variable of your class
private ImageView image;
on your onCreate initialize
image = (ImageView) findViewById(R.id.image);
public class Connection extends AsyncTask<String, Void, String> {
public String result;
//I know, this isn't correct, how can i do?
public MainActivity MainActivity;
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
//...
return "a string";
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
//...
// Where the error is generated
//do other stuff with your imageview
//...
}
}
You did not specify what parameter you pass to Connection.java AsyncTask.
One of my student is also having same problem.
Although he is using Volley Library for HttpConnection (posting data) and main issue was:
he is writing URL directly without the http protocol prefix i.e.
String post_url ="api/do_post";
Simply add http/https at front of your post url:
String post_url ="http://api/do_post";
actually i was working an activity and service application. same problem i also got,
in that in bindservice i have used the BIND_IMPORTANT flag instead of using BIND_AUTO_CREATE.
once i changed the flag it was worked successfully for me.

How to inject an anonymous inner class with dagger?

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

Categories