IPC (InterProcess cummunication)mechanism. This mechanismallows Services to be exposed to other processes and for serialized data to besent between the processes.

create The Stock class, a Parcelable class that can be sent over IPC:

//The Stock class, a Parcelable class that can be sent over IPC.
//sent back and forth between main application and background service.
public class Stock implements Parcelable {
// user defined
private String symbol;
private double maxPrice;
private double minPrice;
private double pricePaid;
private int quantity;

// dynamic retrieved
private String name ="";
private double currentPrice=0D;

// db assigned
private int id;

//private constructor for Parcel
private Stock(Parcel parcel){
this.readFromParcel(parcel);
}

// constructors
public Stock(String symbol, double pricePaid, int quantity, int id) {
this.symbol = symbol;
this.pricePaid = pricePaid;
this.quantity = quantity;
this.id = id;
}

public Stock(String symbol, double pricePaid, int quantity) {
this(symbol, pricePaid, quantity, 0);
}

public Stock(Stock old, int id){
this.symbol = old.symbol;
this.maxPrice = old.maxPrice;
this.minPrice = old.minPrice;
this.pricePaid = old.pricePaid;
this.quantity = old.quantity;
this.name = old.name;
this.currentPrice = old.currentPrice;
this.id = id;
}



// getters and setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getCurrentPrice() {
return currentPrice;
}
public void setCurrentPrice(double currentPrice) {
this.currentPrice = currentPrice;
}
public String getSymbol() {
return symbol;
}
public double getMaxPrice() {
return maxPrice;
}
public double getMinPrice() {
return minPrice;
}
public double getPricePaid() {
return pricePaid;
}
public int getQuantity() {
return quantity;
}
public void setMaxPrice(double maxPrice) {
this.maxPrice = maxPrice;
}
public void setMinPrice(double minPrice) {
this.minPrice = minPrice;
}
public int getId() {
return id;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (name != null){
sb.append(name).append(' ');
}
sb.append('(').append(symbol.toUpperCase()).append(')')
.append(" $").append(currentPrice);
return sb.toString();
}
/**
* Any Parcelable needs a static field called CREATOR that
* acts as a factory class for the Parcelable.
* deserialize that Parcel back into a Stock.
*/
public static final Parcelable.Creator<Stock> CREATOR = new Parcelable.Creator<Stock>() {
//a factory method
public Stock createFromParcel(Parcel source) {
return new Stock(source);
}


public Stock[] newArray(int size) {
return new Stock[size];
}
};

public int describeContents() {
return 0;
}

//Serialize stock to Parcel
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(symbol);
parcel.writeDouble(maxPrice);
parcel.writeDouble(minPrice);
parcel.writeDouble(pricePaid);
parcel.writeInt(quantity);
parcel.writeDouble(currentPrice);
parcel.writeString(name);
}
//read values from the Parcel in the same order as you wrote them to the Parcel
//Deserialize stock from Parcel
public void readFromParcel(Parcel parcel){
symbol = parcel.readString();
maxPrice = parcel.readDouble();
minPrice = parcel.readDouble();
pricePaid = parcel.readDouble();
quantity = parcel.readInt();
currentPrice = parcel.readDouble();
name = parcel.readString();
}
}

create the StocksDb class:

