[关闭]
@mSolo 2015-04-10T06:55:54.000000Z 字数 11113 阅读 3867

Android IPC/Binder Framework 实战(上)

Android IPC 框架 实战


笔记
https://thenewcircle.com/s/post/1340/Deep_Dive_Into_Binder_Presentation.htm

知识点

什么是 Binder ?

An IPC/component system for developing object-oriented OS services.
不支持 RPC

IPC 与 Intents 和 ContentProviders

Messenger IPC

代码示例

  1. public class DownloadClientActivity extends Activity {
  2. private static final int CALLBACK_MSG = 0;
  3. @Override
  4. public void onClick(View view) {
  5. Intent intent = new Intent("com.marakana.android.download.service.SERVICE");
  6. ArrayList<Uri> uris =
  7. intent.putExtra("uris", uris);
  8. Messenger messenger = new Messenger(new ClientHandler(this));
  9. intent.putExtra("callback-messenger", messenger);
  10. super.startService(intent);
  11. }
  12. private static class ClientHandler extends Handler {
  13. private final WeakReference<DownloadClientActivity> clientRef;
  14. public ClientHandler(DownloadClientActivity client) {
  15. this.clientRef = new WeakReference<DownloadClientActivity>(client);
  16. }
  17. @Override
  18. public void handleMessage(Message msg) {
  19. Bundle data = msg.getData();
  20. DownloadClientActivity client = clientRef.get();
  21. if (client != null && msg.what == CALLBACK_MSG && data != null) {
  22. Uri completedUri = data.getString("completed-uri");
  23. // client now knows that completedUri is done
  24. }
  25. }
  26. }
  27. }
  28. public class MessengerDemoService extends IntentService {
  29. private static final int CALLBACK_MSG = 0;
  30. @Override
  31. protected void onHandleIntent(Intent intent) {
  32. ArrayList<Uri> uris = intent.getParcelableArrayListExtra("uris");
  33. Messenger messenger = intent.getParcelableExtra("callback-messenger");
  34. for (Uri uri : uris) {
  35. // download the uri
  36. if (messenger != null) {
  37. Message message = Message.obtain();
  38. message.what = CALLBACK_MSG;
  39. Bundle data = new Bundle(1);
  40. data.putParcelable("completed-uri", uri);
  41. message.setData(data);
  42. try {
  43. messenger.send(message);
  44. } catch (RemoteException e) {
  45. } finally {
  46. message.recycle();
  47. }
  48. }
  49. }
  50. }
  51. }

Binder Terminology

AIDL

Android Interface Definition Language is a Android-specific language for defining Binder-based service interfaces

src/com/example/app/IFooService.aidl

  1. package com.example.app;
  2. import com.example.app.Bar;
  3. interface IFooService {
  4. void save(inout Bar bar);
  5. Bar getById(int id);
  6. void delete(in Bar bar);
  7. List<Bar> getAll();
  8. }

Binder Object Reference

命令

$ adb shell service list

实战

