Issue accessing a variable in a Java class - java

I am trying to access the variable ArrayofTaxiDrivers in the class DownloadTask from the onCreate method of my activity file. However the variable is blank when accessed this way. The content does show when accessed from within the onPostExecute method of DownloadTask though.
Any help is greatly appreciated!
public class DownloadTask extends AsyncTask<String,Void,String> {
ArrayList<TaxiDriver> ArrayofTaxiDrivers = new ArrayList<TaxiDriver>();
#Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
try {
JSONObject jsonObject = new JSONObject(s);
JSONArray items = jsonObject.getJSONArray("items");
DownloadTask task = new DownloadTask();
for(int i=0; i<items.length(); i++) {
JSONObject itemsObject = items.getJSONObject(i);
JSONObject fields = itemsObject.getJSONObject("fields");
task.addTaxiDriver(new TaxiDriver(fields.getString("name"), fields.getString("contact")));(asList(fields.getString("name"), fields.getString("contact"))));
}
Log.i("info",task.ArrayofTaxiDrivers.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_taxi_main);
DownloadTask task = new DownloadTask();
task.execute("https://test.com/json");
Log.i("info",task.ArrayofTaxiDrivers.toString());
}

When you call
task.execute("https://test.com/json");
the task will be executed based on its priority. For this reason the onPostExecute will be called after some time and probably after the onCreate
Log.i("info",task.ArrayofTaxiDrivers.toString());
I suggest you to think that "execute" is an instruction that exits immediatly and only after a while it will be executed.

I am trying to access the variable ArrayofTaxiDrivers in the class
DownloadTask from the onCreate method of my Activity.
That is because when you created DownloadTask, the List ArryofTaxiDrivers is initialized and at that time the size of the List is zero.
If you have the data in the onPostExecute() method, that means it was probably added by AsyncTask's doInBackground() method. Could be somewhere else entirely depending on your code.
Now the AsyncTask works asynchronously: it means that while it has been kicked to start executing, it doesn't start right away. However it will eventually start executing.
So when you access the list in onCreate() of the Activity, the list doesn't have any data because you haven't added to it.
What you should do
Instead implement an interface/callback to notify the Activity that the data is loaded and ready to be used. This callback can come from onPostExecute().

Related

Google Directions API using ExecutorService instead of AsyncTask

