List reading empty when inside doInBackground of AsyncTask - java

I am trying to read a list of integers inside of the doInBackground of AsyncTask. When I pass the list into the constructor of AsyncTask, it is full. But, by the time I get to the doInBackground function, it is empty. Any ideas?
public class floatingActionButtonClickListener implements View.OnClickListener{
#Override
public void onClick(View v) {
if(mAdapter.getDeleteModeStatus()){
// Delete items from database
ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
new DeleteDatabase().execute(IDsToDelete);
// Turn FAB back to regular button
mFAB.setImageResource(R.drawable.baseline_add_white_48); // Turn FAB to delete button
// Disable delete mode
mAdapter.exitDeleteMode();
// Load database
new LoadDatabase().execute();
}
else{
Intent intent = new Intent(getBaseContext(), AcitivtyJournal.class);
int journalType = Constants.JOURNALTYPE_FULL;
intent.putExtra(Constants.JOURNAL_TYPE, journalType);
startActivity(intent);
}
}
}
private class DeleteDatabase extends AsyncTask <ArrayList<Integer>, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressBarHolder.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(ArrayList<Integer>... arrayLists) {
ArrayList<Integer> IDsToDelete = arrayLists[0];
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "JournalEntries")
.build();
for(Integer idToDelete : IDsToDelete){
db.mJournalEntriesDao().deleteCompleteJournalEntry(idToDelete);
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
mProgressBarHolder.setVisibility(View.GONE);
}
}
}

This is not how you use and AsyncTask. You need to declare the parameters and then recieve them in the callback.
Please also note that you are trying to access the same data(IDsToDelete) from two threads(Main and Background), in your way, without proper syncronization.
private class DeleteDatabase extends AsyncTask<ArrayList<Integer>, Void, Void> {
#Override
protected Void doInBackground(ArrayList<Integer>... arrayLists) {
ArrayList<Integer> params = arrayLists[0];
// Do what you need
}
}
ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
new DeleteDatabase().execute(IDsToDelete);
When you have multithreading you need to look for two things:
atomic execution of operations
memory visibility.
There is a shared memory and every CPU caches the data. When you create something from one thread you can't just expect that the second thread will just read it. In your case you are creating the AsyncTask and inject the params from one thread, but then you read them in doInBackground from another. In general when you go through a synchronized block or hit a volatile variable(I say in general, because I also don't fully understand how JVM works), the thread flushes it's cache to the main memory and then reads also from it. This is how the data is shared. That is why it is better to use the framework way, because the frame will take care of proper publication of your data between threads. You are ok with immutable data, but a List is not such thing. And even if you declare the reference as immutable, you might see the right object from both threads, but the data they are holding might be old.
Just to be clear. I am not saying that the previous way was not working. I am saying that it is on good will. You can't just share data betweeb threads and hope it works.

Figured it out. Posting for people in the future who may have similar questions.
Embarrasingly enough, the ArrayList<Integer> was coming empty because I was deleting it in the function mAdapter.exitDeleteMode(); after I call AsyncTask().execute().
I was not aware that when I send the list to the AsyncTask it was the exact address of the list and not just a new list (that is, until I posted the comment above, and then it clicked). I think I got that train of thinking from C++ or another language. I don't remember which.
Solution: The solution I came up with is to just move mAdapter.exitDeleteMode() into of onPostExecute()instead of having it in the onClick() method.
Another Potential Solution: I believe another solution that would work (but I did not test) would be to just insert a new ArrayList<Integer> () into the AsyncTask

Related

Best practices for start() and stop() in Android MVP?