https://github.com/mSoloYu/StockQuoteDemo.git

  1. // IStockQuoteService.aidl
  2. package com.stockquote.example;
  3. // Declare any non-default types here with import statements
  4. import com.stockquote.example.StockQuoteRequest;
  5. import com.stockquote.example.StockQuoteResponse;
  6. interface IStockQuoteService {
  7. StockQuoteResponse retrieveStockQuote(in StockQuoteRequest request);
  8. }
  9. // StockQuoteResponse.aidl
  10. package com.stockquote.example;pp
  11. Parcelable StockQuoteResponse;
  12. // StockQuoteResponse.java
  13. public class StockQuoteResponse implements Parcelable {
  14. private final StockQuote mResult;
  15. public StockQuoteResponse(StockQuote result) {
  16. mResult = result;
  17. }
  18. public StockQuote getResult() {
  19. return mResult;
  20. }
  21. public int describeContents() {
  22. return 0;
  23. }
  24. public void writeToParcel(Parcel parcel, int flags) {
  25. parcel.writeSerializable(mResult);
  26. }
  27. public static final Parcelable.Creator<StockQuoteResponse> CREATOR
  28. = new Parcelable.Creator<StockQuoteResponse>() {
  29. public StockQuoteResponse createFromParcel(Parcel in) {
  30. return new StockQuoteResponse((StockQuote)in.readSerializable());
  31. }
  32. public StockQuoteResponse[] newArray(int size) {
  33. return new StockQuoteResponse[size];
  34. }
  35. };
  36. }
  1. <service android:name="com.stockquote.server.StockQuoteService">
  2. <intent-filter>
  3. <action android:name="com.stockquote.example.IStockQuoteService" />
  4. </intent-filter>
  5. </service>
  1. // StockQuoteServiceImpl.java
  2. public class StockQuoteServiceImpl extends IStockQuoteService.Stub {
  3. private static final String TAG = "StockQuoteServiceImpl";
  4. @Override
  5. public StockQuoteResponse retrieveStockQuote(StockQuoteRequest request)
  6. throws RemoteException {
  7. String[] stockIdArray = null;
  8. if (request.getType() == StockQuoteRequest.Type.STOCKQUOTE_MULTIPLE) {
  9. stockIdArray = request.getStockIdArray();
  10. } else {
  11. return null;
  12. }
  13. StockQuote stockQuote = StockNetResourceManager.getInstance()
  14. .setUpStockQuotes(stockIdArray);
  15. return new StockQuoteResponse(stockQuote);
  16. }
  17. }
  18. // StockQuoteService
  19. public class StockQuoteService extends Service {
  20. private static final String TAG = "StockQuoteService";
  21. private StockQuoteServiceImpl mService;
  22. @Override
  23. public void onCreate() {
  24. super.onCreate();
  25. mService = new StockQuoteServiceImpl();
  26. }
  27. @Override
  28. public IBinder onBind(Intent intent) {
  29. return mService;
  30. }
  31. @Override
  32. public boolean onUnbind(Intent intent) {
  33. return super.onUnbind(intent);
  34. }
  35. @Override
  36. public void onDestroy() {
  37. mService = null;
  38. super.onDestroy();
  39. }
  40. }
  41. // StockNetResourceManager.java
  42. public class StockNetResourceManager {
  43. private static final String URL_STOCK_REC = "http://hq.sinajs.cn/list=";
  44. private static final StockNetResourceManager INSTANCE = new StockNetResourceManager();
  45. private final OkHttpClient client = new OkHttpClient();
  46. private StockNetResourceManager() {
  47. }
  48. public static StockNetResourceManager getInstance() {
  49. return INSTANCE;
  50. }
  51. public StockQuote setUpStockQuotes(String[] stockIds) {
  52. StringBuilder stockRecUrl = new StringBuilder(URL_STOCK_REC);
  53. for (String stockId : stockIds) {
  54. makeRealStockId(stockId, stockRecUrl);
  55. stockRecUrl.append(",");
  56. }
  57. stockRecUrl.deleteCharAt(stockRecUrl.length() - 1);
  58. Request request = new Request.Builder().url(stockRecUrl.toString()).build();
  59. try {
  60. return cookStockQuote(client.newCall(request).execute().body().string());
  61. } catch (IOException e) {
  62. e.printStackTrace();
  63. }
  64. return null;
  65. }
  66. public StockQuote cookStockQuote(String rawRecs) {
  67. // var hq_str_sz002024="苏宁云商,11.26,11.22,11.33,11.45,11.17,11.33,11.34,131241390,1484755809.02,
  68. // 153559,11.33,358350,11.32,396400,11.31,654870,11.30,151700,11.29,420400,11.34,315415,11.35,170927,11.36,202600,11.37,111001,11.38,
  69. // 2015-03-13,15:05:53,00";
  70. // name,open,lastClose,current,highest,lowest,close,**,vol(手),money(元),
  71. // after split, the related index will be :
  72. String[] stockRecItemArray = rawRecs.split(",");
  73. String name = stockRecItemArray[0].split("\"")[1];
  74. // hanlde suspend day
  75. if (stockRecItemArray[1].startsWith("0.000")) {
  76. return new StockQuote(StockQuote.EVEN_COLOR, name, stockRecItemArray[3],
  77. stockRecItemArray[3], stockRecItemArray[3], "+0.00", "+0.00%");
  78. }
  79. String lastPriceStr = stockRecItemArray[2];
  80. String curPriceStr = stockRecItemArray[3];
  81. int lastPrice = Integer.parseInt(lastPriceStr.replace(".", ""));
  82. int curPrice = Integer.parseInt(curPriceStr.replace(".", ""));
  83. int priceColor = StockQuote.EVEN_COLOR;
  84. if (curPrice > lastPrice) {
  85. priceColor = StockQuote.RISE_COLOR;
  86. } else if (curPrice < lastPrice) {
  87. priceColor = StockQuote.DOWN_COLOR;
  88. }
  89. float dividerForGap = 100.00f;
  90. float divider = 100.00f;
  91. if (name.startsWith("上证指数") || name.startsWith("深证成指")) {
  92. dividerForGap = 1000.00f;
  93. stockRecItemArray[3] = stockRecItemArray[3].substring(0, stockRecItemArray[3].length() - 1);
  94. stockRecItemArray[4] = stockRecItemArray[4].substring(0, stockRecItemArray[4].length() - 1);
  95. stockRecItemArray[5] = stockRecItemArray[5].substring(0, stockRecItemArray[5].length() - 1);
  96. }
  97. String priceGap = String.format("%+.2f", (curPrice - lastPrice)/dividerForGap);
  98. String percentage = String.format("%+.2f%%", (curPrice - lastPrice) * divider/lastPrice);
  99. return new StockQuote(priceColor, name, stockRecItemArray[3],
  100. stockRecItemArray[4], stockRecItemArray[5], priceGap, percentage);
  101. }
  102. private void makeRealStockId(String stockId, StringBuilder realStockIdBuilder) {
  103. if (stockId.startsWith("sh") || stockId.startsWith("sz")) {
  104. realStockIdBuilder.append(stockId);
  105. return ;
  106. }
  107. if (stockId.startsWith("600") || stockId.startsWith("601")) {
  108. realStockIdBuilder.append("sh").append(stockId);
  109. } else {
  110. realStockIdBuilder.append("sz").append(stockId);
  111. }
  112. }
  113. }
  1. public class MainActivity extends Activity
  2. implements ServiceConnection {
  3. private static final String TAG = "MainActivity";
  4. private TextView mNameTv;
  5. private TextView mQuoteTv;
  6. private IStockQuoteService mService;
  7. @Override
  8. protected void onCreate(Bundle savedBundle) {
  9. super.onCreate(savedBundle);
  10. setContentView(R.layout.main);
  11. mNameTv = (TextView) findViewById(R.id.name);
  12. mQuoteTv = (TextView) findViewById(R.id.quote);
  13. }
  14. @Override
  15. protected void onResume() {
  16. super.onResume();
  17. if (!super.bindService(new Intent(IStockQuoteService.class.getName()),
  18. this, BIND_AUTO_CREATE)) {
  19. }
  20. }
  21. @Override
  22. protected void onPause() {
  23. super.onPause();
  24. super.unbindService(this);
  25. }
  26. public void onServiceConnected(ComponentName name, IBinder service) {
  27. mService = IStockQuoteService.Stub.asInterface(service);
  28. setText();
  29. }
  30. public void onServiceDisconnected(ComponentName name) {
  31. mService = null;
  32. }
  33. private void setText() {
  34. final StockQuoteRequest request = new StockQuoteRequest(null,
  35. new String[]{"002024"}, StockQuoteRequest.Type.STOCKQUOTE_MULTIPLE);
  36. final ProgressDialog dialog = ProgressDialog.show(this, "",
  37. "正在获取...", true);
  38. new AsyncTask<Void, Void, StockQuote>() {
  39. @Override
  40. protected StockQuote doInBackground(Void... params) {
  41. try {
  42. StockQuoteResponse response = mService.retrieveStockQuote(request);
  43. dialog.dismiss();
  44. return response.getResult();
  45. } catch (RemoteException e) {
  46. Log.wtf(TAG, "Failed to communicate with the service", e);
  47. dialog.dismiss();
  48. return null;
  49. }
  50. }
  51. @Override
  52. protected void onPostExecute(StockQuote result) {
  53. dialog.dismiss();
  54. if (result == null) {
  55. Toast.makeText(MainActivity.this, "获取失败",
  56. Toast.LENGTH_LONG).show();
  57. } else {
  58. mNameTv.setText(result.getStockName());
  59. mQuoteTv.setText(result.getStockPrice());
  60. }
  61. }
  62. }.execute();
  63. }
  64. }
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:orientation="vertical" android:layout_width="match_parent"
  3. android:layout_height="match_parent">
  4. <TextView
  5. android:id="@+id/name"
  6. android:gravity="center_horizontal|center_vertical"
  7. android:layout_weight="1"
  8. android:layout_width="match_parent"
  9. android:layout_height="0dp" />
  10. <TextView
  11. android:id="@+id/quote"
  12. android:gravity="center_horizontal|center_vertical"
  13. android:layout_weight="1"
  14. android:layout_width="match_parent"
  15. android:layout_height="0dp" />
  16. </LinearLayout>
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注