ps:閱讀本文 須要對android 多進程編程有必定了解。html
1.Android中總共有幾種方式進行IPC?java
答:一共有兩種,一種是binder 還有一種是socket。Binder 你們用的比較多。Socket不多有人用,這裏給出一個利用Socket進行ipc通訊的例子。android
服務端代碼:編程
1 package com.example.administrator.socketipcdemo; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.os.IBinder; 6 import android.util.Log; 7 8 import java.io.BufferedReader; 9 import java.io.BufferedWriter; 10 import java.io.IOException; 11 import java.io.InputStreamReader; 12 import java.io.OutputStreamWriter; 13 import java.io.PrintWriter; 14 import java.net.ServerSocket; 15 import java.net.Socket; 16 17 public class ServerService extends Service { 18 19 public static final int SERVER_PORT_NUMBER = 5678; 20 private boolean mServiceDestroyed = false; 21 22 @Override 23 public void onCreate() { 24 new Thread(new ServerRunnable()).start(); 25 super.onCreate(); 26 } 27 28 @Override 29 public void onDestroy() { 30 mServiceDestroyed = true; 31 super.onDestroy(); 32 } 33 34 public ServerService() { 35 } 36 37 @Override 38 public IBinder onBind(Intent intent) { 39 // TODO: Return the communication channel to the service. 40 throw new UnsupportedOperationException("Not yet implemented"); 41 } 42 43 //這個線程 用於監聽端口號 44 class ServerRunnable implements Runnable { 45 @Override 46 public void run() { 47 48 ServerSocket serverSocket = null; 49 try { 50 serverSocket = new ServerSocket(SERVER_PORT_NUMBER); 51 } catch (IOException e) { 52 e.printStackTrace(); 53 } 54 while (!mServiceDestroyed) { 55 try { 56 final Socket client = serverSocket.accept(); 57 new Thread() { 58 @Override 59 public void run() { 60 try { 61 responseClientRequest(client); 62 } catch (IOException e) { 63 e.printStackTrace(); 64 } 65 } 66 }.start(); 67 68 } catch (IOException e) { 69 e.printStackTrace(); 70 } 71 } 72 } 73 } 74 75 private void responseClientRequest(Socket client) throws IOException { 76 BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); 77 PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true); 78 while (!mServiceDestroyed) { 79 String str = in.readLine(); 80 if (str == null) { 81 break; 82 } 83 String reponseStr = "我是服務器端,我收到了來自客戶端的消息:" + str; 84 out.println(reponseStr); 85 } 86 out.close(); 87 in.close(); 88 client.close(); 89 } 90 }
客戶端代碼:緩存
1 package com.example.administrator.socketipcdemo; 2 3 import android.content.Intent; 4 import android.os.Bundle; 5 import android.os.SystemClock; 6 import android.support.design.widget.FloatingActionButton; 7 import android.support.design.widget.Snackbar; 8 import android.support.v7.app.AppCompatActivity; 9 import android.support.v7.widget.Toolbar; 10 import android.util.Log; 11 import android.view.View; 12 import android.view.Menu; 13 import android.view.MenuItem; 14 import android.widget.Button; 15 import android.widget.EditText; 16 import android.widget.TextView; 17 import android.widget.Toast; 18 19 import java.io.BufferedReader; 20 import java.io.BufferedWriter; 21 import java.io.IOException; 22 import java.io.InputStreamReader; 23 import java.io.OutputStreamWriter; 24 import java.io.PrintWriter; 25 import java.net.Socket; 26 27 public class MainActivity extends AppCompatActivity { 28 29 private Button bt, bt2; 30 private TextView tv; 31 private EditText et; 32 33 private Socket socket; 34 private PrintWriter mPrintWriter; 35 36 37 @Override 38 protected void onCreate(Bundle savedInstanceState) { 39 super.onCreate(savedInstanceState); 40 setContentView(R.layout.activity_main); 41 Intent intent = new Intent(this, ServerService.class); 42 startService(intent); 43 tv = (TextView) findViewById(R.id.tv); 44 et = (EditText) findViewById(R.id.et); 45 bt = (Button) this.findViewById(R.id.bt); 46 bt.setOnClickListener(new View.OnClickListener() { 47 @Override 48 public void onClick(View v) { 49 new Thread() { 50 @Override 51 public void run() { 52 tryToLinkServer(); 53 } 54 }.start(); 55 56 } 57 }); 58 59 bt2 = (Button) this.findViewById(R.id.bt2); 60 bt2.setOnClickListener(new View.OnClickListener() { 61 @Override 62 public void onClick(View v) { 63 sendMessageToServer(et.getText().toString()); 64 } 65 }); 66 67 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 68 setSupportActionBar(toolbar); 69 70 FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 71 fab.setOnClickListener(new View.OnClickListener() { 72 @Override 73 public void onClick(View view) { 74 Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 75 .setAction("Action", null).show(); 76 } 77 }); 78 } 79 80 @Override 81 protected void onDestroy() { 82 if(socket!=null) 83 { 84 try { 85 socket.shutdownInput(); 86 socket.close(); 87 } catch (IOException e) { 88 e.printStackTrace(); 89 } 90 } 91 super.onDestroy(); 92 } 93 94 @Override 95 public boolean onCreateOptionsMenu(Menu menu) { 96 // Inflate the menu; this adds items to the action bar if it is present. 97 getMenuInflater().inflate(R.menu.menu_main, menu); 98 return true; 99 } 100 101 @Override 102 public boolean onOptionsItemSelected(MenuItem item) { 103 // Handle action bar item clicks here. The action bar will 104 // automatically handle clicks on the Home/Up button, so long 105 // as you specify a parent activity in AndroidManifest.xml. 106 int id = item.getItemId(); 107 108 //noinspection SimplifiableIfStatement 109 if (id == R.id.action_settings) { 110 return true; 111 } 112 113 return super.onOptionsItemSelected(item); 114 } 115 116 private void sendMessageToServer(final String str) { 117 if (mPrintWriter != null) { 118 mPrintWriter.println(str); 119 } 120 } 121 122 123 private void tryToLinkServer() { 124 while (socket == null) { 125 try { 126 socket = new Socket("localhost", ServerService.SERVER_PORT_NUMBER); 127 mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); 128 } catch (IOException e) { 129 //每次連不上就等待1秒再從新連 130 SystemClock.sleep(1000); 131 e.printStackTrace(); 132 } 133 } 134 runOnUiThread(new Runnable() { 135 @Override 136 public void run() { 137 Toast.makeText(MainActivity.this, "和服務器進程成功連接", Toast.LENGTH_SHORT).show(); 138 } 139 }); 140 try { 141 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); 142 while (!MainActivity.this.isFinishing()) { 143 final String msg = br.readLine(); 144 runOnUiThread(new Runnable() { 145 @Override 146 public void run() { 147 tv.setText(msg); 148 } 149 }); 150 } 151 mPrintWriter.close(); 152 br.close(); 153 socket.close(); 154 } catch (IOException e) { 155 e.printStackTrace(); 156 } 157 } 158 159 160 }
最後看一下運行效果:安全
2.android:process 屬性值的書寫有什麼講究?服務器
答::remote 這種寫法 其實就等於 包名:remote 並且這種寫法 屬於當前app的私有進程, 其餘app 不能夠和這個進程跑在一塊兒的。網絡
若是是直接 把android:process 寫成字符串形式的話, 那這種進程就是全局進程了,誰均可以用。哪怕是其餘app 只要是shareUid同樣app
就能夠和這個進程跑在一塊兒。固然了,簽名也必須同樣!dom
3.多進程編程的時候 咱們須要注意哪些坑?
答:必定要記住 多進程的時候 實際上 一個進程就是一個虛擬機,因此 會引起以下幾個問題:
a:全部靜態變量和單例模式之類的 所有沒用了。由於你多進程麼,假設你的app代碼裏面 開啓了2個進程,同時你的代碼裏面 有一個靜態變量,這個時候注意 你的靜態變量雖然在代碼裏只有一份,
可是此時是2個進程在跑 ,有2個虛擬機,因此你這個靜態變量也是會變成兩份的!
b:SharedPreferences 會失去同步效果。由於sp這個東西 大家看下源碼就知道了,實際上他的底層就是個xml。。。而且android 對這個xml的讀寫本身弄了一套緩存,注意這個緩存是運行在內存中的,
因此你就知道 一旦多個進程的話,這個緩存就是多份了。。。。因此記住 不要在多進程裏面使用sp
c:Application 會建立屢次。這個大家打下log就知道了,因此若是大家application 有特殊處理的話 記得考慮下多進程的狀況。
上面3個是咱們須要注意的點,其實也很好理解,對於同一個app的 多個進程來講 ,他就等於 多個app 在運行,只不過這些app的uid和簽名都同樣!你想明白這點 就懂了android 多進程了。
4.android中有哪幾種序列化方式?分別要注意什麼?
答:兩種。Serializable和Parcelable
Serializable:這種方式 就是要注意serialVersionUID,通常ide 給你生成的值 都是根據你class的結構來作的,假設你在版本1.0.1 裏面 建立了class A,而且序列化了一個對象a 在sd卡里。
過了一段時間 你在1.0.2 版本里 把A的代碼 改了不少,此時ide 會把你的serialVersionUID 值也隨之改掉。那若是你在1.0.2版本里 還想反序列化這個對象a的話 就會出錯了。
因此serialVersionUID 就是一個記錄class 版本號的標示,咱們最好仍是把他寫死。。。。這樣不會影響咱們的客戶端。此外 transient 這個標記的變量也不會被序列化。
Parcelable:write方法就是序列化的時候 執行的方法 creator 就是反序列化的過程。Intent bundle bitmap 都實現了這個接口。List Map 也能夠序列化 提早是 元素是這個接口對象。
二者基本上是差很少的,只不過Parcelable效率更高,通常在內存中使用時 咱們用Parcelable,若是是 序列化到本地或者網絡 這種流裏的時候 咱們就用Serializable 由於比較方便。
5.當遇到一個數據 沒法放在Bundle裏時,如何進行進程間通信?
答:假設咱們有一個需求,讓A進程 計算一個東西之後 把 結果 result 傳遞給B進程。可是這個result結果 沒有實現Parcelable 接口也沒法放在bundle裏。此時 該如何傳遞這個result到B?
其實可讓A進程 啓動B進程 的一個intentService。讓這個service 去計算出來這個結果result,這時候 咱們會發現 此時這個service和b進程 在一個進程裏。 result固然就隨便傳遞了。不須要ipc來傳遞
6.Messenger 使用時,要注意哪些,他的原理是什麼?
答:原理的話 其實看一下 源碼就知道了:
1 /** 2 * Create a Messenger from a raw IBinder, which had previously been 3 * retrieved with {@link #getBinder}. 4 * 5 * @param target The IBinder this Messenger should communicate with. 6 */ 7 public Messenger(IBinder target) { 8 mTarget = IMessenger.Stub.asInterface(target); 9 }
一看到這個代碼咱們就明白 原理就是AIDL麼。要注意的話 就是Messenger只能用於單向通訊,不能用於雙向的 。若是你要用雙向通訊而且還要用Messenger來完成的話 就必須用2個Messenger。
Messenger傳遞對象就是傳遞的Message對象。其中咱們注意了,在進程通訊的時候,Message裏的object 字段 只能傳遞 系統的parceable對象。也就是intent bitmap 這種系統本身實現的parceable接口對象。
若是是咱們本身寫的parceable 是沒法放在object裏面 用於進程通訊的,若是你要用,請放在bundle裏。此外Messenger 在內部 是串行處理請求的,大量消息 一塊兒發給服務端這種業務模型
最好就別用Messenger了。直接本身寫一個AIDL 最合適。
7.使用AIDL的時候 有哪些注意事項?
答:有下面幾個注意事項:
a:aidl文件裏不是全部數據類型均可以使用。只支持 基本數據類型,string,charSequence,List(只支持ArrayList,且裏面的元素都能被AIDL支持),Map(只支持hashMap,而且元素必須是AIDL支持的),Parcelable,AIDL本身。
b:自定義的parceable對象要在aidl中 import 進來。而且自定義的parceable 要在aidl裏 也額外聲明一下,具體的看我前面的那篇blog便可。
c:aidl 裏面只能寫方法 不能寫靜態常量。
8.in out inout 這三個參數 在aidl 到底有啥用,不寫有什麼危害麼?
答:據我觀察 你不寫其實沒什麼危害,可是你寫明白了 傳輸效率會增長。其實這3個參數很好理解,簡單創建一個方法模型:
假設你的aidl文件裏有一個方法 void addPerson(Person person),這方法一看 就是客戶端傳一個person 到服務端 因此這個地方參數就是in。
若是你有一個方法叫 void getList(List a) 你看這個方法 就是把服務端的list 傳遞給這個參數a的list 那你就把參數寫成out便可。
inout 就更好理解了,實際就是 void modifyList(List b),意思就是 先把b 這個list 傳遞給服務端,而後還要修改這個list。
9.CopyOnWriteArrayList 能夠在aidl中使用嗎?爲何?
答:可使用。
1 public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
雖然看聲明 他並無實現Parceable這個接口。也不是ArrayList的子類,但實際上AIDL支持的是抽象的List,因此在底層的時候 Binder 會把CopyOnWriteArrayList
轉換成ArrayList 傳遞給客戶端的。ConcurrentHashMap 也是同樣。
10.Android 進程通訊時候 能傳遞對象嗎?
答:嚴格意義上 是不能的,實際上binder 會把客戶端傳遞過來的對象 從新轉換爲一個新的對象 傳遞給服務端。對象的跨進程傳輸 本質上就是序列化和反序列化的過程。
11.RemoteCallBackList 幹嗎的?使用時注意哪些?
答:具體可看http://www.cnblogs.com/punkisnotdead/p/5158016.html。 實際上這個東西講明白了 就是用於 android中管理 跨進程listener接口的。
你想明白這個道理 就都懂了。並且他特別方便的是,客戶端進程終止之後 他能夠自動刪除listenr。使用注意點就是begin和finish要成對出現。就算你是遍歷listenrer操做
也要用這2個方法
12.aidl運行時的 線程模型?
答:http://www.cnblogs.com/punkisnotdead/p/5163464.html 這篇分析binder代碼的時候 已經講的很清楚了。這裏再總結一次。
client 調用 server的方法a,client自己是會掛起的, 會一直等待server的方法a的 執行結果。
同時這個方法a 是運行在binder線程池中,因此server的方法 能夠執行耗時操做。只不過 client調用的server方法時
注意不要在ui線程裏調用,否則會anr的。同時若是你的業務是 一個server 多種client ,那你的server端 方法 要支持同步,否則會數據錯亂的!
13.服務端 調用 客戶端listener 方法有什麼講究?
答:實際上 和12問題是同樣的,server 想調用 client的方法b,b也是會執行在 client所屬進程的 binder線程池內的。同時咱們也要避免 若是方法b執行時間很長,
記得server調用的時候 不要在主線程裏調用。此外咱們通常client 都是在activity裏,記得 listener調用的方法 若是涉及到ui,請用handler切換到ui線程來作。
14.如何作權限認證?
答:兩種方法,能夠在onBind裏 檢查權限,也能夠在server的onTransact裏驗證,驗證失敗返回false便可。後者方法更好 還能夠驗證uid pid等 能夠支持複雜的多進程業務模型,
尤爲是安全相關的。
15.一個aidl 就必須對應一個service嗎?多種aidl 是否是隻能多個service?
答:不是的,aidl 只不過是幫你書寫binder用的工具,你固然能夠只啓動一個service 可是對應多個binder。要知道 service 資源是有限的 假設你app複雜 10個業務 開啓10個service
那不是就亂套了。徹底能夠只開啓一個service 可是這一個service 能夠控制多種aidl 對應的binder,你要用哪一個 就取那個binder 便可。
下面給出實例。
首先看一下 代碼結構和運行效果,實際上就是一個加法binder 和一個乘法binder 只不過 這2個binder 都由一個service來控制而已。
而後來看一下加法和乘法的 aidl以及對應的binder 對象:
1 // IAddition.aidl 2 package com.example.administrator.bindermanager; 3 4 // Declare any non-default types here with import statements 5 6 interface IAddition { 7 8 int add(int a,int b); 9 }
1 package com.example.administrator.bindermanager; 2 3 import android.os.RemoteException; 4 5 /** 6 * Created by Administrator on 2016/1/29. 7 */ 8 public class AdditionImpl extends IAddition.Stub { 9 @Override 10 public int add(int a, int b) throws RemoteException { 11 return a + b; 12 } 13 }
1 // IMultiplication.aidl 2 package com.example.administrator.bindermanager; 3 4 // Declare any non-default types here with import statements 5 6 interface IMultiplication { 7 8 int multip(int a,int b); 9 }
1 package com.example.administrator.bindermanager; 2 3 import android.os.RemoteException; 4 5 /** 6 * Created by Administrator on 2016/1/29. 7 */ 8 public class MultiplicationImpl extends IMultiplication.Stub { 9 @Override 10 public int multip(int a, int b) throws RemoteException { 11 return a * b; 12 } 13 }
而後看看咱們最爲關鍵的binder manger 如何設計:
1 // IBinderManger.aidl 2 package com.example.administrator.bindermanager; 3 4 // Declare any non-default types here with import statements 5 6 interface IBinderManger { 7 IBinder queryBinder(int binderCode); 8 }
1 package com.example.administrator.bindermanager; 2 3 import android.os.IBinder; 4 import android.os.RemoteException; 5 import android.util.Log; 6 7 /** 8 * Created by Administrator on 2016/1/29. 9 */ 10 public class BinderMangerImpl extends IBinderManger.Stub { 11 12 public BinderMangerImpl() { 13 super(); 14 } 15 16 @Override 17 public IBinder queryBinder(int binderCode) throws RemoteException { 18 IBinder binder = null; 19 switch (binderCode) { 20 case BinderManger.BINDER_ADDITION: 21 binder = new AdditionImpl(); 22 break; 23 case BinderManger.BINDER_MULTIPLICATION: 24 binder = new MultiplicationImpl(); 25 break; 26 default: 27 break; 28 } 29 return binder; 30 } 31 }
1 package com.example.administrator.bindermanager; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.os.Binder; 6 import android.os.IBinder; 7 import android.util.Log; 8 9 public class BinderMangerService extends Service { 10 11 private IBinder mBinderManger = new BinderMangerImpl(); 12 13 public BinderMangerService() { 14 } 15 16 @Override 17 public IBinder onBind(Intent intent) { 18 return mBinderManger; 19 } 20 }
1 package com.example.administrator.bindermanager; 2 3 import android.content.ComponentName; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.content.ServiceConnection; 7 import android.os.IBinder; 8 import android.os.RemoteException; 9 10 /** 11 * Created by Administrator on 2016/1/29. 12 */ 13 public class BinderManger { 14 15 public static final int BINDER_ADDITION = 0; 16 public static final int BINDER_MULTIPLICATION = 1; 17 private Context mContext; 18 private IBinderManger mBinderManger; 19 private static BinderManger sInstance; 20 21 private BinderManger(Context mContext) { 22 this.mContext = mContext.getApplicationContext(); 23 connectBinderService(); 24 } 25 26 public static BinderManger getInstance(Context context) { 27 if (sInstance == null) { 28 sInstance = new BinderManger(context); 29 } 30 return sInstance; 31 } 32 33 34 private synchronized void connectBinderService() { 35 Intent service = new Intent(mContext, BinderMangerService.class); 36 mContext.bindService(service, mServiceConnection, Context.BIND_AUTO_CREATE); 37 } 38 39 private ServiceConnection mServiceConnection = new ServiceConnection() { 40 @Override 41 public void onServiceConnected(ComponentName name, IBinder service) { 42 mBinderManger = IBinderManger.Stub.asInterface(service); 43 } 44 45 @Override 46 public void onServiceDisconnected(ComponentName name) { 47 48 } 49 }; 50 51 public IBinder queryBinder(int binderCode) throws RemoteException { 52 IBinder binder = null; 53 binder = mBinderManger.queryBinder(binderCode); 54 return binder; 55 } 56 }
最後看一下 咱們的clinet端:
1 package com.example.administrator.bindermanager; 2 3 import android.os.Bundle; 4 import android.os.RemoteException; 5 import android.support.design.widget.FloatingActionButton; 6 import android.support.design.widget.Snackbar; 7 import android.support.v7.app.AppCompatActivity; 8 import android.support.v7.widget.Toolbar; 9 import android.view.View; 10 import android.view.Menu; 11 import android.view.MenuItem; 12 import android.widget.Button; 13 import android.widget.EditText; 14 import android.widget.TextView; 15 16 import org.w3c.dom.Text; 17 18 public class MainActivity extends AppCompatActivity { 19 20 private Button bt, bt2, bt3; 21 private EditText et1, et2; 22 private TextView tv; 23 private BinderManger binderManger; 24 25 @Override 26 protected void onCreate(Bundle savedInstanceState) { 27 super.onCreate(savedInstanceState); 28 setContentView(R.layout.activity_main); 29 tv = (TextView) findViewById(R.id.tv2); 30 et1 = (EditText) findViewById(R.id.et); 31 et2 = (EditText) findViewById(R.id.et2); 32 bt = (Button) this.findViewById(R.id.bt); 33 bt.setOnClickListener(new View.OnClickListener() { 34 35 @Override 36 public void onClick(View v) { 37 binderManger = BinderManger.getInstance(MainActivity.this); 38 } 39 }); 40 41 bt2 = (Button) this.findViewById(R.id.bt2); 42 bt2.setOnClickListener(new View.OnClickListener() { 43 44 @Override 45 public void onClick(View v) { 46 try { 47 final IMultiplication multiplicationImpl = 48 (IMultiplication) MultiplicationImpl.asInterface(binderManger.queryBinder(BinderManger.BINDER_MULTIPLICATION)); 49 50 runOnUiThread(new Runnable() { 51 @Override 52 public void run() { 53 try { 54 tv.setText(multiplicationImpl.multip(Integer.parseInt(et1.getText().toString()), Integer.parseInt(et2.getText().toString())) + ""); 55 } catch (RemoteException e) { 56 e.printStackTrace(); 57 } 58 } 59 }); 60 61 } catch (RemoteException e) { 62 e.printStackTrace(); 63 } 64 } 65 }); 66 67 bt3 = (Button) this.findViewById(R.id.bt3); 68 bt3.setOnClickListener(new View.OnClickListener() { 69 70 @Override 71 public void onClick(View v) { 72 try { 73 final IAddition additionImpl = 74 (IAddition) AdditionImpl.asInterface(binderManger.queryBinder(BinderManger.BINDER_ADDITION)); 75 runOnUiThread(new Runnable() { 76 @Override 77 public void run() { 78 try { 79 tv.setText(additionImpl.add(Integer.parseInt(et1.getText().toString()), Integer.parseInt(et2.getText().toString())) + ""); 80 } catch (RemoteException e) { 81 e.printStackTrace(); 82 } 83 } 84 }); 85 86 } catch (RemoteException e) { 87 e.printStackTrace(); 88 } 89 } 90 }); 91 92 93 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 94 setSupportActionBar(toolbar); 95 96 FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 97 fab.setOnClickListener(new View.OnClickListener() { 98 @Override 99 public void onClick(View view) { 100 Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 101 .setAction("Action", null).show(); 102 } 103 }); 104 } 105 106 @Override 107 public boolean onCreateOptionsMenu(Menu menu) { 108 // Inflate the menu; this adds items to the action bar if it is present. 109 getMenuInflater().inflate(R.menu.menu_main, menu); 110 return true; 111 } 112 113 @Override 114 public boolean onOptionsItemSelected(MenuItem item) { 115 // Handle action bar item clicks here. The action bar will 116 // automatically handle clicks on the Home/Up button, so long 117 // as you specify a parent activity in AndroidManifest.xml. 118 int id = item.getItemId(); 119 120 //noinspection SimplifiableIfStatement 121 if (id == R.id.action_settings) { 122 return true; 123 } 124 125 return super.onOptionsItemSelected(item); 126 } 127 }