Calling method from another class in onPostExecute causing nullPointerException - java

This might help someone also: How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?
I am calling method from another class in onPostExecute().
I assume that onPostExecute() is called after doInBackground(String... params) and that is right, according to documentation and debugger.
Calling the method:
protected void onPostExecute(String result) {
CreateHangOut crtHO = new CreateHangOut();
crtHO.createHangOut(result);
}
Part of method called, causing NPE (first line of method):
public void createHangOut(String location) {
String city=autocompleteTV.getText().toString();
}
Autocomplete TextView(autocompleteTV) is initialized onCreate of the activity.
Here is how I call AsyncTask:
create.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new
HTTPRequest().execute((autocompleteTV.getText()).toString());
}
});
Method called onCreate (of activity from where button is clicked) :
private void initialize() {
gAPI= new GoogleAPIAutocomplete();
autocompleteTV = (AutoCompleteTextView)
findViewById(R.id.crtHOLocOptionsTV);
setUpAutocomplete();
create = (Button) findViewById(R.id.crtHOCreateBtn);
name =(EditText) findViewById(R.id.crtHONameET);
create.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new
HTTPRequest().execute((autocompleteTV.getText()).toString());
}
});
}

Because createHangOut method is in CreateHangOut Activity so no need to create new object for accessing method just call it using method name if class which extends AsyncTask class is inner class of CreateHangOut :
protected void onPostExecute(String result) {
CreateHangOut.this.createHangOut(result);
}

Related

Accessing data of destroyed activity means I have a memory leak?

