Problem with accessing the views from exception within asyncTask - java

I am having a problem which is I think that I can't access th,e ListView from the asyncTask
Actually, I really don't know the real problem here
Let me show you what is happening
I have an activity which is executing AsyncTask and creates HttpURLConnection. Sometimes I get an exception (ProtocolException) because the stream un-expectedly ends.
So, I created a handler for this exception that calls a function or a method inside the class of the activity to display a message to the user
Here is a picture so you understand what is my project.
image
the problem here whenever the exception is thrown, the same function/method that I use to add the text to the listView is called, but after it called the listView disappear, but when I minimize the soft keyboard manually the everything becomes fine.
the structure of my class is
public class MainActivity extends AppCompatActivity
{
protected void onCreate(Bundle savedInstanceState)
{
addMessageToListView()//works fin here
}
protected void addMessage(String message, int userMessage, ListView listView) // the function
{
try
{
messages.add(new Message(message,userMessage));
MessagesAdapter messagesAdapter = new MessagesAdapter(messages, getBaseContext());
messagesAdapter.notifyDataSetChanged();
listView.setAdapter(messagesAdapter);
}
catch (Exception exception)
{
}
}
private class HttpPostAsyncTask extends AsyncTask<String, Void, String>
{
...
#Override
protected void onPostExecute(String result)
{
try
{
addMessageToListView()//works fin here
}
catch (Exception exception)
{
}
}
protected String doInBackground(String... params)
{
String result = "";
for (int i = 0; i <= 0; ++i)
{
result = this.invokePost(params[i], this.postData);
}
return result;
}
private String invokePost(String requestURL, HashMap<String, String> postDataParams)// called from doInBackground
{
try
{
addMessageToListView()//works fin here
}
catch (Exception exception)
{
addMessageToListView()//not orking here
}
}
}
}
I don't know how to explain more actually.

You can change Views only in mainthread of your app. The doInBackground doesn't run in mainthread of your app.

Solved by adding:
new Thread()
{
#Override
public void run()
{
MainActivity.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
addMessageToListView()//not orking here
}
});
super.run();
}
}.start();
Editing the previous code in my question:
public class MainActivity extends AppCompatActivity
{
protected void onCreate(Bundle savedInstanceState)
{
addMessageToListView()//works fin here
}
protected void addMessage(String message, int userMessage, ListView listView) // the function
{
try
{
messages.add(new Message(message,userMessage));
MessagesAdapter messagesAdapter = new MessagesAdapter(messages, getBaseContext());
messagesAdapter.notifyDataSetChanged();
listView.setAdapter(messagesAdapter);
}
catch (Exception exception)
{
}
}
private class HttpPostAsyncTask extends AsyncTask<String, Void, String>
{
...
#Override
protected void onPostExecute(String result)
{
try
{
addMessageToListView()//works fin here
}
catch (Exception exception)
{
}
}
protected String doInBackground(String... params)
{
String result = "";
for (int i = 0; i <= 0; ++i)
{
result = this.invokePost(params[i], this.postData);
}
return result;
}
private String invokePost(String requestURL, HashMap<String, String> postDataParams)// called from doInBackground
{
try
{
addMessageToListView()//works fin here
}
catch (Exception exception)
{
new Thread()
{
#Override
public void run()
{
MainActivity.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
addMessageToListView()//not orking here
}
});
super.run();
}
}.start();
}
}
}
}

Related

Why is my code not working in a AsyncTask using the JSoup library for my Android activity?