/**
* A data access object for persisting and retrieving stock data. This uses
* a SQLite database for persistence and retrieval.
*/
public class StocksDb {
private static final String TAG = "StocksDb";
// database metadata
private static final String DB_NAME = "stocks.db";
private static final int DB_VERSION = 1;
private static final String TABLE_NAME = "stock";

// column names
private static final String ID = "id";
private static final String SYMBOL = "symbol";
private static final String MAX_PRICE = "max_price";
private static final String MIN_PRICE = "min_price";
private static final String PRICE_PAID = "price_paid";
private static final String QUANTITY = "quantity";
private static final String CURRENT_PRICE = "current_price";
private static final String NAME = "name";


// SQL statements
private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
" ("+ID+" INTEGER PRIMARY KEY, "+SYMBOL+" TEXT, "+
MAX_PRICE+" DECIMAL(8,2), " + MIN_PRICE+" DECIMAL(8,2), " +
PRICE_PAID+ " DECIMAL(8,2), " + QUANTITY + " INTEGER, " +
CURRENT_PRICE + " DECIMAL(8,2), "+NAME+" TEXT)";
private static final String INSERT_SQL = "INSERT INTO " + TABLE_NAME +
" ("+SYMBOL+", "+MAX_PRICE+", "+MIN_PRICE+", "+PRICE_PAID+
", "+QUANTITY+", " + CURRENT_PRICE+", "+NAME+") " +
"VALUES (?,?,?,?,?,?,?)";
private static final String READ_SQL = "SELECT "+ID+", "+SYMBOL+", " +
MAX_PRICE+", " + MIN_PRICE +", "+PRICE_PAID+", "+
QUANTITY+", " +CURRENT_PRICE+ ", "+NAME+" FROM " +
TABLE_NAME;
private static final String UPDATE_SQL = "UPDATE " + TABLE_NAME +
" SET "+CURRENT_PRICE+"=? WHERE "+ID+"=?";

// The Context object that created this StocksDb
private final Context context;
private final SQLiteOpenHelper helper;
private SQLiteStatement stmt;
private SQLiteStatement updateStmt;
private final SQLiteDatabase db;


/**
* Constructor that takes a Contex object, usually the
* Service or Activity that created this
* instance. This will initialize the SQLiteOpenHelper used for the
* database, and pre-compile the insert and update SQL statements.
*
* @param ctx The <code>Context</code> that created this instance
*/
public StocksDb(Context ctx){
context = ctx;

// initialize the database helper
helper = new SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION){
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
Log.d(TAG, "Created table: \n" + CREATE_TABLE);
}


@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
throw new UnsupportedOperationException();
}
};

// open the database
db = helper.getWritableDatabase();

// pre-compile statements
stmt = db.compileStatement(INSERT_SQL);
updateStmt = db.compileStatement(UPDATE_SQL);
}

/**
* Saves a <code>Stock</code> to the database.
*/
public Stock addStock(Stock stock){
Log.d(TAG, "Adding stock to db, stock="+stock);
stmt.bindString(1, stock.getSymbol());
stmt.bindDouble(2, stock.getMaxPrice());
stmt.bindDouble(3, stock.getMinPrice());
stmt.bindDouble(4, stock.getPricePaid());
stmt.bindLong(5, stock.getQuantity());
stmt.bindDouble(6, stock.getCurrentPrice());
stmt.bindString(7, stock.getName());
int id = (int) stmt.executeInsert();
return new Stock (stock, id);
}

/**
* Updates the current price of a <code>Stock</code> stored in the
* database.
*/
public void updateStockPrice(Stock stock){
Log.d(TAG, "Updating stock price in DB stock="+stock.toString());
updateStmt.bindDouble(1, stock.getCurrentPrice());
updateStmt.bindLong(2, stock.getId());
updateStmt.execute();
}

/**
* Retrieve all of the <code>Stock</code>s stored in the database.
*
* @return List of all of the Stocks stored in the database.
*/
public ArrayList<Stock> getStocks() {
Log.d(TAG, "Getting stocks form DB");
Cursor results = db.rawQuery(READ_SQL, null);
ArrayList<Stock> stocks = new ArrayList<Stock>(results.getCount());
if (results.moveToFirst()){
int idCol = results.getColumnIndex(ID);
int symbolCol = results.getColumnIndex(SYMBOL);
int maxCol = results.getColumnIndex(MAX_PRICE);
int minCol = results.getColumnIndex(MIN_PRICE);
int priceCol = results.getColumnIndex(PRICE_PAID);
int quanitytCol = results.getColumnIndex(QUANTITY);
int currentPriceCol = results.getColumnIndex(CURRENT_PRICE);
int nameCol = results.getColumnIndex(NAME);
do {
Stock stock = new Stock(results.getString(symbolCol),
results.getDouble(priceCol),
results.getInt(quanitytCol), results.getInt(idCol));
stock.setMaxPrice(results.getDouble(maxCol));
stock.setMinPrice(results.getDouble(minCol));
stock.setCurrentPrice(results.getDouble(currentPriceCol));
stock.setName(results.getString(nameCol));
Log.d(TAG, "Stock from db = " + stock.toString());
stocks.add(stock);
} while (results.moveToNext());
}
if (!results.isClosed()){
results.close();
}
return stocks;
}

