How do I get UI reference from AsyncTask in android - android

I am trying to learn MultiThreading in android although my code works fine when I print the data on Logcat window but my app crashes and gives me a null point exception whenever I try to update a component from the asynctask.
It gives me the following error
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.append(java.lang.CharSequence)' on a null object reference
at com.shivam.asynctasks.MainActivity.logm(MainActivity.java:41)
Line 41
textView.append(message + "\n");
My Code
public class MainActivity extends AppCompatActivity {
Button button ;
TextView textView;
String TAG = "MyTag";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.button);
textView=findViewById(R.id.TextView);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String TAG ="MyTag";
Log.d(TAG,"OnClick Thread Started");
MyTask mytask =new MyTask();
mytask.execute("Red","Black","Yellow","Blue","Orange");
}
});
}
public void logm(String message) {
Log.d(TAG, message);
textView.append(message + "\n");
}
}
class MyTask extends AsyncTask<String,String,String>{
#Override
protected String doInBackground(String... strings) {
String TAG = "MyTag";
for (String value :
strings) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "do in Background : "+value);
publishProgress(value);
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
MainActivity mainActivity =new MainActivity();
for (String color : values) {
mainActivity.logm(color);
}
}
}

You need to reference your activity not create new one. Here you can see.
import android.os.AsyncTask;
public class MainActivity extends AppCompatActivity {
Button button ;
TextView textView;
String TAG = "MyTag";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.button);
textView=findViewById(R.id.TextView);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String TAG ="MyTag";
Log.d(TAG,"OnClick Thread Started");
MyTask mytask =new MyTask(this);
mytask.execute("Red","Black","Yellow","Blue","Orange");
}
});
}
public void logm(String message) {
Log.d(TAG, message);
textView.append(message + "\n");
}
}
class MyTask extends AsyncTask<String,String,String> {
WeakReference<MainActivity> mainActivityRef;
public MyTask(MainActivity activity){
mainActivityRef = new WeakReference<MainActivity>(activity);
}
#Override
protected String doInBackground(String... strings) {
String TAG = "MyTag";
for (String value :
strings) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "do in Background : "+value);
publishProgress(value);
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
MainActivity mainActivity = mainActivityRef.get();
for (String color : values) {
mainActivity.logm(color);
}
}

You are getting the error because the you are creating the instance of the mainactivity class again inside the onProgressUpdate() method whose textView is not initiated. Thats why you are getting the null pointer exception as the textview field is not being initiated.
There is a simple solution to your problem. The onProgressUpdate() method runs on the main UI thread and you have the access to the textview variable inside the onProgressUpdate() method. so simply do the following:
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
MainActivity mainActivity =new MainActivity();
for (String color : values) {
textView.append(color + "\n");
}
}

Related

Static AsyncTask ProgressBar

Sorry if this seems a basic question. I've updated Android Studio and notice some memory leak warnings on my AsyncTasks saying I should make them static. I have made them static but can't seem to make anything like List, ProgressBar, ImageView work without getting the same memory leak warning. It seems I can't win no matter which way I try it. I guess my questions are:
Are AsyncTasks supposed to be static? The official documentation doesn't make it static but my IDE fires warnings saying they should.
If they are meant to be static, how can I start and stop a ProgressBar within the static AsyncTask.
EDIT
This still throws "This AsyncTask class should be static or leaks might occur"
private class DownloadCategoryTask extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
String url = Config.API_URL +
"/Index.aspx?" +
"type=3&" +
"site_id=" + SITE_ID;
String method = "GET";
String array_name = "categories";
Downloaded_category_array = Config.getJSONNew(url, method, array_name, context);
return "";
}
protected void onPostExecute(String result) {
if(isCancelled()){
return;
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
//Update your UI here
//showProgressBar();
}
});
Populate_category_list();
}
}
Try this solution which I found:
public class MainActivity extends AppCompatActivity {
private ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = findViewById(R.id.progress_bar);
}
public void startAsyncTask(View v) {
ExampleAsyncTask task = new ExampleAsyncTask(this);
task.execute(10);
}
private static class ExampleAsyncTask extends AsyncTask<Integer, Integer, String> {
private WeakReference<MainActivity> activityWeakReference;
ExampleAsyncTask(MainActivity activity) {
activityWeakReference = new WeakReference<MainActivity>(activity);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
MainActivity activity = activityWeakReference.get();
if (activity == null || activity.isFinishing()) {
return;
}
activity.progressBar.setVisibility(View.VISIBLE);
}
#Override
protected String doInBackground(Integer... integers) {
for (int i = 0; i < integers[0]; i++) {
publishProgress((i * 100) / integers[0]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Finished!";
}
}
}
Reference: here
No, No need to make AsyncTasks as static.
If non static methods are trying to modify static members then IDE throws warning to make it static.
If you want to update your UI from AsyncTask use 'runOnUiThread'.
runOnUiThread(new Runnable() {
#Override
public void run() {
//Update your UI here
showProgressBar();
}
});
Looks like you are using anonymous inner class.
Here is the solution,
private class LoadData extends AsyncTask<Void, Void, String> {
LoadData() {
}
#Override
protected String doInBackground(Void... params) {
return "task finished";
}
#Override
protected void onPostExecute(String result) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//Update your UI here
//showProgressBar();
}
});
}
}
//Execute your task
new LoadData().execute();