I have some questions regarding the Presenter’s start(), stop() method. What would you normally put into these methods to prevent memory leaks or any potential problem.
For example, I have an Activity that host a VideoView. The videoPath passed to the Activity will be passed to the Presenter to a VideoUtility to trim the original video into a shorter one before getting passed back to the Activity to be played with the VideoView.
Here’s the confusion: I don’t know where is the appropriate place to call the trimVideo() method as it essentially only need to happen once (unlike in the Android Architect Blueprint, the task is updated with latest data, and thus it’s put in the onResume()).
Please see the code snippet below:
VideoEditorContract:
public interface VideoEditorContract {
interface View extends BaseView<Presenter> {
void playTrimVideo(String trimmedVideoPath);
}
interface Presenter extends BasePresenter {
}
}
VideoEditorActivityBase:
public class VideoEditorActivityBase extends AppCompatActivity implements VideoEditorContract.View {
private VideoEditorContract.Presenter mPresenter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_editor);
String videoPath = getIntent().getStringExtra(RequestCode.EXTRA_VIDEO_PATH);
mPresenter = new VideoEditorPresenter(videoPath, this);
}
#Override
public void onResume(){
super.onResume();
mPresenter.start();
}
#Override
public void playTrimVideo(String trimmedVideoPath) {
final VideoView vv = findViewById(R.id.act_video_editor_videoView);
vv.setVideoPath(trimmedVideoPath);
vv.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
vv.start();
}
});
}
#Override
public void setPresenter(VideoEditorContract.Presenter presenter) {
//do nothing as this activity has already init a presenter
}
}
VideoEditorPresenter:
public class VideoEditorPresenter implements VideoEditorContract.Presenter {
private final VideoEditorContract.View mVideoEditorView;
#NonNull
private String mVideoPath;
public VideoEditorPresenter(#NonNull String videoPath, #NonNull VideoEditorContract.View videoEditorView) {
mVideoPath = checkNotNull(videoPath);
mVideoEditorView = checkNotNull(videoEditorView, "videoEditorView cannot be null!");
mVideoEditorView.setPresenter(this);
//trimVideo(); //should I do it here since this task is only need to be done once
}
#Override
public void start() {
//trimVideo(); //I can do it here but then I need to introduce a control variable; not sure if this is the best practice
}
private void trimVideo() {
//trim video stuff
}
// Currently it doesn't have a stop() method. But if it have one,
// what should I put in it? Releasing and clean up the
// VideoUtility I suppose?
}
I got the answer from Francesco Cervone in Medium about this matter (his article is also an excellent resource on MVP, btw. Very well in tune with the Android Architect Blueprint). I leave the relevant bit here for future reader.
Hi, thank you.
Well, I think that the video should be trimmed in the Presenter#start(). Then, after the video has been trimmed, the presenter should call view.playTrimmedVideo(). You shouldn’t do anything in the presenter constructor.
I suppose the video “editing” is something expensive, so you should do that in a separate thread (using for example an async task). You need to implement the Presenter#stop() method because you have to cancel ongoing operations if there are any, unless you retain the presenter.
You said that the trimVideo should be called just once. You could cache/persist in some way the result of trimVideo so that if the video has been already trimmed, you use it.
I hope I answered your question.
"Could you elaborate more on why shouldn’t we put anything in the Presenter’s constructor? I’ve seen the Presenter’s bare minimal constructor in a couple of places but I don’t understand the reason behind it."
First, it’s a responsibility problem: you are going to create an instance of Presenter, and I don’t think that the video editing is something that belongs to the construction of that object.
Second, you don’t know when the presenter is being instantiated, so you shouldn’t execute expensive tasks in the constructor. If you use some dependency injection framework, the construction of the Presenter would be managed by the framework itself and it needs to be efficient. The construction of other objects could depend on the presenter one.

Activity collides with AsyncTask? How to implement AsyncTask into GUI?

I am sorry for my bad english skills. I'm new to programming/stackoverflow and try to create a little android quiz app. This app has to connect to a php server and login/getquestion...
The simplest example is the login. The user has to type in his data and then i have to connect.
To provide that the Gui doesnt freeze i have to use asynchronous tasks.
Here the activity's code:
public void login(final String username, final String password) {
final Activity a = this;
FutureTask t = new FutureTask(new Callable() {
public Object call() {
Connection.GetInstance(a).login(username,password);
afterLoginTry(username,password);
return null;
}
});
t.run();
}
This calls a method in another class, which calls another FutureTask which calls an AsyncTask. At the end there is always an public synchronized method such as afterlogintry(). This works but it's a bit slow and i think dirty code.
My main problem is that i don't know how to give results back through different layers of classes and especially to the activity without using hotfixes all the time.
Is there any good explanation or tutorial, which describes how to design such a construct?
Thx for help
The way you can pass AsyncTask results back to other classes, is by declaring callbacks for the task, that will then report the result to a listener. Here is how it works.
First, you must declare an interface in your AsyncTask which contains a method that will send out the result of the task. So in my example task below, my result is a String. The String gets passed to onPostExecute() when the task finishes its work. I then call my callback method on a registered listener, and pass that return value on to whoever is listening for it. You register a listener by passing in an instance of your callbacks from whichever class is creating the task.
public class MyTask extends AsyncTask<String, Void, String> {
MyTaskCallback listener;
public MyTask(MyTaskCallback listener) {
this.listener = listener;
}
protected String doInBackground(String... params) {
String input = params[0];
//do work
input += "did some work on this String";
return input;
}
//When the thread finishes its work, this gets
//called on the main UI thread
protected void onPostExecute(String result) {
listener.onResultReceived(result);
}
public interface MyTaskCallback {
void onResultReceived(String result);
}
}
So next we need to register a listener for these callbacks, so when the result comes in from the task, it will get reported directly to our class. So let's say we have a simple Activity. The way we register the callbacks is to use the implements keyword on our class declaration, and then to actually implement the callback method in the class itself. We then create our task, and we pass in this which is our Activity that implements the callbacks. A simple example Activity that does this looks like this:
public class TaskActivity extends AppCompatActivity implements MyTask.MyTaskCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
//we pass in "this" because our Activity itself
//implements the callbacks below.
MyTask myTask = new MyTask(this);
myTask.execute();
}
//Here we implement our callback method, so the task
//can send its results straight through here
public void onResultReceived(String theResult) {
Log.d("TASK RESULT", "Here is our result String: "+theResult);
}
}
Now, our task has our Activity connected to it, through the callbacks we passed into it. So now when our task gets a result, we can send it directly to our listener, which is our Activity, and the result will come right through to our implemented onResultReceived method.
Callbacks are a great way to pass information around between classes while also keeping everything very separated. Hope this helps!

