I am attempting to pass a string I got in an Asynchronous task class back in to my main activity, but when I pass the string result (which I know isn't null because logging the string right before passing it to the interface outputs what it should), I get a nullPointerException that says I can't pass a null object to the interface method.
Here is the AsyncTask class,
public class APICalls extends AsyncTask<String,Void, String> {
public AsyncResponse delegate;
protected String doInBackground(String... zipcodes){
String zipcode = zipcodes[0];
String apikey = "6562c36e87ba41f6bc887104d1e82eb8";
String baseURL = "https://congress.api.sunlightfoundation.com";
String zipCodeAddition = "/legislators/locate?apikey="+apikey + "&zip=" + zipcode;
String url = baseURL + zipCodeAddition;
String results = "";
URL apiurl = null;
try {
apiurl = new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
HttpsURLConnection urlConnection = null;
try {
urlConnection = (HttpsURLConnection) apiurl.openConnection();
} catch (IOException e) {
e.printStackTrace();
}
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
int data = in.read();
while(data != -1){
results += String.valueOf((char) data);
data = in.read();
}
in.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
urlConnection.disconnect();
}
return results;
}
protected void onPostExecute(String result){
String results = result;
try {
delegate.processFinish(results);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The error occurs in the line delegate.processFinish(results);. When I log the results string it is not null. The interface is:
public interface AsyncResponse {
void processFinish(String output) throws IOException;
}
Then in the main activity I implement the interface and have the method:
public void processFinish(String output) throws IOException {
Log.v("++++++++", output);
}
You get NPE not because output is null, but because delegate is. You never initialize it.
Related
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.
I'm trying to use AsyncTask and BufferedReader to read the line shown in the http with the following code.
private class DownloadFilesTask extends AsyncTask <Void, Integer, String> {
#Override
protected String doInBackground(Void... params) {
String request_url = "http://www.ryanheise.com/sarcastic.cgi";
try {
URL url = new URL(request_url);
try {
URLConnection conn = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
try {
String joke = in.readLine();
Log.d("Joke -- ", joke);
return joke;
} finally {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
Log.d("IOE", " ----------- IOE");
}
} catch (MalformedURLException e) {
e.printStackTrace();
Log.d("MURL", " ----------- MURL");
}
return "unable to get joke";
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected void onPostExecute(String result) {
mJoke_tv.setText(result);
Log.d("onPost", result);
}
}
and it runs with no exception but returns an unexpected result.
the log.d("joke---" , joke) shows:
"!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">"
which I have no idea why.
the logcat shows:
D/JokeĀ --: !DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
can anyone help me out of it please?
many thanks.
I have an AsyncTask that downloads a bunch of images, as seen below:
class DownloadHelper extends AsyncTask<Void, Void, Void> {
public Context mContext;
private DBHelper mDatabase;
DownloadHelper(Context context) {
this.mContext = context;
mDatabase = new DBHelper(mContext);
}
#Override
protected Void doInBackground(Void... voids) {
List<Exercise> mExercises = mDatabase.getExercises();
for (int i = 0; i < mExercises.size(); i++) {
Exercise e = mExercises.get(i);
Log.d("path", e.getImage_start());
saveFile(e.getLink_start(), e.getImage_start());
saveFile(e.getLink_end(), e.getImage_end());
}
return null;
}
private void saveFile(String url, String path){
//region Save Bitmap To File
URL mURL = null;
try { mURL = new URL( url ); }
catch (MalformedURLException e) { Log.d("Error", "ce url de cacat smr yo niki nu merge"); e.printStackTrace();}
HttpURLConnection mConn = null;
try { mConn = (HttpURLConnection) mURL.openConnection(); mConn.setDoInput(true); mConn.connect(); }
catch (IOException e) {e.printStackTrace();}
Bitmap mBitmap = null;
try {
InputStream mInput = mConn.getInputStream();
mBitmap = BitmapFactory.decodeStream(mInput);
} catch (Exception e) { e.printStackTrace(); }
//endregion
//region Save Bitmap
if (mBitmap != null){
try {
FileOutputStream mOutput = new FileOutputStream(path);
mBitmap.compress(Bitmap.CompressFormat.PNG, 90, mOutput);
mOutput.close();
} catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); }
}
}
}
and it is called in a function like this:
public void initialize(){
PermissionManager mManager = new PermissionManager() {};
mManager.checkAndRequestPermissions((Activity) mContext);
downloadExercises();
//region Create Exercises Folder To Store Images
File mFolder = mContext.getDir("exercises", Context.MODE_PRIVATE);
if (!mFolder.exists()) mFolder.mkdir();
Log.d("path", mFolder.getAbsolutePath());
//endregion
DownloadHelper mDownload = new DownloadHelper(mContext);
mDownload.execute();
}
However, when i debug the app, i have a breakpoint on mDownload.execute() and then some other ones in the doInBackground(), but the app never gets to the async task.
What am i doing wrong?
I had a similar issue, I believe you need to pass in null parameters when executing your async task:
mDownload.execute((Void) null);
If this doesn't help, perhaps your if statement is not passing, therefore your method is never run?
Just try this,
class DownloadHelper extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... strings) {
String response=null;
//** Do Your code here and must the result declare to response **//
return response;
}
}
In your main class after declare Asyntask then get the return value
DownloadHelper mDownload = new DownloadHelper();
mDownload.execute(mContext);
then add this line
String get_return=mDownload.get();
I figured out what was the problem. The Async was running but it seems that the downloadExercises() function added the exercises to the database AFTER the async would call getExercises() in order to download the images and therefore it didnt do anything. The solution i found was to prompt the user with a dialog to download the images AFTER the download and insertion of exercises was completed.
I am trying to return the content of a text file on localhost (wamp server) as a string. I can read the text file but I cannot return a string because the function run of Runnable is a void. I'm working on Android Studio (that's why I'm using thread).
public String serverToString()
{
String str;
Thread t = new Thread(new Runnable() {
public void run() {
try {
URL url = new URL("http://myIP/test.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
str = in.readLine();
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Throwable th) {
th.printStackTrace();
}
}
});
t.start();
return str;
}
Advancing the the Cricket answer, I usually create an AsyncTask and inside it I define a callback interface.
The activity executing this task should implements this interface.
As an example of part of the code:
public class TeamUpdateTask extends AsyncTask, Object, TeamUpdateResponse> {
private TeamUpdateTaskCallback mListener;
#Override
public void onPostExecute (TeamUpdateResponse result) {
if (exception == null) {
mListener.OnTeamUpdateCompleted(result);
} else {
processException();
}
}
public void setListener (TeamUpdateTaskCallback listener) {
mListener = listener;
}
public interface TeamUpdateTaskCallback {
void OnTeamUpdateCompleted (TeamUpdateResponse response);
}
}
Hope it helps.
Generally, Volley library would be preferred over raw Thread. Or AsyncTask
but I cannot return a string because the function run of Runnable is a void
You can pass the result to a new method, though.
Define an interface
public interface ServerResponse {
void onResponse(String msg);
}
Add a parameter
public void serverToString(final ServerResponse callback)
{
String str;
Thread t = new Thread(new Runnable() {
public void run() {
try {
URL url = new URL("http://myIP/test.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
callback.onResponse(in.readLine()); // This is the 'return' now
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Throwable th) {
th.printStackTrace();
}
}
});
t.start();
}
And instead of this
String response = serverToString();
Do this
serverToString(new ServerResponse() {
#Override
public void onResponse(String response) {
// handle message
}
});
I am trying to get data from RSS feed to display it in fragments (11 fragment), but each time i pass to a new fragment the UI block for a several seconds because it's fetching data so i try to use asyncTask to do this in background but it seems that it does not work.
public class AndroidSaxFeedParser extends AsyncTask<String, Long, ArrayList<Article>>{
String dt;
String bb;
String nameCat;
RootElement root;
Element item;
static final String RSS = "rss";
static final String FEED = "feed";
static final String ENTRY = "entry";
static final String CHANNEL = "channel";
static final String PUB_DATE = "pubDate";
static final String DESCRIPTION = "description";
static final String LINK = "link";
static final String TITLE = "title";
static final String ITEM = "item";
static final String CATEGORY = "category";
static final String DURATION = "itunes:duration";
ArrayList<Article> rssItems = new ArrayList<Article>();
public URL feedUrl;
Context mContext;
public AndroidSaxFeedParser(Context context)
{
mContext = context;
}
// ProgressDialog pd = new ProgressDialog(mContext);
#Override
protected void onPostExecute(ArrayList<Article> result) {
// pd.dismiss();
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
// ProgressDialog.show(mContext, "", "Chargement...");
super.onPreExecute();
}
#Override
protected ArrayList<Article> doInBackground(String... params) {
try {
feedUrl = new URL(params[0]);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
final Article currentRssItem = new Article();
root = new RootElement(RSS);
Element channel = root.getChild(CHANNEL);
item = channel.getChild(ITEM);
item.getChild(TITLE).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentRssItem.setTitle(body);
Log.i("Title Article", " "+currentRssItem.getTitle());
}
});
item.getChild(CATEGORY).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentRssItem.setCategorie(body);
Log.i("Category Article", " "+currentRssItem.getCategorie());
}
});
item.getChild(DESCRIPTION).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
String imgUrl, desc;
try {imgUrl = body.substring(body.indexOf("src=")+5,body.indexOf("\"", body.indexOf("src=")+6));}
catch (Exception e)
{imgUrl = "";}
try {desc=body;}
catch (Exception e)
{ desc = "";}
currentRssItem.setImageUrl(imgUrl);
currentRssItem.setDescription(desc);
Log.i("Image URL Article", " "+currentRssItem.getImageUrl());
Log.i("Description Article", " "+currentRssItem.getDescription());
}
});
item.getChild(PUB_DATE).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentRssItem.setPubDate(body);
Log.i("Date Article", " "+currentRssItem.getPubDate());
}
});
item.setEndElementListener(new EndElementListener(){
public void end() {
rssItems.add(currentRssItem.copy());
}
});
try {
Xml.parse(feedUrl.openConnection().getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
return rssItems;
}
I am calling it this way in each fragment
ArrayList<Article> feeds ;
try {
feeds=AndroidSaxFeedParser.execute(url).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
You should always download the file and save it as a String before asking the XML class to parse it.
public String getXml(String url) {
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
// HTTP OK 200
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
// NOTE: Here need to set the default charset to be UTF-8
content = EntityUtils.toString(entity, "UTF-8");
return content;
}
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
content = null;
}
}
In this way it is less likely to get interrupted due to connection problem. In addtition, please tell us more about what "it seems that it does not work" means. Did it fail to parse the xml, fail to run the task, or fail what?
Also, you should not be calling
feeds=AndroidSaxFeedParser.execute(url).get();
in your fragment. You should modify this function of your AndroidSaxFeedParser:
#Override
protected void onPostExecute(ArrayList<Article> result) {
feeds = result;
// Do whatever you wanna do to set up things with the feeds
}
To make this work you must put your AndroidSaxFeedParser as an inner class of your fragment.