Single button multiple action

I am using a single button to do two task.
Watson Conversation.
Watson Text to Speech.
My code is executing only if my TextView has some Text name (string), but the Text to Speech is playing the last conversation response even though the new conversation response is updated at TextView display on my phone UI.. Continuation of this here Race condition with UI thread issue.
Also I found out, if I keep my TextView empty i get error this:
Code here:
private class ConversationTask extends AsyncTask<String, Void, String> {
String textResponse = new String();
#Override
protected String doInBackground(String... params) {
System.out.println("in doInBackground");
MessageRequest newMessage = new MessageRequest.Builder().inputText(params[0]).context(context).build();
// async
GLS_service.message("xxxxxxx", newMessage).enqueue(new ServiceCallback<MessageResponse>() {
#Override
public void onResponse(MessageResponse response) {
context = response.getContext();
textResponse = response.getText().get(0);
reply.setText(textResponse);
System.out.println(textResponse);
}
#Override
public void onFailure(Exception e) {
}
});
return textResponse;
}
}
//
private class WatsonTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(final String... textToSpeak) {
/* runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(" ");
}
});*/
TextToSpeech textToSpeech = initTextToSpeechService();
streamPlayer = new StreamPlayer();
streamPlayer.playStream(textToSpeech.synthesize(textToSpeak[0], Voice.EN_LISA).execute());
return "Text to Speech Done";
}
/*#Override protected void onPostExecute(String result) {
textView.setText("");
}*/
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Register the UI controls.
input = (EditText) findViewById(R.id.input);
send = (ImageButton) findViewById(R.id.send);
textView = (TextView) findViewById(R.id.textView);
reply = (TextView) findViewById(R.id.reply);
play = (ImageButton) findViewById(R.id.play);
new ConversationTask().execute("");
//Button function
send.setOnClickListener(action3);
}
//five actions on button click
public void action5() {
String textResponse = new String();
System.out.println("Text to Speech:" + reply.getText());
//textView.setText("");
WatsonTask task = new WatsonTask();
task.execute(String.valueOf(reply.getText()));
//new WatsonTask().execute(reply.getText().toString());
}
View.OnClickListener action3 = new View.OnClickListener() {
public void onClick(View v) {
//action here//
new ConversationTask().execute(input.getText().toString());
action5();
}
};
}
Please help.
Action 3
View.OnClickListener action3 = new View.OnClickListener() {
public void onClick(View v) {
//action here//
new ConversationTask().execute(input.getText().toString());
}
};
Action 5
public void action5(String replyString) {
WatsonTask task = new WatsonTask();
task.execute(replyString);
}
Conversation Task
private class ConversationTask extends AsyncTask<String, Void, String> {
String textResponse = new String();
#Override
protected String doInBackground(String... params) {
System.out.println("in doInBackground");
MessageRequest newMessage = new MessageRequest.Builder().inputText(params[0]).context(context).build();
// async
GLS_service.message("xxxxxxx", newMessage).enqueue(new ServiceCallback<MessageResponse>() {
#Override
public void onResponse(MessageResponse response) {
context = response.getContext();
textResponse = response.getText().get(0);
reply.setText(textResponse);
action5(textResponse);
}
#Override
public void onFailure(Exception e) {
}
});
return textResponse;
}
}
WatsonTask
private class WatsonTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(final String... textToSpeak) {
reply.setText(textToSpeak[0]);
TextToSpeech textToSpeech = initTextToSpeechService();
streamPlayer = new StreamPlayer();
streamPlayer.playStream(textToSpeech.synthesize(textToSpeak[0], Voice.EN_LISA).execute());
return textToSpeak[0];
}
}
And for the sake of completeness address to the comment by Marcin Jedynak
I think your program scenario will follow next sequences:
Enter text to conversation task.
Get conversation result from GLS_service.message().
Input the result from sequence 2, for make the voice.
So try to change your code like this.
// There is no need to return String. Just send result to TextToSpeech.
//private class ConversationTask extends AsyncTask<String, Void, String> {
private class ConversationTask extends AsyncTask<String, Void, Void> {
String textResponse = new String();
#Override
protected String doInBackground(String... params) {
System.out.println("in doInBackground");
MessageRequest newMessage = new MessageRequest.Builder().inputText(params[0]).context(context).build();
// async
GLS_service.message("xxxxxxx", newMessage).enqueue(new ServiceCallback<MessageResponse>() {
#Override
public void onResponse(MessageResponse response) {
context = response.getContext();
textResponse = response.getText().get(0);
reply.setText(textResponse);
System.out.println(textResponse);
action5(textResponse); // It is real result that you want.
}
#Override
public void onFailure(Exception e) {
}
});
//return textResponse; // Not necessary.
}
}
//
private class WatsonTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(final String... textToSpeak) {
/* runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(" ");
}
});*/
TextToSpeech textToSpeech = initTextToSpeechService();
streamPlayer = new StreamPlayer();
streamPlayer.playStream(textToSpeech.synthesize(textToSpeak[0], Voice.EN_LISA).execute());
return "Text to Speech Done";
}
/*#Override protected void onPostExecute(String result) {
textView.setText("");
}*/
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Register the UI controls.
input = (EditText) findViewById(R.id.input);
send = (ImageButton) findViewById(R.id.send);
textView = (TextView) findViewById(R.id.textView);
reply = (TextView) findViewById(R.id.reply);
play = (ImageButton) findViewById(R.id.play);
new ConversationTask().execute("");
//Button function
send.setOnClickListener(action3);
}
//five actions on button click
// Need a parameter to get String.
//public void action5() {
public void action5(String text) {
// String textResponse = new String(); // Replace to parameter as "text".
//System.out.println("Text to Speech:" + reply.getText());
System.out.println("Text to Speech:" + text);
//textView.setText("");
WatsonTask task = new WatsonTask();
//task.execute(String.valueOf(reply.getText()));
task.execute(text); // Replace to parameter as "text".
//new WatsonTask().execute(reply.getText().toString());
}
View.OnClickListener action3 = new View.OnClickListener() {
public void onClick(View v) {
//action here//
new ConversationTask().execute(input.getText().toString());
// action5(); // This invoking is not necessary at this point.
// Try to invoke this method after you get conversation result.
}
};
If it is not working even you changed, I want to know how you implement initTextToSpeechService() method.
Hope this helps you.