/**
* Method to close the underlying database connection.
*/
public void close(){
helper.close();
}
}

Android IDL or AIDL.

create the Stock.aidl :

package example.stockportfolio;

parcelable Stock;

create theIStockService.aidl,The external interface into the stock portfolio service.

package example.stockportfolio.service;
import example.stockportfolio.Stock;
interface IStockService{
Stock addToPortfolio(in Stock stock);
List<Stock> getPortfolio();
}

you can only import other AIDL definitions.It only exposes two methods to the outside world.

A Java interface can be generated from the interface defined in the.aidl file.

Java interface generated from AIDL interface

public interface IStockService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder
implements com.flexware.stocks.service.IStockService
{
// generated code
}
public void addToPortfolio(com.flexware.stocks.Stock stock)
throws android.os.RemoteException;
public java.util.List<com.flexware.stocks.Stock> getPortfolio()
throws android.os.RemoteException;
}

......

You’llwant to extend this abstract class,stub implementing the IStockService methods.

change the background service classPortfolioManagerService

public class PortfolioManagerService extends Service {
//Helper class for persisted data
private final StocksDb db=new StocksDb(this);
/*
* 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
//subclass extends Binder.return.
return new IStockService.Stub() {
@Override
public List<Stock> getPortfolio() throws RemoteException {
// TODO Auto-generated method stub
return db.getStocks();
}
@Override
public Stock addToPortfolio(Stock stock) throws RemoteException {
return db.addStock(stock);
}
};
}
}

create the main activity classViewStocks

//The main Activity binding to and call the Service
public class ViewStocks extends ListActivity {
private static final String LOGGING_TAG = "ViewStocks";
// The list of stocks shown to the user
private ArrayList<Stock> stocks;
// Service used to persist and retrieve stocks
private IStockService stockService;
// Is the service bound currently?
private boolean bound = false;
// Connection to the stock service, handles lifecycle events
private ServiceConnection connection=new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
// TODO Auto-generated method stub
stockService=IStockService.Stub.asInterface(service);
Log.d(LOGGING_TAG,"Connected to service");
try {


//refresh();
stocks=(ArrayList<Stock>)stockService.getPortfolio();
if(stocks==null){
stocks=new ArrayList<Stock>(0);
Log.d(LOGGING_TAG, "No stocks returned from service");
}
else{
Log.d(LOGGING_TAG, "Got "+ stocks.size() +" stocks from service");
}
refresh();

} catch (RemoteException e) {
Log.e(LOGGING_TAG, "Exception retrieving portfolio from service",e);
}

}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
stockService=null;
}

};



@Override
public void onStart(){
super.onStart();
// create initial list
//bind to remote service
if(!bound){
bound=bindService(new Intent(ViewStocks.this,PortfolioManagerService.class),connection,Context.BIND_AUTO_CREATE);
Log.d(LOGGING_TAG, "Bound to service: " + bound);
}
if (!bound){
Log.e(LOGGING_TAG, "Failed to bind to service");
throw new RuntimeException("Failed to find to service");
}
this.setListAdapter(new BaseAdapter(){
@Override
public int getCount() {
// TODO Auto-generated method stub
if(stocks==null){
return 0;
}
return stocks.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
if(stocks==null){
return null;
}

return stocks.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
if(stocks==null){
return 0L;
}
return stocks.get(position).getId();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
if(convertView==null){
LayoutInflater inflater=getLayoutInflater();
convertView=inflater.inflate(R.layout.stock, parent,false);
}
TextView rowTxt=(TextView)convertView.findViewById(R.id.rowTxt);
rowTxt.setText(stocks.get(position).toString());
return convertView;
}
@Override
public boolean hasStableIds() {
return true;
}
});
}
@Override
public void onPause(){
super.onPause();
if(bound){
bound=false;
unbindService(connection);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
// Create UI elements, data loaded by <code>onStart</code>
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


// add widgets
final EditText symbolIn = (EditText) findViewById(R.id.inputSymbol);
final EditText maxIn = (EditText) findViewById(R.id.inputMax);
final EditText minIn = (EditText) findViewById(R.id.inputMin);
final EditText priceIn = (EditText) findViewById(R.id.inputPrice);
final EditText quantIn = (EditText) findViewById(R.id.inputQuant);

// Add event handler to button
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String symbol = symbolIn.getText().toString();
symbolIn.setText("");
double max = Double.parseDouble(maxIn.getText().toString());
maxIn.setText("");
double min = Double.parseDouble(minIn.getText().toString());
minIn.setText("");
double pricePaid = Double.parseDouble(priceIn.getText().toString());
priceIn.setText("");
int quantity = Integer.parseInt(quantIn.getText().toString());
quantIn.setText("");
Stock stock=new Stock(symbol,pricePaid,quantity);
stock.setMaxPrice(max);
stock.setMinPrice(min);
// Add stock to portfolio using service in the background
new AsyncTask<Stock,Void,Stock>(){
@Override
protected Stock doInBackground(Stock... newStocks) {
// TODO Auto-generated method stub
// There can be only one!
try{
return stockService.addToPortfolio(newStocks[0]);
} catch (RemoteException e) {
Log.e(LOGGING_TAG, "Exception adding stock " +"to portfolio", e);
}
return null;
}
@Override
protected void onPostExecute(Stock s){
Log.d(LOGGING_TAG, "Stock returned from service: " + s);
if (s == null){
Log.w(LOGGING_TAG, "Stock returned from Service " +
"was null or invalid");
Toast.makeText(ViewStocks.this, "Stock not found", Toast.LENGTH_SHORT);
} else {
refreshStockData();
}
}
}.execute(stock);
}

});
}

@Override
public void onDestroy(){
super.onDestroy();
// disconnect from the stock service
unbindService(connection);
}

//Refresh UI when data is retrieved
private void refresh(){
Log.d(LOGGING_TAG, "Refreshing UI with new data");
for (Stock s : stocks){
Log.d(LOGGING_TAG, "Got stock: " + s.toString());
}
BaseAdapter adapter=(BaseAdapter)this.getListAdapter();
adapter.notifyDataSetChanged();
}

//Update stock data from the service and refresh the UI
private void refreshStockData(){
if (stocks != null && stocks.size() > 0){
new AsyncTask<Void, Void, ArrayList<Stock>>(){
@Override
protected ArrayList<Stock> doInBackground(Void... nada){
try {
return (ArrayList<Stock>) stockService.getPortfolio();
} catch (Exception e) {
Log.e(LOGGING_TAG, "Exception getting stock data", e);
}
return null;
}

@Override
protected void onPostExecute(ArrayList<Stock> result) {
Log.d(LOGGING_TAG, "Got new stock data from service");
if (result != null){
stocks = result;
refresh();
} else {
Toast.makeText(ViewStocks.this, "Exception getting " +"latest stock data", Toast.LENGTH_SHORT);
}
}
}.execute();
}
}
}

at the same time,create the stock.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/rowTxt"
android:layout_width="wrap_content" />
</LinearLayout>

change the acitivity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|left">
<EditText
android:id="@+id/inputSymbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions"
android:hint="@string/hintSymbol"/>
<EditText
android:id="@+id/inputMin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:hint="@string/hintMin"/>
<EditText
android:id="@+id/inputMax"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:hint="@string/hintMax"
/>
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right">
<EditText
android:id="@+id/inputPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:hint="@string/hintPrice"/>

<EditText
android:id="@+id/inputQuant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="number"
android:hint="@string/hintQuant"/>
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btnLbl"/>
</LinearLayout>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>

change the strings.xml, add:

<string name="hintSymbol">Stock Symbol</string>
<string name="hintMin">Min. Price</string>
<string name="hintMax">Max Price</string>
<string name="hintPrice">Price Paid</string>
<string name="hintQuant">Quantity</string>
<string name="btnLbl">Add to Portfolio</string>
<string name="app_name">StockManager</string>
<string name="service_name">Stock Portfolio Service</string>

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. android横竖屏备忘
  2. Android(安卓)学习路线图
  3. Delphi XE开发 Android(安卓)开机自动启
  4. Android应用程序中执行二进制命令
  5. Android push 极光通信
  6. Android Animation 框架
  7. Android SDK: adb shell 命令的使用(am、p
  8. RTC搭建android下三层应用程序访问服务器
  9. Android 绑定数据到界面控件
  10. 转发---Android(安卓)DRM