Every tutorial I find seems to use AsyncTask (depreciated) instead of ExecutorService. I took a java course on Udemy and they used AsyncTask for everything as well. Here is one class I'm working with:
public class FetchURL extends AsyncTask<String, Void, String> {
Context mContext;
String directionMode = "driving";
public FetchURL(Context mContext) {
this.mContext = mContext;
}
#Override
protected String doInBackground(String... strings) {
// For storing data from web service
String data = "";
directionMode = strings[1];
try {
// Fetching the data from web service
data = downloadUrl(strings[0]);
Log.d("mylog", "Background task data " + data.toString());
} catch (Exception e) {
Log.d("Background Task", e.toString());
}
return data;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
PointsParser parserTask = new PointsParser(mContext, directionMode);
// Invokes the thread for parsing the JSON data
parserTask.execute(s);
}
private String downloadUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
// Creating an http connection to communicate with url
urlConnection = (HttpURLConnection) url.openConnection();
// Connecting to url
urlConnection.connect();
// Reading data from url
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
data = sb.toString();
Log.d("mylog", "Downloaded URL: " + data.toString());
br.close();
} catch (Exception e) {
Log.d("mylog", "Exception downloading URL: " + e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
}
and I'd really like to use ExecutorService like here instead of AsyncTask. I'm beating my head against the wall and I can't seem to get the proper arguments in and this thing working.
Replace your AsyncTask with a Runnable:
public class FetchUrl implements Runnable {
public interface Callback {
void onSuccess(String data);
void onFailure(Exception e);
}
private String url;
private WeakReference<Callback> callbackWeakReference;
public FetchUrl(String url, Callback callback) {
this.url = url;
this.callbackWeakReference = new WeakReference<>(callback);
}
#Override
public void run() {
try {
String data = downloadUrl(url);
Callback callback = callbackWeakReference.get();
if (callback != null) {
callback.onSuccess(data);
}
} catch (Exception e) {
Callback callback = callbackWeakReference.get();
if (callback != null) {
callback.onFailure(e);
}
}
}
... // include your downloadUrl function
}
Then create and submit it to the ExecutorService:
FetchUrl.Callback callback = new FetchUrl.Callback() {
#Override
public void onSuccess(String data) {
// handle your data
}
#Override
public void onFailure(Exception e) {
// handle the exception
}
};
Runnable job = new FetchUrl(url, callback);
ExecutorService executorService = Executors.newFixedThreadPool(4);
executorService.submit(job);
Notice I used a WeakReference<Callback>, because code in your callback is holding a reference to Context and would cause Context leaks.
The submit() function returns a Future to control your submitted job. It's handy if you want to cancel the job or want to wait for its completion (blocking the current thread). The latter usecase would perhaps favor using Callable<Result> instead of Runnable, because the calling thread can handle the exception and there would be no use for a callback making your code more concise.
Also don't forget to call shutdown() on your ExecutorService when you no longer need it.

Getting null value of Global variable in java class?

Here is my Code:
public class ServerCall {
Context context;
public int cartCount;
public ServerCall(Context context){
this.context=context;
}
public Integer addCartItem(RequestObject requestObject) {
new AddToCartList().execute(requestObject);
Log.d("count",String.valueOf(cartCount));
return cartCount;
}
public class AddToCartList extends AsyncTask<RequestObject, Void, JSONObject> {
#Override
protected JSONObject doInBackground(RequestObject... arg0) {
// Creating service handler class instance
ServiceHandler sh = new ServiceHandler();
// Making a request to url and getting response
String jsonStr = sh.makeServiceCall(arg0[0], ServiceHandler.POST);
// List<Products> result = new ArrayList<Products>();
Log.d("Response: ", "> " + jsonStr);
JSONObject product = new JSONObject();
if (jsonStr != null) {
try {
JSONObject jsonObj = new JSONObject(jsonStr);
product = jsonObj.getJSONObject("rsBody");
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
return product;
}
#Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
try {
if (result != null) {
String status = result.getString("status");
int totalCartItem = result.getInt("totalCartItem");
/* cartHelper = new CartHelper();
cartHelper.setStatus(status);
cartHelper.setTotalCartItem(totalCartItem);*/
cartCount=totalCartItem;
Log.d("status",status);
Log.d("totalCartItem",String.valueOf(cartCount));
Toast.makeText(context, status, Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
}
}
We didn't get value of global variable cartCount which I set inside AddToCartList class and try to get its value from addCartItem() function from where AddToCartList is called but we get null value.
I think that the main problem in your solution is the fact that you're trying to edit ServerCall variable from an Inner class, this would work only if cartCount is static, and I suggest you wait for your task to be finished as some people have already mentioned, using the get method new AddToCartList().execute().get()
The problem is, ServerCall and AddToCartList are not the same class, so you must first get a reference to the servercall in addtocartlit, then reference the cartCount using your reference to the servercall instance, like call.cartCount, instead of cartcount, unless its an inner class which it does not appear to be.
Secondly, you must save a reference to the addtocartlist asynctask inside addCartItem() ,then call its .get() method after starting it, this will ensure it finishes before you try to log the new value.

AsyncTask static, different type of parameters and returning value. Android.osNetworkthreadException

I have to do a lot of different things that AsyncTask doesn't allow (or maybe I don't know how to do). I have a class that call AsyncTask method (AsyncTask is another class) and I need to pass a String and an Integer, my AsyncTask has to open an online file and catch items and return a String[]. I was thinking to have solved my problem but it doesn't work with some android OS returning android.os.NetworkOnMainThreadException so I don't know other way to solve and I don't know what is the problem. My code:
public class Methods extends Activity{
static String url = "http://www.MYADDRESS.com/";
static String ConfPath = new String();
static public String[] Read(String path, int LinesNumber) throws InterruptedException{
try {
return new AsyncTask<Object, Integer, String[]>(){
#Override
public String[] doInBackground(Object... params) {
try {
String[] menus = new String [(int) params[1]];
BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url+params[0]).openStream()));
String line = reader.readLine();
for (int k = 0; k < (int) params[1]; k++) {
menus[k] = line;
line = reader.readLine();
}
return menus;
}
catch (IOException e){
e.printStackTrace();
}
return null;
}
}.execute(path,LinesNumber).get();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
the problem is
.execute(path,LinesNumber).get();
that makes the UI Thread wait the execution of your AsyncTask, since get is a blocking call. You should use just .execute(path,LinesNumber);

Trying to return with a variable which is cannot be resolved as variable

I'm new im Java, and im trying to return with a defined string variable at the end of the function, but eclipse keeps saying that it's cannot be resolved to a variable, and wants me to define it. Probably it's because im define the variable within the Try{} brackets, but how else could i do it?
public class readtextfile extends AsyncTask<String, Integer, String>{
private TextView description;
public readtextfile(TextView descriptionTextView){
this.description = descriptionTextView;
}
#Override
protected String doInBackground(String... params) {
try {
URL url = new URL("http://example.com/description1.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String line = null;
String result = "";
while ((line = in.readLine()) != null) {
//get lines
result+=line;
}
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
protected void onProgressUpdate() {
//called when the background task makes any progress
}
protected void onPreExecute() {
//called before doInBackground() is started
}
#Override
protected void onPostExecute(String result) {
this.description.setText(result);
}
}
Move the local variable declaration
String result = "";
to before the try block. If you define a variable within a block it's not available outside that block.
Alternatively you could move return result; to the end of the try block, but then you'd have to add another return statement at the end of the method, for the cases where an exception was thrown and got caught.
Or you could get rid of the try-block, move the exception-handling to elsewhere, and let any exceptions get thrown.
URL url = null;
String result = "";
Then inside your try, catch block.
try {
url = ....;
.
.
result = ....;
Declare the variable outside the try block.

Why Android thread gets terminated before it finishes to execute it?

I have a thread which get some data from Internet. It seams that it is executed correctly and data is retrieved. However if I call a method which should return data it leaves me with null. From that I drew a conclusion that thread is somehow stopped just before finning.
Here is the code:
private class getHash extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
String str = null;
try {
// Create a URL for the desired page
URL url = new URL(params[0]);
// Read all the text returned by the server
InputStream is = url.openStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader in = new BufferedReader(isr);
str = in.readLine();
is.close();
isr.close();
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
hash = str; //If I set a global variable here it gets passed without a hitch
return str;
}
#Override
protected void onPostExecute(String result) {
hash = result; // If I comment the line above and live this one I left with a null
}
}
EDIT:
As requested adding code where the thread was called:
getHash hashThread = new getHash();
hashThread.execute(new String[] {"http://www.full.path/to/the/file.hash"});
if(hash != null && !hash.equals(localHash)){
....
Whatever launched the AsyncTask
{
....
getHash hashThread = new getHash(this);
hashThread.execute(new String[] {"http://www.full.path/to/the/file.hash"});
return; // ok now we just have to wait for it to finish ... can't read it until then
}
// Separate callback method
public void onHashComplete(String hash) {
if(hash != null && !hash.equals(localHash)) {
....
}
....
}
Now in your GetHash class
public String doInBackground(String[] params) {
.... // don't set hash here ... it will work but you will probably read it at the wrong time.
return str;
}
public void onPostExecute(String str) {
onHashComplete(str); // or just do all the work in here since it is a private inner class
}
....
Hopefully that helps. Remember doInBackground() happens on the AsyncTask thread, onPostExecute() executes on the main Thread. Whatever thread called execute() is should also be the main thread. Because of the way the main thread works, you can't expect the onPostCreate() to occur until whatever callback that it was using to call execute() in the first place, finishes. So that is why I add the return.

Categories

Resources