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.
Related
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 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.
I am creating an Android chat application wherein I am using WebSockets and on top of that I want to create a custom implementation of Application protocol.
I am stuck in a situation.
Essentially, what I want is a way to know that an event handler method has been called in another class, fire up my own method in my class based on that and then get the result of that event handler method in my class.
How is that possible?
I researched a lot and found something like binding, event emitters, etc. Can someone point me to the right direction and provide some resources from where I can learn this technique?
This is what I have done so far:
public void connect(){
try {
setUpWebSocketHandler(handler);
mConnection.connect(wsuri, handler);
}
catch (WebSocketException e) {
Log.d("exception", e.toString());
}
}
public void setUpWebSocketHandler(WebSocketHandler handler)
{
handler = new WebSocketHandler(){
//first method for websockethandler
#Override
public void onOpen() {
//here i create a json format string to be sent to my server that returns something afterwards
String output = json.toString();
Log.d("OUTPUT+" , output);
Log.d("onOpen", "Status: Connected to " + wsuri);
mConnection.sendTextMessage(output);
}
//second method for websockethandler
#Override
public void onTextMessage(final String payload) {
Log.d("onTextMessage", "Response: " + payload);
JSONObject jsonObj = null;
try {
jsonObj = new JSONObject(payload);
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
String type = jsonObj.getString("type");
switch (type) {
case "xxx":
//authEvent
System.out.println("xxx");
break;
case "yyy":
//userOnlineEvent
System.out.println("yyy");
break;
case "zzz":
System.out.println("zzz");
break;
case "userListToken":
userList = getUserList(payload);
break;
default:
System.out.println("DefaultCase");
break;
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//third method for websockethandler
#Override
public void onClose(int code, String reason) {
Log.d("onClose", "Connection lost.");
}
};
}
public String getUserList(final String payload)
{
final Thread connectthread;
connectthread = new Thread(
new Runnable()
{
public void run()
{
try {
//here i create a URL, send post request to it and i get a response with userlist
HttpClient client = new DefaultHttpClient();
HttpGet post = new HttpGet(url);
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
while ((userList = rd.readLine()) != null) {
System.out.println(userList);
Log.d("HTTP GET RESPONSE", "Response: " + userList);
}
} catch (JSONException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
);
connectthread.start();
try
{
connectthread.join();
}
catch (Exception e)
{
Log.i("error","Error!!");
}
System.out.println("userListToken");
return userList;
}
I have another question. I got the userList using callbacks....The problem now is:
private class ProcessLogin extends AsyncTask<String, Void, String> {
private ProgressDialog pDialog;
String uname,password;
#Override
protected void onPreExecute() {
super.onPreExecute();
uname = txtUsername.getText().toString();
password = txtPassword.getText().toString();
pDialog = new ProgressDialog(LoginActivity.this);
pDialog.setTitle("Contacting Servers");
pDialog.setMessage("Logging in ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected String doInBackground(String... args) {
String user = null;
ifly.connect();
user = userList;
return user;
}
#Override
protected void onPostExecute(String user) {
try {
if(user != null){
//Intent i = new Intent("com.example.tabmainactivity");
Log.d("Got it", "Response: " + userList);
pDialog.dismiss();
//startService(new Intent(getApplicationContext(),iFlyChatMessage.class));
//startActivity(i);
//finish();
}else{
// username / password doesn't match
pDialog.dismiss();
Toast.makeText(getApplicationContext(),
"Incorrect username/password", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void processMessage(String userList)
{
this.userList = userList;
}
I want the userList in postExecute so that i can send this userList to another activity. How do i stop doinbackground() to wait for callback to finish. If I use thread.sleep, the whole process stops, not even connect works.
Thanks
You can declare an interface somewhere, make your event handler accept an instance of this interface, then create an anonymous class implementing this interface while passing that instance in your handler's registration with event source.
Something like below:
public class MyClass{
...
...
component.addXXXListener(new EventHandler(new MyInterface() {
#Override
public void doSomething() {
callMethod();
}
}));
...
...
public void callMethod() {
...
...
}
I hope you got the point.
I'm not sure that I understood you correctly.
You should use callback object.
Something like:
public interface MessageProcesor{
public void processMessage(String message);
}
Your activity should implement this interface.
And you should have MessageProcesor field in your "client" class.
Your code should look something like this:
private MessageProcesor callback;
public void setUpWebSocketHandler(WebSocketHandler handler)
{
handler = new WebSocketHandler(){
//first method for websockethandler
#Override
public void onOpen() {
//here i create a json format string to be sent to my server that returns something afterwards
String output = json.toString();
Log.d("OUTPUT+" , output);
Log.d("onOpen", "Status: Connected to " + wsuri);
mConnection.sendTextMessage(output);
}
//second method for websockethandler
#Override
public void onTextMessage(final String payload) {
Log.d("onTextMessage", "Response: " + payload);
JSONObject jsonObj = null;
try {
jsonObj = new JSONObject(payload);
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
String type = jsonObj.getString("type");
switch (type) {
case "xxx":
//authEvent
System.out.println("xxx");
break;
case "yyy":
//userOnlineEvent
System.out.println("yyy");
break;
case "zzz":
System.out.println("zzz");
break;
case "userListToken":
userList = getUserList(payload);
callback.processMessage(userList);
break;
default:
System.out.println("DefaultCase");
break;
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//third method for websockethandler
#Override
public void onClose(int code, String reason) {
Log.d("onClose", "Connection lost.");
}
};
}
public String getUserList(final String payload)
{
final Thread connectthread;
connectthread = new Thread(
new Runnable()
{
public void run()
{
try {
//here i create a URL, send post request to it and i get a response with userlist
HttpClient client = new DefaultHttpClient();
HttpGet post = new HttpGet(url);
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
while ((userList = rd.readLine()) != null) {
System.out.println(userList);
Log.d("HTTP GET RESPONSE", "Response: " + userList);
}
} catch (JSONException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
);
connectthread.start();
try
{
connectthread.join();
}
catch (Exception e)
{
Log.i("error","Error!!");
}
System.out.println("userListToken");
return userList;
}
You can pass "callback" as constructor param or via setter method.
Hope this helps.
My Android App needs some basic data to run. This data is downloaded from a server using JSON. In Xcode I simply used the sendsynchronous request but I noticed that Eclipse gives me a error when i do networking on the main ui.
Found a lot of stuff on asynctask but i want my app to wait till the required data is downloaded (synchronous?).
I tried using asynctask .execute().get() and setting the variables in onPostExecute but when I return the variable I get a NullPointerException. Does someone know how to make this work? I really need this data before the app can run so I want my app to wait till the data is downloaded.
MainActivity calls this:
SingletonClass appIDSingleton = SingletonClass.getInstance();
this.ID = appIDSingleton.getAppID();
Singleton Class:
public String getAppID() {
try {
new DownloadAppID().execute(APP_ID_URL).get(5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return AppID; //AppID is still NULL (because the download isnt finished yet?)
}
private class DownloadAppID extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result) {
System.out.println(result);
AppID = result;
}
}
You need to understand that your getAppID method can't return a result that is going to be computed asynchronously.
You could for instance provide a listener to your async task in order to notify when app ID is available:
SingletonClass appIDSingleton = SingletonClass.getInstance();
appIDSingleton.getAppID(new AppIdDownloadListener() {
#Override
public void appIDAvailable(String appId) {
this.ID = appId;
}
});
public void getAppID(AppIdDownloadListener listener) {
try {
new DownloadAppID(listener).execute(APP_ID_URL).get(5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public interface AppIdDownloadListener {
public void appIDAvailable(String appId);
}
private class DownloadAppID extends AsyncTask<String, Void, String> {
private AppIdDownloadListener listener;
public DownloadAppID(AppIdDownloadListener listener) {
this.listener = listener;
}
#Override
protected String doInBackground(String... params) {
/* Your stuff here */
}
#Override
protected void onPostExecute(String result) {
System.out.println(result);
listener.appIDAvailable(result);
}
}