In Android How to receive String from Asynctask?

In my Android project, inside the MainActivity I have :
String receivedData = new myTask().execute().get();
Now myTask-task is:
public class MainActivity extends Activity {
private Button button;
private TextView finalResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.btn_do_it);
finalResult = (TextView) findViewById(R.id.tv_result);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String receivedData = new myTask().execute().get();
finalResult.setText(receivedData);
}
});
}
private class myTask extends AsyncTask<String, Void, String> {
#Override
protected Void doInBackground(Void... params) {
Gson gson = new Gson();
List<Myobject> newObject = new ArrayList<Myobject>();
try {
//here I add object valus to the list
newObject.add(valueadded)
} catch {
Exception e
}
//here returning the value as String
return gson.toJson(newObject);
}
protected void onPostExecute(String result) {
String receivedData = result;
}
}
}
But receivedData is not receiving any value from AsyncTask.
Why is that so? What am I doing wrong?
Your AsyncTask is defined as this:
private class myTask extends AsyncTask<String, Void, Void>
The last generic type is the type of your result. You have Void there. That means your AsyncTask does not return a value. If you want a String result, you will have to define it like this:
private class myTask extends AsyncTask<String, Void, String>
This means you can now return a String from doInBackground().
Try something like this
public class MainActivity extends Activity {
String receivedData;
private Button button;
private TextView finalResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.btn_do_it);
finalResult = (TextView) findViewById(R.id.tv_result);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new myTask().execute().get();
}
});
}
private class myTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(Void... params) {
Gson gson = new Gson();
List<Myobject> newObject = new ArrayList<Myobject>();
try {
//here I add object valus to the list
newObject.add(valueadded)
} catch (Exception e) {
//here returning the value as String
return gson.toJson(newObject);
}
}
protected void onPostExecute(String result) {
String receivedData = result;
finalResult.setText(receivedData);
}
}
}
You can add onPostExecute method inside the AsynchTask to receive the String. Like Below
private class myTask extends AsyncTask<String, Void, String> {
#Override
protected Void doInBackground(Void... params) {
.........
return someString;
}
protected void onPostExecute(String result) {
String receivedData = result;
}
}

