android in practice_Using a Service for caching data(portfolio project)

Caching of data can make a huge difference in the performance of any application.

You want to centralize the access to this data in one place and cache it, since retrieving it over the network is slow and expensive. You want to do this from the background Service, so that it can retrieve the data even when the main application isn’t being used and so that it can be exposed to the main application via IPC with the background Service.

Your background Service can be started at device boot. Then it can retrieve data over the network. This can be done periodically, as needed. Finally, once the user launches your application, one of your app’s activities can bind to the Service and invoke one of its methods to return the data that the Service downloaded from the network.

the list of stocks that the user wants to track is managed locally, stored in a local SQLite database. To track the current price of the stock, we’ll download this data over the network.   

Stock Service now with caching.

modify the service class PortfolioManagerService:

//supports remote communication.
public class PortfolioManagerService extends Service {
private static final String TAG = "PortfolioManagerService";
// This is a data access object used for persisting stock information.
private StocksDb db;
// Timestamp of last time stock data was downloaded from the Itnernet
private long timestamp = 0L;
// How old downloaded stock data can be and still be used
private static final int MAX_CACHE_AGE = 15*60*1000; // 15 minutes
// Types of Notifications
private static final int HIGH_PRICE_NOTIFICATION = 1;
private static final int LOW_PRICE_NOTIFICATION = 0;

@Override
public void onCreate(){
super.onCreate();
db=new StocksDb(this);
}


@Override
public int onStartCommand(Intent intent, int flags, int startId){
if (db == null){
db = new StocksDb(this);
}
try {
updateStockData();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Service.START_STICKY;
}
@Override
public void onDestroy(){
super.onDestroy();
db.close();
}
/*
* a Service usually run in its own process.Interprocess communication (IPC) is necessary.
* The onBind method is where the IPC channel is established.
*/
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
if (db == null){
db = new StocksDb(this);
}
// implement the IStockService interface defined in AIDL 
// Stub class extends Binder.return.
return new IStockService.Stub() {
public Stock addToPortfolio(Stock stock) throws RemoteException {
Log.d(TAG, "Adding stock="+stock);
Stock s = db.addStock(stock);
Log.d(TAG, "Stock added to db");
try {
updateStockData();
for (Stock x:db.getStocks()){
if (x.getSymbol().equalsIgnoreCase(stock.getSymbol())){
s = x;
}
}
Log.d(TAG, "Stock data updated");
} catch (IOException e) {
Log.e(TAG, "Exception updating stock data", e);
throw new RemoteException();
}
return s;
}


public List<Stock> getPortfolio() throws RemoteException {
Log.d(TAG, "Getting portfolio");
ArrayList<Stock> stocks = db.getStocks();
long currTime = System.currentTimeMillis();
if (currTime - timestamp <= MAX_CACHE_AGE){
Log.d(TAG, "Fresh cache, returning it");
return stocks;
}
// else cache is stale, refresh it
Stock[] currStocks = new Stock[stocks.size()];
stocks.toArray(currStocks);
try {
Log.d(TAG, "Stale cache, refreshing it");
ArrayList<Stock> newStocks = fetchStockData(currStocks);
Log.d(TAG, "Got new stock data, updating cache");
updateCachedStocks(newStocks);
return newStocks;
} catch (Exception e) {
Log.e(TAG, "Exception getting stock data",e);
throw new RemoteException();
}
}
};
}
//update our cache with the fresh data
public void updateStockData ()throws IOException{
ArrayList<Stock> stocks = db.getStocks();
Stock[] currStocks = new Stock[stocks.size()];
currStocks = stocks.toArray(currStocks);
stocks = fetchStockData(currStocks);
updateCachedStocks(stocks);
}
private void updateCachedStocks(ArrayList<Stock> stocks){
Log.d(TAG, "Got new stock data to update cache with");
timestamp = System.currentTimeMillis();
Stock[] currStocks = new Stock[stocks.size()];
currStocks = stocks.toArray(currStocks);
for (Stock stock : currStocks){
Log.d(TAG, "Updating cache with stock=" + stock.toString());
db.updateStockPrice(stock);
}
Log.d(TAG, "Cache updated, checking for alerts");
checkForAlerts(stocks);
}

//retrieve data from the network
private ArrayList<Stock> fetchStockData(Stock[] stocks) throws IOException{
Log.d(TAG, "Fetching stock data from Yahoo");
ArrayList<Stock> newStocks=new ArrayList<Stock>(stocks.length);
if(stocks.length>0){
StringBuilder sb=new StringBuilder();
for(Stock stock:stocks){
sb.append(stock.getSymbol());
sb.append('+');
}
sb.deleteCharAt(sb.length()-1);
String urlStr="http://finance.yahoo.com/d/quotes.csv?f=sb2n&s="+sb.toString();
HttpClient client=new DefaultHttpClient();
HttpGet request=new HttpGet(urlStr.toString());
HttpResponse response=client.execute(request);
BufferedReader reader=new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line=reader.readLine();
int i=0;
Log.d(TAG, "Parsing stock data from Yahoo");
while(line!=null){
Log.d(TAG, "Parsing: " + line);
String[] values=line.split(",");
Stock stock=new Stock(stocks[i],stocks[i].getId());
stock.setCurrentPrice(Double.parseDouble(values[1]));
stock.setName(values[2]);
Log.d(TAG, "Parsed Stock: " + stock);
newStocks.add(stock);
line=reader.readLine();
i++;
}


}
return newStocks;
}

private void checkForAlerts(Iterable<Stock> stocks){

}
}

你可能感兴趣的:(android in practice_Using a Service for caching data(portfolio project))