I've created an interface which holds a reference to an interfaces instantiated from an activity.
This is the interface:
public interface Calback {
void fun();
}
This is the activity which instantiates the calback and binds it to asincktask.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView txt = findViewById(R.id.helloTxtv);
txt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Calback call = new Calback() {
#Override
public void fun() {
Log.d("tag","text of destroyed activity: "+((TextView)findViewById(R.id.helloTxtv)).getText());
}
};
Worker worker = new Worker(call);
worker.execute();
}
});
}
}
What's strange is that using that calback I can access textview even if the activity was destroyed.
This is the code from asyncktask:
public class Worker extends AsyncTask<Void, Void, Void> {
private final Calback call;
public Worker(Calback call) {
this.call = call;
}
#Override
protected Void doInBackground(Void... voids) {
try {
sleep(5000);
Log.d("tag","done");
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
call.fun();
}
}
To ensure that the activity it's destroyed I've just rotated the screen.(But I've got the same result after starting another activity and finish the current one)
And here is the log result.
PS: I've used Android Studio 3.0
If you are able to access the text of the TextView after the parent Activity has been destroyed, then you have a memory leak.
However, I'm not convinced that is what is going on here. I think it is more likely that either the activity has not been destroyed, or the activity's state was persistent and you are now looking at the state in the new (reincarnated) activity.
Why? Because, it seems that the callback is being called via an onClick listener for the text view. And that can only occur if the specific text view is still visible. It can't be visible if it is a component of a destroyed activity.

AsyncTask: doInBackground is not finishing

I'am trying to implement an AsyncTask in Android that will load all my data from the database. Therefore I used the onPreExecute method to start a ProgressDialog
public class DataLoader extends AsyncTask<Void, Void, Void> {
private LoginActivity activity;
private ProgressDialog nDialog;
public DataLoader (LoginActivity act){
this.activity = act;
nDialog = new ProgressDialog(activity);
}
protected void onPreExecute() {
System.out.print("Start AsyncTask");
nDialog.setMessage("Loading data..");
nDialog.setTitle("Starting the application");
nDialog.setIndeterminate(false);
nDialog.setCancelable(true);
nDialog.show();
}
#Override
protected Void doInBackground(Void ... params) {
System.out.println("Starting doInBackground");
loadDashboardData();
return null;
}
protected void onPostExecute() {
nDialog.dismiss();
Intent i = new Intent();
i.setClass(activity.getApplicationContext(), DashboardActivity.class);
activity.startActivity(i);
}
The I use the doInBackground method to load call a function to load the data. This method is called from an visible activity. The task is called with:
public class LoginActivity extends Activity {
public void onClick(View v) {
DataLoader dl = new DataLoader(this);
dl.execute();
}
}
And the code for the doInBackground is:
protected Void doInBackground(Void ... params) {
System.out.println("Starting doInBackground");
loadDashboardData();
return null;
}
Now the problem is that my doInBackground method will not finish. I tried to implement the loadDashboardData() call in the onPreExecute method. This will not show my dialog box but it will load the data correctly. In this case the UI Thread is not responding and will response after all the data has been loaded.
What can hinder the doInBackground method to execute correctly and load the data properly? The called method works (because I can call it and get the correct data). Also I'am not seeing the println in my run console.
In the frontend I can see the progressbar spinning, but in the backend I can see that no data is loaded.
Your problem is that you are overriding the wrong method name : )
It should be
#Override
protected void onPostExecute(Void result) {
// your code
}
as in your case the variable which doInBackground return is Void.
You can check the documentation about AsyncTask .

Android - How to pass interface to AsyncTask

I'm trying to figure out how to create an AsyncTask that runs my php API code in the background then alerts my MainActivity once it completes. I've been reading tutorials and trying things for hours now and I'm just frustrated at this point as I can't find anywhere that answers my question.
I create the AsyncTask and it runs successfully and I can log the returned information from my API in the onPostExecute but I cannot figure out how to alert the MainActivity that the task was completed. I do not know what to pass into the creation of the APICall. Every tutorial I read shows that the AsyncTask constructor takes the interface as an argument as shown in my code below, but how do you pass an interface as an argument?
MainActivity.java (implements OnTaskCompleted)
myButton4.setOnClickListener(new OnClickListener(){
public void onClick(View v){
APICall api = new APICall( ???What do I put here?? );
api.execute("users");
}});
....
#Override
public void onTaskCompleted() {
Log.v("Play","Main Activity ON Task completed!");
OnTaskCompleted.java
public interface OnTaskCompleted {
public void onTaskCompleted();
}
APICall.java (extends AsyncTask)
public APICall(OnTaskCompleted listener){
this.listener = listener;
}
....
protected void onPostExecute(JSONObject j)
{
listener.onTaskCompleted();
}
You should pass the reference of your listener to the APICall class:
APICall api = new APICall(MainActivity.this);
Simple you can use anonymous interface instance like this.
myButton4.setOnClickListener(new OnClickListener(){
public void onClick(View v){
APICall api = new APICall(new OnTaskCompleted() {
#Override
public void onTaskCompleted() {
}
});
api.execute("users");
}});
OR you can Implement interface at class level like this
public class MainActivity extends Activity implements MainActivity.OnTaskCompleted {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButton4.setOnClickListener(new OnClickListener(){
public void onClick(View v){
APICall api = new APICall(MainActivity.this);
api.execute("users");
}});
}
#Override
public void onTaskCompleted() {
// Do your code on task complete
}
}
APICall api = new APICall( ???What do I put here?? );
What do I put here??
The one that implements your listener in this case your MainActivity
APICall api = new APICall(MainActivity.this);

Passing string from class to main activity

I'm trying to pass something from one class to my MainActivity, but it doesn't seem to work, I don't understand why.
I have my GPS Tracker on another class (not the MainActivity) in order to reuse it.
When the location changes, I want my other class to call a method from within the MainActivity to update my UI.
I summarized my code like that :
My MAIN ACTIVITY :
public class MainActivity extends Activity implements OnClickListener {
TextView tv;
EditText et;
Button btun;
int arg0;
int stuff;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
et = (EditText) findViewById(R.id.et);
btun = (Button) findViewById(R.id.btun);
btun.setOnClickListener(this);
}
private void setter(int stuff) {
tv.setText(stuff);
}
public void setText(int _stuff) {
_stuff = stuff;
setter(_stuff);
}
#Override
public void onClick(View v) {
Getter get = new Getter();
get.getInfo(Integer.parseInt(et.getText().toString()));
}
The other Class :
public class Getter {
int _getString;
MainActivity main = new MainActivity();
public void getInfo(int getString) {
_getString = getString * 8;
main.setText(_getString);
}
}
I end up having a NullPointerException in my LogCat
at :
- tv.setText(stuff);
- setter(_stuff);
- main.setText(_getString);
- get.getInfo(Integer.parseInt(et.getText().toString()));
and I don't really know why, and above all, how to fix it.
I'll appreciate any help !
(PS : My GPS tracker thingy is working fine, it's just about invoking my setter() method.
Instantiaing an Object of MainActivity doesn't automatically call onCreate method but this method is called when you start an activity using Intent; And using the same intent you can pass extra values. For example:
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("key", value);
context.startActivity(intent);
and then in your main activity onCreate method:
String value = getIntent.getStringExtra("key");
Edit:
In your case why don't you change your void getInfo(int getString) to return a String value i.e.
public class Getter {
...
...
public String getInfo(int getString) {
_getString = getString * 8;
return Integer.toString(_getString);
}
}
and then in onClick event of MainActivity bind this returned text to TextView
It's maybe because the MainActivity's onCreate()-Method hasn't been called. Therefore the tv is still null causing the NullPointerException
One problem is here. main is an Activity, but it should be the MainActivity calling this object.
public class Getter {
int _getString;
MainActivity main = new MainActivity();
public void getInfo(int getString) {
_getString = getString * 8;
main.setText(_getString);
}
}
I cannot really make out what you are trying to achieve in the Getter class, but either:
1: Pass the Activity instance to the object
public class Getter {
int _getString;
MainActivity _main = null;
public Getter(MainActivity main) {
_main = main;
}
public void getInfo(int getString) {
_getString = getString * 8;
_main.setText(_getString);
}
}
#Override
public void onClick(View v) {
Getter get = new Getter(this);
get.getInfo(Integer.parseInt(et.getText().toString()));
}
or
2: set the text in the Activity and only get the value from the Getter (My choice)
public class Getter {
int _getString;
MainActivity main = new MainActivity();
public void getInfo(int getString) {
return getString * 8;
}
}
#Override
public void onClick(View v) {
Getter get = new Getter();
int info = get.getInfo(Integer.parseInt(et.getText().toString()));
setText(Integer.toString(info));
}
Use Application Class or create a separate Class and declare a static variable in it. Use getter & setter methods to get the value. To update the Textview in mainacivity from other class pass the texview reference variable from main activity and put null check condition in other class if textview is not null then update the value.

Enabling Buttons after doInBackground finishes

I would like to enable a few buttons from my main activity once the stuffs from doInBackground() is finished! Can someone please let me know how to do that?
I can't use findViewByID() for making he button visible from the AsyncTask class as it's not an activity class! :/
Do Like this...
Define a method which enables the Buttons.
Then on PostExecute() on AsyncTask, call that method
there is one callback onPostExecution(...) { } of AsynTask class use this method to UI stuff,for enable,disable button just write this way in onPostExcustion(...)
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
}
});
also make sure this method only available in activity class
thank you
Follow this way:
[1] Create your AsyncTask :
public class performBackgroundTask extends AsyncTask<Void, Void, Void> {
ProgressDialog Dialog = new ProgressDialog(HotUsers.this);
protected void onPreExecute() {
Dialog.setMessage("Loading Hot Users...");
Dialog.show();
}
protected void onPostExecute(Void unused) {
if(Dialog.isShowing())
Dialog.dismiss();
set_details_on_screen();
}
#Override
protected Void doInBackground(Void... params) {
get_details_from_server(); // get data like userid,username,userdesc etc...
return null;
}
}
[2] That will call function to proceed for UI changes.
public void set_details_on_screen()
{
if(userid > 0 )
handler_default.sendEmptyMessage(0);
else
handler_default.sendEmptyMessage(1);
}
[3] At last your UI changes will be reflected on screen with this Handler.
private Handler handler_default = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 0: {
textuserid = (TextView) findViewById(R.id.userid);
textusername = (TextView) findViewById(R.id.username);
textuserdesc = (TextView) findViewById(R.id.userdesc);
textuserid.setText(userid);
textusername.setText(username);
textuserdesc.setText(userdesc);
break;
}
case 1: {
Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show();
break;
}
}
}
};
Thanks.
your class which extends AsyncTask you can push your context into it, when calling the execute().
private class RegisterUser extends AsyncTask<String,String,String> {
private ListActivity activity;
public RegisterUser(ListActivity activity) {
this.activity = activity;
}
protected void onPostExecute(JSONObject json) {
activity.editText = (EditText)activity.findViewById(R.id.editText1);
//or
activity.enableButton();
}
}
and call the execute from the Activity like this:
new RegisterUser(this).execute(new String[] {"param"});
or you can define the AsyncTask class inside your Activity class - where you can reach everything.
more info Lars Vogel - Android Threads, Handlers and AsyncTask

Categories