Android handler does not start

I have app where i generate longitude and latitude from address i use AsyncTask where i start in doInBackground generating coordinates my problem is that in my code it appears that Handler is not turned on when i put this line :
viedotGeoCoo();
outside from AsyncTask it appears that everything is working perfectly.
This is my code:
public class AddEvent extends Activity {
Button addressButton, timeButton;
TextView addressTV,textView2;
TextView latLongTV, longCo, textView4;
EditText editNosaukums;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_event);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
addressTV = (TextView) findViewById(R.id.addressTV);
latLongTV = (TextView) findViewById(R.id.latLongTV);
longCo = (TextView) findViewById(R.id.longCo);
textView4 = (TextView) findViewById(R.id.textView4);
editNosaukums = (EditText) findViewById(R.id.editNosaukums);
textView2 = (TextView) findViewById(R.id.textView2);
addressButton = (Button) findViewById(R.id.addressButton);
addressButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.addressButton:
DownloadFilesTask task = new DownloadFilesTask();
task.execute((Void[]) null);
break;
}
}
});
}
private class DownloadFilesTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... urls) {
Looper.prepare();
viedotGeoCoo();
return null;
}
protected void onProgressUpdate(Void... progress) {
}
protected void onPostExecute(Void result) {
Log.e("Add_Event", "GEO IZDEVAAS");
sutitDatus();
}
}
public void viedotGeoCoo() {
EditText editValsts = (EditText) findViewById(R.id.editValsts);
EditText editPilseta = (EditText) findViewById(R.id.editPilseta);
EditText editIelaNr = (EditText) findViewById(R.id.editIelaNr);
String valsts = editValsts.getText().toString();
String pilseta = editPilseta.getText().toString();
String ielanr = editIelaNr.getText().toString();
String address = valsts + " "+ pilseta + " " + ielanr;
Log.e("ADD_EVENT", "HANDLER SAAKAS");
GeocodingLocation locationAddress = new GeocodingLocation();
locationAddress.getAddressFromLocation(address,
getApplicationContext(), new GeocoderHandler());//jadublice jaataisa speciala klase
GeocodingLocationLat locationAddressLat = new GeocodingLocationLat();
locationAddressLat.getAddressFromLocation(address,
getApplicationContext(), new GeocoderHandlerLat());//jadublice jaataisa speciala klase
Log.e("ADD_EVENT", "GEO GENEREETS");
}
//sanjem stringu no com.wunderlist.slidinglayersample.GeocodingLocation.java
private class GeocoderHandler extends Handler {
#Override
public void handleMessage(Message message) {
Log.e("Add_Event", "HANDLER_LONG");
}
}
private class GeocoderHandlerLat extends Handler {
#Override
public void handleMessage(Message message) {
Log.e("Add_Event", "Handler_Lat");
}
}
}
Has anyone have any idea why my code is not working properly?
You calling videotGeoConn() in background Thread but Thread is exiting after doInBackground
You can call a constructor from super class and pass main looper:
private class GeocoderHandlerLat extends Handler {
public GeocoderHandlerLat(){
super(Looper.getMainLooper());
}
#Override
public void handleMessage(Message message) {
Log.e("Add_Event", "Handler_Lat");
}
}
Or you can add a paremeter to videotGeoConn and create handler in onPreExecuteMethod:
private class DownloadFilesTask extends AsyncTask<Void, Void, Void> {
private GeocoderHandlerLatHandler handler;
protected void onPreExecute(){
handler = new GeocoderHandlerLat();
}
protected Void doInBackground(Void... urls) {
// Looper.prepare() is not needed
viedotGeoCoo(handler);
return null;
}
}