public class ConnectionTest extends AsyncTask<Void, Void, Void> {
String connection;
String loginFormUrl = "https://intranet.tam.ch/";
#Override
protected Void doInBackground(Void... voids) {
try{
Connection.Response loginForm = Jsoup.connect(loginFormUrl).method(Connection.Method.GET)
.execute();
connection = loginForm.toString();
System.out.print(title);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
My Activity should just display the connection in a TextView. I have also tried making a Thread and running it in the new Thread but it also won't work.
Here is my Activity
public class Test extends AppCompatActivity {
TextView textView;
ConnectionTest connectionTest = new ConnectionTest();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
connectionTest.getWebsite();
textView = findViewById(R.id.sdweedew);
textView.setText(connectionTest.connection);
}
}
Change your activity code like this,
I've used a TextView to display the status of the connection.
public class MainActivity extends AppCompatActivity {
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
textView = findViewById(R.id.sdweedew);
new ConnectionTest().execute();
}
class ConnectionTest extends AsyncTask<Void, Void, String> {
String loginFormUrl = "https://intranet.tam.ch/";
#Override
protected String doInBackground(Void... voids) {
try {
Connection.Response loginForm = Jsoup.connect(loginFormUrl).method(Connection.Method.GET)
.execute();
return loginForm.statusMessage();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
if (textView != null) {
textView.setText(s);
}
super.onPostExecute(s);
}
}
}
And remember to add Internet permission in manifest file.
<uses-permission android:name="android.permission.INTERNET" />
please check this code
private void getWebsite() {
new Thread(new Runnable() {
#Override
public void run() {
final StringBuilder builder = new StringBuilder();
try {
Document doc = Jsoup.connect("https://intranet.tam.ch/").get();
String title = doc.title();
Elements links = doc.select("a[href]");
builder.append(title).append("\n");
for (Element link : links) {
builder.append("\n").append("Link : ").append(link.attr("href"))
.append("\n").append("Text : ").append(link.text());
}
} catch (IOException e) {
builder.append("Error : ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(builder.toString());
}
});
}
}).start();
}

how to return string from AsyncTask to another activity

I have created a class and extend with AsyncTask , now i want to return me a string to another activity throw this class . its getting jsonstring from mysql mDatabase
enter code here
public class GetJson extends AsyncTask<Void,Void,String> {
String JSON_STRING;
String json_url;
public String pasString;
Activity ab;
#Override
protected void onPreExecute() {
json_url="https://XXXXXXX.000webhostapp.com/Json_getData_Survey.php";
}
public GetJson(Activity b) {
ab=b;
}
#Override
protected String doInBackground(Void... params) {
try {
URL url =new URL(json_url);
HttpURLConnection httpURLConnection =(HttpURLConnection) url.openConnection();
InputStream inputStream =httpURLConnection.getInputStream();
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder=new StringBuilder();
while ((JSON_STRING=bufferedReader.readLine())!=null)
{
stringBuilder.append(JSON_STRING+"\n");
}
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
String strings =stringBuilder.toString().trim();
return strings;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
pasString=result;
// Toast.makeText(ab,pasString,Toast.LENGTH_LONG).show();
// json_string1=result;
}
}
i just need to return string1 to my another Activity , i have creaetd a another mehtod in GetJson class to return this string but when i display this it show nothing in it. please help
its Quite simple
make an interface class as following
public interface ResponseListener() {
void onResponseReceive(String data);
}
and add instance of this class in you GetJson class like this
public class GetJson extends AsyncTask<Void,Void,String> {
String JSON_STRING;
String json_url;
public String pasString;
Activity ab;
// this is new code
ResponseListener listener;
public void setOnResponseListener(ResponseListener listener) {
this.listener = listener;
}
#Override
protected void onPreExecute() {
json_url="https://XXXXXXX.000webhostapp.com/Json_getData_Survey.php";
}
// now add this code in onPost function
#Override
protected void onPostExecute(String result) {
pasString=result;
listener.onResponseReceive(pasString);
// Toast.makeText(ab,pasString,Toast.LENGTH_LONG).show();
// json_string1=result;
}
now when you call GetJson from your activity, just simple do that;
GetJson json = new GetJson(Activity.this);
json.setOnResponseListener(new ResponseListener() {
#Override
public void onResponseReceived(String data) {
// here you will get your response
}
});
hope you will understand. :)
Try using activity results. You can set the return value on the one activity, and get it when that activity terminates.
https://developer.android.com/training/basics/intents/result.html

How to make a program wait for a method in java

I am writing a programm that returns me a ArrayList of Strings. Problem is, when I call the method the list is not filled yet so I get an empty list back .
I tried it with a thread but now I get a null reference when I call the method. By the way i had to implement a async task, otherwise I get an exception when trying to use InetAddress.
private class DeviceManager extends Thread {
private ArrayList<String> deviceList;
private String networkIP;
public DeviceManager(String networkIP) {
this.networkIP = networkIP;
}
public void run() {
getDeviceList();
}
public ArrayList<String> getDeviceList() {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
deviceList = new ArrayList<String>();
InetAddress address;
Log.i("NetworkIPgetDeviceList", networkIP);
String deviceIP = networkIP;
for (int i = 0; i < 255; i++) {
address = InetAddress.getByName(deviceIP += "" + i);
if (address.isReachable(2000)) {
Log.i("Devicefound", deviceIP);
deviceList.add(deviceIP);
}
deviceIP = networkIP;
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
return deviceList;
}
public ArrayList<String> getList() {
return this.deviceList;
}
}
Artur what you are doing in your code is starting a thread to retrieve device list and then another thread(AsyncTask) to actually creates the device list. So you have three threads running here simultaneously (assuming you are using DeviceManager class in UIThread). The reason getDeviceList() is returning null is because AsyncTasks doInBackground hasn't run yet to collect your device list it might be waiting for its chance to get scheduled. so to conclude that, you just need one thread(other than UIThread), it can either be a Thread or AsyncTask (more preferable as it gives better control) as rusted brain has used in his answer. I prefer to make DeviceManager as AsyncTask (just a bit cleaner and if device managers only task is to retrieve device list) as code below.
in AsyncTask doInBackground runs in a background thread(as name suggests) and onPostExecute runs on the UI thread after doInBackground
class DeviceManager extends AsyncTask<String, Void, List<String>> {
private ConnectionCompleteListener listener;
public interface ConnectionCompleteListener {
void onSuccess(List<String> deviceList);
// if you need to know reason for failure you can add
// parameter to onFailure
void onFailure();
}
public DeviceManager(ConnectionCompleteListener listener) {
this.listener = listener;
}
#Override
protected List<String> doInBackground(String... params) {
List<String> deviceList = new ArrayList<>();
String networkIP = params[0];
try {
InetAddress address;
Log.i("NetworkIPgetDeviceList", networkIP);
String deviceIP = networkIP;
for (int i = 0; i < 255; i++) {
address = InetAddress.getByName(deviceIP += "" + i);
if (address.isReachable(2000)) {
Log.i("Devicefound", deviceIP);
deviceList.add(deviceIP);
}
deviceIP = networkIP;
}
} catch (IOException e) {
deviceList = null;
e.printStackTrace();
}
return deviceList;
}
#Override
protected void onPostExecute(List<String> deviceList) {
if (deviceList == null) {
this.listener.onFailure();
} else {
this.listener.onSuccess(deviceList);
}
}
}
so in your activity you can call
new DeviceManager(new DeviceManager.ConnectionCompleteListener
() {
#Override
public void onSuccess(List<String> deviceList) {
}
#Override
public void onFailure() {
}
}).execute("YOUR_NETWORK_IP");
You are doing it completely wrong. A Thread runs in the background and so does AsyncTask, so basically you are making a background task run in background. Inception.
Try this:
public class DeviceManager {
private ArrayList<String> deviceList;
private String networkIP;
private ConnectionCompleteListener listener;
public interface ConnectionCompleteListener {
void onSuccess();
void onFailure();
}
public void setConnectionCompleteListener(ConnectionCompleteListener listener) {
this.listener = listener;
}
public DeviceManager(String networkIP) {
this.networkIP = networkIP;
}
public void getDeviceList() {
new AsyncTask<Void, Void, Boolean>() {
#Override
protected void onPostExecute(Boolean result) {
if(result) listener.onSuccess();
else listener.onFailure();
}
#Override
protected Boolean doInBackground(Void... params) {
try {
deviceList = new ArrayList<String>();
InetAddress address;
Log.i("NetworkIPgetDeviceList", networkIP);
String deviceIP = networkIP;
for (int i = 0; i < 255; i++) {
address = InetAddress.getByName(deviceIP += "" + i);
if (address.isReachable(2000)) {
Log.i("Devicefound", deviceIP);
deviceList.add(deviceIP);
}
deviceIP = networkIP;
}
return true;
} catch (UnknownHostException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return null;
}
}.execute();
}
public ArrayList<String> getList() {
return this.deviceList;
}
}
Then in your other class:
private class classname{
DeviceManager manager=new DeviceMnager(networkIp);
manger.setConnectionCompleteListener(new DeviceManager.ConnectionCompleteListener() {
#Override
public void onSuccess() {
// get your list here
manager.getList();
}
#Override
public void onFailure() {
// connection failed show error
}
});
}
You are getting empty array list because as you are using async task for getting array list and async task doINBackground method runs on different thread(means not on main thread). So when your program runs then your program doesn't wait for async task response.
You can solve this like that...
Use onPostExecute method in async task class and return the arraylist
#Override
protected void onPostExecute(Void result) {
//return array list here
getList();
}
Hope this will help you
First of All you don't need to make DeviceManager a thread as the task which you are running in getDeviceList will start in another new thread. Second You shouldn't wait on main(UI) thread so instead of waiting callback is a better mechanism.
If you insist on the same code try this..
public class DeviceManager extends Thread {
private ArrayList<String> deviceList;
private String networkIP;
private boolean dataAvailable;
public DeviceManager(String networkIP) {
this.networkIP = networkIP;
}
public void run() {
getDeviceList();
}
public ArrayList<String> getDeviceList() {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
deviceList = new ArrayList<String>();
InetAddress address;
Log.i("NetworkIPgetDeviceList", networkIP);
String deviceIP = networkIP;
for (int i = 0; i < 255; i++) {
System.out.println("checking " + i);
address = InetAddress.getByName(deviceIP += "" + i);
if (address.isReachable(2000)) {
Log.i("Devicefound", deviceIP);
deviceList.add(deviceIP);
}
deviceIP = networkIP;
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
dataAvailable = true;
synchronized (DeviceManager.this) {
DeviceManager.this.notify();
}
return null;
}
}.execute();
return deviceList;
}
synchronized public ArrayList<String> getList() {
while (!dataAvailable) {
try {
wait();
} catch (InterruptedException e) {
}
}
return this.deviceList;
}
}

"The content of the adapter has changed but ListView did not receive a notification" Error on listview

This error is Showing often "The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread."
Getting the NewsList and other images and ads from API using JSON.
class LongOperation extends AsyncTask<String, Void, String> {
protected void onPreExecute() {
}
protected String doInBackground(String... params) {
try {
AdSpotList.add(sched);
Image_view_List.add(sched);
NewsList.add(sched);
handler.sendEmptyMessage(1);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
}
}
Handler handler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 1) {
if (NewsList.size() != 0) {
if (NewsList.size() <= 5) {
adapter = new CustomAdapter(getActivity(),
Image_view_List, NewsList, AdSpotList, res);
lv_daily_summary.setAdapter(adapter);
} else {
getActivity().runOnUiThread(new Runnable() {
public void run() {
lv_daily_summary.invalidateViews();
adapter.notifyDataSetChanged();
}
});
}
}
}
}
};
This complete page is on the Fragment.

AsyncTask not calling onPostExecute

Other class:
SpotifyTask st = new SpotifyTask(new Closure<JSONObject>() {
#Override
public void executeOnSuccess(JSONObject result) {
track.setJson(result);
}
});
st.execute("asd");
Being SpotifyTask:
public class SpotifyTask extends AsyncTask<Object, Void, JSONObject> {
private final Closure<JSONObject> closure;
public SpotifyTask(Closure<JSONObject> closure) {
this.closure = closure;
}
public static void getTrack(Closure<JSONObject> closure) {
new SpotifyTask(closure).execute("asd");
}
#Override
protected JSONObject doInBackground(Object... params) {
JSONObject result = null;
SpotifyCall spcall = new SpotifyCall();
try {
result = spcall.getTrack();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(JSONObject result) {
System.out.println("ASD: on post execute "+result);
closure.executeOnSuccess(result);
}
}
So... doInBackground is running OK, and and returning a JSONObject all right; I know because Im debbuging it and "result" IS a JSONObject.
But onPostExecute is never executed, the debugger never gets there and "ASD: on postexecute "+result is never logged.
Any suggestions?
Thanks in advance!
The problem was that I was "holding" the UI Thread:
this.status = "loading";
final Track track = new Track();
SpotifyTask.getTrack(new Closure<JSONObject>() {
#Override
public void executeOnSuccess(JSONObject result) {
track.setJson(result);
}
});
while (this.status.equals("loading")) {
if (track.getJson() != null) {
this.trackUno = track.getJson();
this.status = "ready";
} else {
try {
System.out.println("Not ready, waiting.");
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
As soon I removed the while block, it worked perfectly.
I would have to find another way to "wait" for the call to be complete.
Thanks for your time fellas!

Categories