Android 多进程编程 15问15答!

ps:阅读本文 需要对android 多进程编程有一定了解。

1.Android中总共有几种方式进行IPC?

答:一共有两种,一种是binder 还有一种是socket。Binder 大家用的比较多。Socket很少有人用,这里给出一个利用Socket进行ipc通信的例子。

服务端代码:

 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一样

就可以和这个进程跑在一起。当然了,签名也必须一样!

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 }

时间: 2024-10-29 19:07:34

Android 多进程编程 15问15答!的相关文章

Android 线程与消息 机制 15问15答

1.handler,looper,messagequeue三者之间的关系以及各自的角色? 答:MessageQueue就是存储消息的载体,Looper就是无限循环查找这个载体里是否还有消息.Handler就是创建的时候 会使用looper来构建这个消息循环. handler的主要功能就是 将一个任务切换到某个指定的线程中去执行. 2.为何android 无法在子线程更新ui? 答:都知道 更新ui 实际工作都是在viewrootimpl这个类里面去做的.他的源码里有下面这样一个函数: 1 voi

[Android][转]Android View绘制13问13答

转自:http://www.androidchina.net/4458.html 1.view的绘制流程分几步,从哪开始?哪个过程结束以后能看到view? 答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程.draw流程结束以后就可以在屏幕上看到view了. 2.view的测量宽高和实际宽高有区别吗? 答:基本上百分之99的情况下都是可以认为没有区别的.有两种情况,有区别.第一种 就是有的时候会因为某些原因 view会多次测量,那

Android View绘制13问13答

http://android.jobbole.com/82796/?utm_source=hao.jobbole.com&utm_medium=relatedArticle

15个热门的编程趋势及15个逐步走向衰落的编程方向

Peter Wayner是InfoWorld的一名特约编辑,也是一个多产的作家.除了InfoWorld之外,他还经常为纽约时报和连线杂志撰写文章.近日,Peter撰写了一篇文章,谈到了未来15个热门的编程趋势以及15个逐步走向衰落的技术方向,该文发表之后在技术社区中引起了较大的反响,也希望文中的观点能给各位读者带来一些启示. 程序员们普遍对时尚界嗤之以鼻,因为这个圈子中的趋势就像风一样变幻不定.裙子忽长忽短.颜色变来变去.领结时大时小.不过在技术界,精确.科学与数学却统治着一切.然而,这并不是说

Android BaseAdapter加载多个不同的Item布局时出现UncaughtException in Thread main java.lang.ArrayIndexOutOfBoundsException: length=15; index=15

java.lang.ArrayIndexOutOfBoundsException: length=15; index=15 异常出现的场景:在做聊天界面时,需要插入表情,图片,文字,名片,还有几种较为复杂的布局.这时就需要用到BaseAdapter中的getViewTypeCount()和getItemViewType(int position) 方法了,在发送复杂界面时出现了这个异常. 令人抓狂的是这个异常居然是UncaughtException,根本无法判断哪一行出错了,刚开始的时候觉得一定

Android官方入门文档[15]重新创建一个Activity活动

Android官方入门文档[15]重新创建一个Activity活动 Recreating an Activity重新创建一个Activity活动 This lesson teaches you to1.Save Your Activity State2.Restore Your Activity State You should also read?Supporting Different Screens?Handling Runtime Changes?Activities 这节课教你1.保存

OpenGL快问快答

OpenGL快问快答 本文内容主要来自对(http://www.opengl.org/wiki/FAQ)的翻译,随机加入了本人的观点.与原文相比,章节未必完整,含义未必雷同,顺序未必一致.仅供参考. 我写这个是为了加深印象,好记性不如烂笔头,好记星不如烂键盘. +BIT祝威+悄悄在此留下版了个权的信息说: 名词术语 渲染:等于"画",等于"draw". OpenGL是什么? OpenGL是Open Graphics Library(开源图形库)的缩写.它是一本说明书

Android 网络编程 记录

简单介绍 看了深入理解Android网络编程感觉不错.今天对Android网络编程进行了要点记录. 内容 Android基于网络技术和编程实践 要点 定义 描写叙述 IP协议 用于报文交换网络的一种面向数据的协议   TCP协议 传输控制协议,传输层通信协议.   UDP协议 用户数据报协议.传输层协议.   SMTP协议 简单邮件传输协议   SOCKET 套接字 应用层与TCP/IP协议族通信的中间软件抽象层. 类型有两种:TCP套接字和UDP套接字. TCP套接字   在保证可靠性上,採用

Java 面试题问与答:编译时与运行时

Java 面试题问与答:编译时与运行时 2012/12/17 | 分类: 基础技术, 职业生涯 | 5 条评论 | 标签: RUNTIME, 面试 分享到:58 本文作者: ImportNew - 朱伟杰 未经许可,禁止转载! 在开发和设计的时候,我们需要考虑编译时,运行时以及构建时这三个概念.理解这几个概念可以更好地帮助你去了解一些基本的原理.下面是初学者晋级中级水平需要知道的一些问题. Q.下面的代码片段中,行A和行B所标识的代码有什么区别呢? 1 2 3 4 5 6 7 8 9 10 11