AsyncTask : passing value to an Activity (onCreate method )

Update1
activity:
public Integer _number = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
if (_number >0)
{
Log.d("onSuccessfulExecute", ""+_number);
}
else
{
Log.d("onSuccessfulExecute", "nope empty songs lists");
}
}
public int onSuccessfulExecute(int numberOfSongList) {
_number = numberOfSongList;
if (numberOfSongList >0)
{
Log.d("onSuccessfulExecute", ""+numberOfSongList);
}
else
{
Log.d("onSuccessfulExecute", "nope empty songs lists");
}
return numberOfSongList;
}
end Update1
UPDATE: AsynchTask has its own external class.
How to pass an value from AsyncTask onPostExecute()... to activity
my code does returning value from onPostExecute() and updating on UI but i am looking for a way to set the activity variable (NumberOfSongList) coming from AsynchTask.
AsyncTask class:
#Override
public void onPostExecute(asynctask.Payload payload)
{
AsyncTemplateActivity app = (AsyncTemplateActivity) payload.data[0];
//the below code DOES UPDATE the UI textView control
int answer = ((Integer) payload.result).intValue();
app.taskStatus.setText("Success: answer = "+answer);
//PROBLEM:
//i am trying to populate the value to an variable but does not seems like the way i am doing:
app.NumberOfSongList = payload.answer;
..............
..............
}
Activity:
public Integer NumberOfSongList;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Several UI Code
new ConnectingTask().execute();
Log.d("onCreate", ""+NumberOfSongList);
}
What about using a setter method? e.g.
private int _number;
public int setNumber(int number) {
_number = number;
}
UPDATE:
Please look at this code. This will do what you're trying to accomplish.
Activity class
public class TestActivity extends Activity {
public int Number;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
Button btnDisplay = (Button) findViewById(R.id.btnDisplay);
btnDisplay.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast toast = Toast.makeText(v.getContext(), "Generated number: " + String.valueOf(Number), Toast.LENGTH_LONG);
toast.show();
}
});
new TestTask(this).execute();
}
}
AsyncTask class
public class TestTask extends AsyncTask<Void, Void, Integer> {
private final Context _context;
private final String TAG = "TestTask";
private final Random _rnd;
public TestTask(Context context){
_context = context;
_rnd = new Random();
}
#Override
protected void onPreExecute() {
//TODO: Do task init.
super.onPreExecute();
}
#Override
protected Integer doInBackground(Void... params) {
//Simulate a long-running procedure.
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(TAG, e.getMessage());
}
return _rnd.nextInt();
}
#Override
protected void onPostExecute(Integer result) {
TestActivity test = (TestActivity) _context;
test.Number = result;
super.onPostExecute(result);
}
}
Just a word of caution: Be very careful when attempting to hold a reference to an Activity instance in an AsyncTask - I found this out the hard way :). If the user happens to rotate the device while your background task is still running, your activity will be destroyed and recreated thus invalidating the reference being to the Activity.
Create a listener.
Make a new class file. Called it something like MyAsyncListener and make it look like this:
public interface MyAsyncListener() {
onSuccessfulExecute(int numberOfSongList);
}
Make your activity implement MyAsyncListener, ie,
public class myActivity extends Activity implements MyAsyncListener {
Add the listener to the constructor for your AsyncTask and set it to a global var in the Async class. Then call the listener's method in onPostExecute and pass the data.
public class MyCustomAsync extends AsyncTask<Void,Void,Void> {
MyAsyncListener mal;
public MyCustomAsync(MyAsyncListener listener) {
this.mal = listener;
}
#Override
public void onPostExecute(asynctask.Payload payload) {
\\update UI
mal.onSuccessfulExecute(int numberOfSongList);
}
}
Now, whenever your AsyncTask is done, it will call the method onSuccessfulExecute in your Activity class which should look like:
#Override
public void onSuccessfulExecute(int numberOfSongList) {
\\do whatever
}
Good luck.

Categories

Resources