Best way to execute HTTP GET in onCreate()

I'm coding an Android client that connects to a REST API. Since Android 3.0 it is not allowed to perform blocking network operations on the main thread, so I'm looking for the best way to implement this.
I have managed my objective using AsyncTask but it seems a rather dirty implementation so I'd like to ask for advice.
The data returned from the async task is used to update the UI.
MainActivity.java:
public class MainActivity extends ActionBarActivity{
ListView establishment_list;
CustomListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
establishment_list = (ListView) findViewById(R.id.establishment_list);
adapter = new CustomListAdapter( this, R.layout.establishment_row_layout, new String[]{"Loading data..."} );
establishment_list.setAdapter(adapter);
View header = (View) getLayoutInflater().inflate(R.layout.establishment_headerview, null);
establishment_list.addHeaderView(header);
// GET establishments from REST API
new NonBloquingGET().execute();
}
/* DIRTY IMPLEMENTATION */
private class NonBloquingGET extends AsyncTask<List<Establishment>, Void, List<Establishment>> {
List<Establishment> establishments;
#Override
protected List<Establishment> doInBackground(List<Establishment>... params) {
/* This is a synchronous call using the Retrofit library*/
establishments = Client.getInstance().getEstablishments();
return establishments;
}
#Override
protected void onPostExecute(List<Establishment> result) {
Log.d("ASYNC TASK", result.toString());
List<String> data = new ArrayList<>();
for (Establishment e : result){
data.add(e.getName());
}
adapter.updateDataSet( data.toArray(new String[data.size()]) );
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
}
Is there a better way to do it as I'm planning to add more Activities and adding an AsyncTask class for each seems awkward?
The first thing you can start with is to make your inner AsyncTask class implementation static, otherwise it will hold an implicit reference to the host class (Activity), this means it won't be garbage collected until task is alive (let's imagine execution of NonBloquingGET takes a lot of time (you are sitting with dial-up speed somewhere on a desert island) and you rotate the screen, activities will be kept in memory). The second step you can think of is to implement a pair of IntentService and BroadcastReceiver. After you understand the key concepts behind it, you can take a look on 3rd party libraries, for example Retrofit for network communications, RxJava for events and Otto for event bus.
Using AsyncTask is actually a good thing as the execution of that is not synchronized with the main activity and so when you want to do some background work and need the main UI to be active at the same time always use AsyncTask.
The drawback of doing network operations on the main thread is that it'll make the UI unresponsive for the time being which will look too laggy and is not a good habit.
static {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
With this code you can use network operations on your main thread.

Why is my counter being reset each time after call toOncreate?

this is my current code
public class ButtonActivity extends Activity {
int count = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
button.setText("Got Pressed:" + ++count);
}
});
}
}
My question why after each call of onDestroy() and the subsequent call of onCreate(), the count gets reset. I looked up on onDestroy() and saw "that is there to let your app have a final chance to clean things up before the activity does get destroyed but it does not mean that the activity will be called" My initial idea was that count is an instance variable and that onCreate() creates a new instance of my class ButtonActivity. Can anyone confirm or refute my intial thoughts ?
If you don't want it reset - make it static: currently the counter is per object
Making count static will solve your problem. (because static member don't belong to a particular instance)
But to be more precise : onCreate don't create a new instance of your activity. In fact : Android-OS create a new instance and give you a chance to initialize it by calling onCreate(...).
And, more generally : you can be sure that onCreate() will never be called twice on the same instance: if you see that onCreate() is called it's because Android-OS has just created a new instance of your Activity (it can be done for many reason, like screen rotation, ...).
More about activity lifecycle here (probably one of the most important concept to understand when you do Android development !)
Storing static data in your activity class, as was suggested here, is a bad practice
and should be avoided.
Why?
Because Android may destroy background activities TOGETHER with their static data
whenever it feels resources are running low. Thus you may declare static fields inside you activity, but you will not get the static behavior you aim for,
What can you do instead:
Option 1:
Create a custom Application class and place your static data there. You will
not even have to declare it as static since Application obj is a singleton and is
guaranteed to stay in memory for as long the the app is alive.
public class MyApplication extends Application {
private DataClass mydata;
// probably with a getter & setter
}
Remember to declare your activity in the manifest:
<application
android:name="mypackage.MyApplication" <--------
.....
Option 2: Serialize your data to shared preferences. This is what they are for.

How can I tell if my context is still valid?

I'm working with a fairly common situation right now - download some data over the web, then update a view to display it. Clearly, I want to do the web download in the background, and then update the view on the main UI thread. Now looking at my code, I'm a little worried about my Activity and its UI elements being killed off before I update them. Here's the essence of what I have in mind:
Thread update = new Thread() {
public void run() {
final Data newData = requestData();
if (newData != null) {
post(new Runnable() {
public void run() {
Toast.makeText(MyClass.this, "I'll do things here that depend on my context and views being valid", Toast.LENGTH_SHORT).show();
}
});
}
}
};
update.start();
It seems possible that while I'm downloading data, the activity may be destroyed. What happens then? Will my thread continue to execute? Will I end up trying to access dead objects?
Usually I do this by AsycTask, but the work seemed simple enough this time to just inline the threads-launching-threads stuff. Will I make things any better by using an AsyncTask instead?
If your Context is an Activity, you can check if it is finishing or has finished with the isFinishing() method:
if ( context instanceof Activity ) {
Activity activity = (Activity)context;
if ( activity.isFinishing() ) {
return;
}
}
Toast.makeText(context, "I'll do things here that depend on my context and views being valid", Toast.LENGTH_SHORT).show();
What you really want to use is an AsyncTaskLoader. These are my new favorite classes in the Android API. I use them all the time and they were made to solve problems just like this. You won't have to worry about when to stop your download or anything like that. All the threading logic is taken care of for you, including telling the thread to stop if the activity has been closed. Just say what it is you want to do in the loadInBackground() method. Note that if you are developing for an API lower than 3.0, you can still access all the loaders via the Android Support Package.
If you use anonymous classes, they will have an internal reference to the outer class, so it's not like it becomes inaccessible all of a sudden because other references have been cleared. AsyncTask actually doesn't change anything, it uses similar mechanics for notifying about results.
You can use loaders, they are designed to be in sync with the activity lifecycle. They are available only since Android 3.0, but you can use support package to work with them on any device with 1.6 or later.
There is even a simpler solution, you can just use a boolean field which indicates whether activity has gone away. You should set this field in onPause() (or whenever you think you won't need the notifications anymore) and check for it when you show toast. You won't even have to use synchronization, since this field is confined to the main thread, so it's absolutely safe. By the way, if you change this field somewhere else than in onDestroy(), don't forget to add a statement which resets your field back in the counterpart method.
public class MyActivity extends Activity {
private boolean activityDestroyed = false;
#Override
protected void onDestroy() {
activityDestroyed = true;
}
private void updateData() {
new Thread() {
#Override
public void run() {
final Data newData = requestData();
if (newData == null) return;
runOnUiThread(new Runnable() {
public void run() {
if (activityDestroyed) return;
Toast.makeText(MyActivity.this, "Blah",
Toast.LENGTH_SHORT).show();
}
});
}
}.start();
}
}
I usually use Weak Reference to avoid leaking context in views
Weak Reference for Context
private var mContext: WeakReference<Context?>? = null
Assign Context
mContext = WeakReference(appContext)
Get Context
mContext .get()
Validate Context
if (mContext?.get() is Activity &&
(mContext?.get() as Activity).isFinishing){
return
}
Kurtis is right. However, if you REALLY want to keep it simple, you can try this:
class MyActivity extends Activity {
static MyActivity context;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
MyActivity.context = this;
}
#Override
public void onDestroy() {
super.onDestroy();
MyActivity.context = null;
}
}
And then you just use MyActivity.context in your class (and check for null there). If you want the toast to not even show up when your app is in the background, use onPause/onResume instead.
Again, this is the quick and lazy approach. AsyncTask or AsyncTaskLoader is how you should be doing things.

Categories