Now using commons-httpclient
This commit is contained in:
parent
114dd4c6f4
commit
b9c5bdf148
@ -3,5 +3,6 @@
|
|||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="src" path="gen"/>
|
<classpathentry kind="src" path="gen"/>
|
||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
|
<classpathentry kind="lib" path="libs/commons-io-2.0.1.jar"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
BIN
libs/commons-io-2.0.1.jar
Normal file
BIN
libs/commons-io-2.0.1.jar
Normal file
Binary file not shown.
@ -1,20 +1,34 @@
|
|||||||
package com.dougkeen.bart;
|
package com.dougkeen.bart;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.HttpStatus;
|
||||||
|
import org.apache.http.client.ClientProtocolException;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
|
import org.apache.http.conn.params.ConnManagerParams;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.http.params.HttpConnectionParams;
|
||||||
|
import org.apache.http.params.HttpParams;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Xml;
|
||||||
|
|
||||||
import com.dougkeen.bart.data.RealTimeDepartures;
|
import com.dougkeen.bart.data.RealTimeDepartures;
|
||||||
|
|
||||||
import android.os.AsyncTask;
|
public abstract class GetRealTimeDeparturesTask
|
||||||
import android.util.Xml;
|
extends
|
||||||
|
|
||||||
public abstract class GetRealTimeDeparturesTask extends
|
|
||||||
AsyncTask<GetRealTimeDeparturesTask.Params, Integer, RealTimeDepartures> {
|
AsyncTask<GetRealTimeDeparturesTask.Params, Integer, RealTimeDepartures> {
|
||||||
|
|
||||||
private static final int CONNECTION_TIMEOUT_MILLIS = 10000;
|
private static final int CONNECTION_TIMEOUT_MILLIS = 10000;
|
||||||
@ -23,7 +37,7 @@ public abstract class GetRealTimeDeparturesTask extends
|
|||||||
+ API_KEY + "&orig=%1$s&dir=%2$s";
|
+ API_KEY + "&orig=%1$s&dir=%2$s";
|
||||||
private final static int MAX_ATTEMPTS = 3;
|
private final static int MAX_ATTEMPTS = 3;
|
||||||
|
|
||||||
private IOException mIOException;
|
private Exception mException;
|
||||||
|
|
||||||
private List<Route> mRoutes;
|
private List<Route> mRoutes;
|
||||||
|
|
||||||
@ -43,8 +57,9 @@ public abstract class GetRealTimeDeparturesTask extends
|
|||||||
|
|
||||||
private RealTimeDepartures getDeparturesFromNetwork(Params params,
|
private RealTimeDepartures getDeparturesFromNetwork(Params params,
|
||||||
int attemptNumber) {
|
int attemptNumber) {
|
||||||
|
String xml = null;
|
||||||
try {
|
try {
|
||||||
URL sourceUrl = new URL(String.format(API_URL,
|
HttpUriRequest request = new HttpGet(String.format(API_URL,
|
||||||
params.origin.abbreviation, mRoutes.get(0).getDirection()));
|
params.origin.abbreviation, mRoutes.get(0).getDirection()));
|
||||||
|
|
||||||
EtdContentHandler handler = new EtdContentHandler(params.origin,
|
EtdContentHandler handler = new EtdContentHandler(params.origin,
|
||||||
@ -52,11 +67,23 @@ public abstract class GetRealTimeDeparturesTask extends
|
|||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
URLConnection connection = sourceUrl.openConnection();
|
|
||||||
connection.setConnectTimeout(CONNECTION_TIMEOUT_MILLIS);
|
HttpResponse response = executeWithRecovery(request);
|
||||||
Xml.parse(connection.getInputStream(),
|
|
||||||
Xml.findEncodingByName("UTF-8"),
|
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
||||||
handler);
|
throw new IOException("Server returned "
|
||||||
|
+ response.getStatusLine().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8");
|
||||||
|
|
||||||
|
xml = writer.toString();
|
||||||
|
if (xml.length() == 0) {
|
||||||
|
throw new IOException("Server returned blank xml document");
|
||||||
|
}
|
||||||
|
|
||||||
|
Xml.parse(xml, handler);
|
||||||
final RealTimeDepartures realTimeDepartures = handler
|
final RealTimeDepartures realTimeDepartures = handler
|
||||||
.getRealTimeDepartures();
|
.getRealTimeDepartures();
|
||||||
return realTimeDepartures;
|
return realTimeDepartures;
|
||||||
@ -67,20 +94,45 @@ public abstract class GetRealTimeDeparturesTask extends
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (attemptNumber < MAX_ATTEMPTS - 1) {
|
if (attemptNumber < MAX_ATTEMPTS - 1) {
|
||||||
try {
|
try {
|
||||||
|
Log.w(Constants.TAG,
|
||||||
|
"Attempt to contact server failed... retrying in 5s",
|
||||||
|
e);
|
||||||
Thread.sleep(5000);
|
Thread.sleep(5000);
|
||||||
} catch (InterruptedException interrupt) {
|
} catch (InterruptedException interrupt) {
|
||||||
// Ignore... just go on to next attempt
|
// Ignore... just go on to next attempt
|
||||||
}
|
}
|
||||||
return getDeparturesFromNetwork(params, attemptNumber + 1);
|
return getDeparturesFromNetwork(params, attemptNumber + 1);
|
||||||
} else {
|
} else {
|
||||||
mIOException = e;
|
mException = new Exception("Could not contact BART system", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} catch (SAXException e) {
|
} catch (SAXException e) {
|
||||||
throw new RuntimeException(e);
|
mException = new Exception(
|
||||||
|
"Could not understand response from BART system: " + xml, e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static HttpResponse executeWithRecovery(final HttpUriRequest request)
|
||||||
|
throws IOException, ClientProtocolException {
|
||||||
|
try {
|
||||||
|
return getHttpClient().execute(request);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// try again... this is a rare error
|
||||||
|
return getHttpClient().execute(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HttpClient getHttpClient() {
|
||||||
|
HttpClient client = new DefaultHttpClient();
|
||||||
|
final HttpParams params = client.getParams();
|
||||||
|
HttpConnectionParams.setConnectionTimeout(params,
|
||||||
|
CONNECTION_TIMEOUT_MILLIS);
|
||||||
|
HttpConnectionParams.setSoTimeout(params, CONNECTION_TIMEOUT_MILLIS);
|
||||||
|
ConnManagerParams.setTimeout(params, CONNECTION_TIMEOUT_MILLIS);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
public static class Params {
|
public static class Params {
|
||||||
public Params(Station origin, Station destination) {
|
public Params(Station origin, Station destination) {
|
||||||
super();
|
super();
|
||||||
@ -105,11 +157,11 @@ public abstract class GetRealTimeDeparturesTask extends
|
|||||||
if (result != null) {
|
if (result != null) {
|
||||||
onResult(result);
|
onResult(result);
|
||||||
} else {
|
} else {
|
||||||
onNetworkError(mIOException);
|
onError(mException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void onResult(RealTimeDepartures result);
|
public abstract void onResult(RealTimeDepartures result);
|
||||||
|
|
||||||
public abstract void onNetworkError(IOException e);
|
public abstract void onError(Exception exception);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.dougkeen.bart;
|
package com.dougkeen.bart;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.app.ListActivity;
|
import android.app.ListActivity;
|
||||||
@ -53,7 +52,7 @@ public class ViewDeparturesActivity extends ListActivity {
|
|||||||
|
|
||||||
private PowerManager.WakeLock mWakeLock;
|
private PowerManager.WakeLock mWakeLock;
|
||||||
|
|
||||||
private boolean mFetchDeparturesOnNextFocus;
|
private boolean mDataFetchIsPending;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@ -96,14 +95,13 @@ public class ViewDeparturesActivity extends ListActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setListAdapter(mDeparturesAdapter);
|
setListAdapter(mDeparturesAdapter);
|
||||||
|
|
||||||
mFetchDeparturesOnNextFocus = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
if (mGetDeparturesTask != null) {
|
if (mGetDeparturesTask != null) {
|
||||||
mGetDeparturesTask.cancel(true);
|
mGetDeparturesTask.cancel(true);
|
||||||
|
mDataFetchIsPending = false;
|
||||||
}
|
}
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
@ -122,9 +120,8 @@ public class ViewDeparturesActivity extends ListActivity {
|
|||||||
public void onWindowFocusChanged(boolean hasFocus) {
|
public void onWindowFocusChanged(boolean hasFocus) {
|
||||||
super.onWindowFocusChanged(hasFocus);
|
super.onWindowFocusChanged(hasFocus);
|
||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
if (mFetchDeparturesOnNextFocus) {
|
if (!mDataFetchIsPending) {
|
||||||
fetchLatestDepartures();
|
fetchLatestDepartures();
|
||||||
mFetchDeparturesOnNextFocus = false;
|
|
||||||
}
|
}
|
||||||
PowerManager powerManaer = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
PowerManager powerManaer = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||||
mWakeLock = powerManaer
|
mWakeLock = powerManaer
|
||||||
@ -154,20 +151,21 @@ public class ViewDeparturesActivity extends ListActivity {
|
|||||||
mGetDeparturesTask = new GetRealTimeDeparturesTask() {
|
mGetDeparturesTask = new GetRealTimeDeparturesTask() {
|
||||||
@Override
|
@Override
|
||||||
public void onResult(RealTimeDepartures result) {
|
public void onResult(RealTimeDepartures result) {
|
||||||
|
mDataFetchIsPending = false;
|
||||||
Log.i(Constants.TAG, "Processing data from server");
|
Log.i(Constants.TAG, "Processing data from server");
|
||||||
processLatestDepartures(result);
|
processLatestDepartures(result);
|
||||||
Log.i(Constants.TAG, "Done processing data from server");
|
Log.i(Constants.TAG, "Done processing data from server");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNetworkError(IOException e) {
|
public void onError(Exception e) {
|
||||||
Log.w(Constants.TAG, e.getMessage());
|
mDataFetchIsPending = false;
|
||||||
|
Log.w(Constants.TAG, e.getMessage(), e);
|
||||||
Toast.makeText(ViewDeparturesActivity.this,
|
Toast.makeText(ViewDeparturesActivity.this,
|
||||||
R.string.could_not_connect,
|
R.string.could_not_connect,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
((TextView) findViewById(android.R.id.empty))
|
((TextView) findViewById(android.R.id.empty))
|
||||||
.setText(R.string.could_not_connect);
|
.setText(R.string.could_not_connect);
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Log.i(Constants.TAG, "Fetching data from server");
|
Log.i(Constants.TAG, "Fetching data from server");
|
||||||
@ -234,13 +232,7 @@ public class ViewDeparturesActivity extends ListActivity {
|
|||||||
if (needsBetterAccuracy
|
if (needsBetterAccuracy
|
||||||
|| firstDeparture.hasDeparted()) {
|
|| firstDeparture.hasDeparted()) {
|
||||||
// Get more data in 20s
|
// Get more data in 20s
|
||||||
mListTitleView.postDelayed(new Runnable() {
|
scheduleDataFetch(20000);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
fetchLatestDepartures();
|
|
||||||
}
|
|
||||||
}, 20000);
|
|
||||||
Log.i(Constants.TAG, "Scheduled another data fetch in 20s");
|
|
||||||
} else {
|
} else {
|
||||||
// Get more 90 seconds before next train arrives, right when
|
// Get more 90 seconds before next train arrives, right when
|
||||||
// next train arrives, or 3 minutes, whichever is sooner
|
// next train arrives, or 3 minutes, whichever is sooner
|
||||||
@ -255,15 +247,12 @@ public class ViewDeparturesActivity extends ListActivity {
|
|||||||
} else if (intervalUntilNextDeparture > alternativeInterval) {
|
} else if (intervalUntilNextDeparture > alternativeInterval) {
|
||||||
interval = alternativeInterval;
|
interval = alternativeInterval;
|
||||||
}
|
}
|
||||||
mListTitleView.postDelayed(new Runnable() {
|
|
||||||
@Override
|
if (interval < 0) {
|
||||||
public void run() {
|
interval = 20000;
|
||||||
fetchLatestDepartures();
|
|
||||||
}
|
}
|
||||||
}, interval);
|
|
||||||
Log.i(Constants.TAG, "Scheduled another data fetch in "
|
scheduleDataFetch(interval);
|
||||||
+ interval / 1000
|
|
||||||
+ "s");
|
|
||||||
}
|
}
|
||||||
if (!mIsAutoUpdating) {
|
if (!mIsAutoUpdating) {
|
||||||
mIsAutoUpdating = true;
|
mIsAutoUpdating = true;
|
||||||
@ -273,6 +262,20 @@ public class ViewDeparturesActivity extends ListActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void scheduleDataFetch(int millisUntilExecute) {
|
||||||
|
if (!mDataFetchIsPending) {
|
||||||
|
mListTitleView.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
fetchLatestDepartures();
|
||||||
|
}
|
||||||
|
}, millisUntilExecute);
|
||||||
|
mDataFetchIsPending = true;
|
||||||
|
Log.i(Constants.TAG, "Scheduled another data fetch in "
|
||||||
|
+ millisUntilExecute / 1000 + "s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void runAutoUpdate() {
|
private void runAutoUpdate() {
|
||||||
if (mIsAutoUpdating && mDeparturesAdapter != null) {
|
if (mIsAutoUpdating && mDeparturesAdapter != null) {
|
||||||
mDeparturesAdapter.notifyDataSetChanged();
|
mDeparturesAdapter.notifyDataSetChanged();
|
||||||
@ -303,7 +306,6 @@ public class ViewDeparturesActivity extends ListActivity {
|
|||||||
+ mOrigin.abbreviation
|
+ mOrigin.abbreviation
|
||||||
+ "&dest="
|
+ "&dest="
|
||||||
+ mDestination.abbreviation)));
|
+ mDestination.abbreviation)));
|
||||||
mFetchDeparturesOnNextFocus = true;
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
@ -166,7 +166,7 @@ public class Departure implements Parcelable, Comparable<Departure> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasDeparted() {
|
public boolean hasDeparted() {
|
||||||
return getMinutes() == 0 || getMeanSecondsLeft() < 0;
|
return getMeanSecondsLeft() < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void calculateEstimates(long originalEstimateTime) {
|
public void calculateEstimates(long originalEstimateTime) {
|
||||||
|
Loading…
Reference in New Issue
Block a user