android开发艺术探索笔记

第一章Activity的生命周期和启动模式

Activity生命周期

单个Activity

启动Activity
onCreat->onStart->onResume
Activity切换到桌面(Activity用了透明主题不会回调onStop)
onPause->onStop
返回Activity
onRestart->onStart->onResume
按Back键回退
onPause->onStop->onDestroy
直接强制停止应用
没有回调

两个Activity

Activity之间的切换
(A1切换A2)
A1 onPause
A2 onCreat->onStart->onResume
A1 onStop
(A2按Back键回退A1)
A2 onPause
A1 onRestart->onStart->onResume
A2 onStop->onDestroy

Activity启动模式

standard(标准模式)

每个Activity都在同一个栈
每次启动一个Activity都新建实例

singleTop

每个Activity都在同一个栈
除了启动本来就在栈顶的Activity不会新建实例
启动不在栈顶的Activity都新建实例

singleTask

每个Activity都在同一个栈
要启动的Activity在栈内的不会重复新建实例
每次切换非栈顶的Activity会把在它后入栈Activity清除

singleInstance

每个Activity独立一个栈
要启动的Activity在栈内的不会重复新建实例
每次切换Activity切换栈

Activity启动方式

显式 Intent

1
2
Intent i=new Intent(MainActivity.this,Main2.class);
startActivity(i);

隐式 Intent

隐式 Intent不明确指定启动哪个Activity,而是设置Action、Data、Category,让系统来筛选出合适的Activity。筛选是根据所有的< intent-filter >来筛选,可以使用隐式 Intent从A应用启动B应用。

设置Action

android:label是设置标签用来区分同一个应用不同activity用同一个action的情况。

1
2
3
4
5
6
7
<activity android:name=".Main2" android:label="hhh">
<!--<activity android:name=".Main2" android:exported="false">改为这样其它应用无法访问 -->
<intent-filter>
<category android:name="android.intent.category.DEFAULT" /><!--此句一般都要加 -->
<action android:name="com.app.cczhr.democ.my2"/><!--一般命名方式是包名+Action名 -->
</intent-filter>
</activity>

启动

1
2
3
4
5
Intent i=new Intent("com.app.cczhr.democ.my2");
/*也可以这样写
Intent i=new Intent();
i.setAction("com.app.cczhr.democ.my2");*/
startActivity(i);

设置Data
1
2
3
4
5
6
7
8
9
10
<activity android:name=".Main2" android:label="main2">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="app" />
<category android:name="android.intent.category.BROWSABLE"/><!--设置可以浏览器启动 -->
<action android:name="android.intent.action.VIEW"/>
</intent-filter>
</activity>

启动

1
2
3
Intent i=new Intent();
i.setData(Uri.parse("app://"));
startActivity(i);

也可以浏览器直接访问”app://“启动
其它语法(懒得打)


设置Category
1
2
3
4
5
6
<activity android:name=".Main2" android:label="main2">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="jjj" />
</intent-filter>
</activity>

启动

1
2
3
Intent i=new Intent();
i.addCategory("jjj");
startActivity(i);

第二章IPC机制(进程间通信机制)

多进程

详细内容https://www.cnblogs.com/mythou/p/3258715.html
在Android使用多进程只有一种方法,就是给四大组件的AndroidManifest指定android:process
android:process有两种,一种是类似”:remote”,另外一种是类似”xxx.xxx.remote”的,前者是属于当前应用的私有进程,其它应用组件不可以和它跑在同一个进程中,后者则是全局进程,可以通过ShareUID跑在同一个进程中。
多进程带来的问题就是共享数据的问题,因为每个进程都分配不同的虚拟机加载,相当于启动新的应用。

启动服务和绑定服务

此部分出处为:http://www.jianshu.com/p/2fb6eb14fdec
作者:食梦兽
个人略微修改

启动服务(startService)

使用Service的步骤:
1.定义一个类继承Service
2.在Manifest.xml文件中配置该Service

1
2
3
4
5
6
<service
android:name=".AppService"
android:enabled="true"
android:exported="true"
>
</service>

3.使用Context的startService(Intent)方法启动该Service

1
2
3
//跨进程启动方法
Intent i=new Intent();
i.setComponent(new ComponentName("com.app.cczhr.myaidl","com.app.cczhr.myaidl.AppService"));

4.不再使用时,调用stopService(Intent)方法停止该服务

使用这种start方式启动的Service的生命周期如下:
onCreate()—>onStartCommand()(onStart()方法已过时) —> onDestory()

说明:如果服务已经开启,不会重复的执行onCreate(), 而是会调用onStart()和onStartCommand()。
服务停止的时候调用 onDestory()。服务只会被停止一次。

特点:一旦服务开启跟调用者(开启者)就没有任何关系了。
开启者退出了,开启者挂了,服务还在后台长期的运行。
开启者不能调用服务里面的方法。

绑定服务(bindService)

使用Service的步骤:
1.定义一个类继承Service
2.在Manifest.xml文件中配置该Service

1
2
3
4
5
6
<service
android:name=".AppService"
android:enabled="true"
android:exported="true"
>
</service>

3.使用Context的bindService(Intent, ServiceConnection, int)方法启动该Service

1
2
3
4
//跨进程启动方法
Intent i=new Intent();
i.setComponent(new ComponentName("com.app.cczhr.myaidl","com.app.cczhr.myaidl.AppService"));
bindService(i, this, Context.BIND_AUTO_CREATE);

4.不再使用时,调用unbindService(ServiceConnection)方法停止该服务
使用这种bind方式启动的Service的生命周期如下:
onCreate() —>onBind()—>onunbind()—>onDestory()

注意:绑定服务不会调用onstart()或者onstartcommand()方法

特点:bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。
绑定者可以调用服务里面的方法。

对象序列化和反序列化

知识背景:
将对象转换为字节流保存起来,并在以后还原这个对象,这种机制叫做对象序列化。
• 当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员 变量。
• 如果一个对象的成员变量是一个对象,那么这个 对象的数据成员也会被保存。
• 如果一个可序列化的对象包含对某个不可序列化 的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我 们可以将这个引用标记为transient,那么对象仍然可以序列化。

选择序列化方法的原则:
•在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
•Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
•Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。

使用Serializable

例子,serialVersionUID是用来检验反序列化的类是否发生变化的。
Serializable是一个空接口主要用来标记。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import java.io.Serializable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SerializableTest1
{
public static void main(String[] args) throws Exception
{
Person p1 = new Person(20, "zhangsan", 4.55);
Person p2 = new Person(50, "lisi", 4.67);
Person p3 = new Person(10, "wangwu", 17.78);
FileOutputStream fos = new FileOutputStream("d://person.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p1);
oos.writeObject(p2);
oos.writeObject(p3);
oos.close();
System.out.println("--------------------");
FileInputStream fis = new FileInputStream("d://person.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Person p = null;
for (int i = 0; i < 3; i++)
{
p = (Person) ois.readObject();
System.out.println(p.age + "," + p.name + "," + p.height);
}
ois.close();
}
}
class Person implements Serializable
{
private static final long serialVersionUID = 657728328721741525L;//1L也一样
int age;
String name;
double height;
public Person(int age, String name, double height)
{
this.age = age;
this.name = name;
this.height = height;
}
/*
更细化的处理
private void writeObject(java.io.ObjectOutputStream out) throws IOException
{
out.writeInt(age);
out.writeUTF(name);
System.out.println("write object");
}
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException
{
age = in.readInt();
name = in.readUTF();
System.out.println("read object");
}
*/
}

输出结果

使用Parcelable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable {
int age;
String name;
double height;
public Person(int age, String name, double height)
{
this.age = age;
this.name = name;
this.height = height;
}
protected Person(Parcel in) {
age = in.readInt();
name = in.readString();
height = in.readDouble();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(age);
parcel.writeString(name);
parcel.writeDouble(height);
}
}

发送

1
2
3
4
Person p1 = new Person(20, "zhangsan", 4.55);
Intent i=new Intent(MainActivity.this,Main2.class);
i.putExtra("person",p1);
startActivity(i);

接收

1
2
3
Intent i = getIntent();
Person p1 =(Person)i.getParcelableExtra("person");
Log.e("message",p1.age+","+p1.name+","+p1.height);

Binder

使用Messenger

总的来说Messenger负责发送信息,message负责装载信息, Bundle负责保存信息。服务端发自己Messenger给客户端,客户端又发自己的Messenger给服务端,利用对方给的Messenger发信息给对方。

服务端

新建一个服务,然后参考以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class MessengerService extends Service{
private final static int MSG=233;
private static final String TAG = "MessengerService";
public static class MessengerHandler extends Handler{//创建Handler用来接收
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case MSG:
Log.i(TAG, "服务端收到的信息:"+msg.getData().getString("data"));
//服务端发信息给客户端
Messenger messenger=msg.replyTo;//获得客户端的Messenger
Message message=Message.obtain(null,MSG);
Bundle bundle=new Bundle();
bundle.putString("reply","服务端回复客户端");
message.setData(bundle);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
//常规代码
private final Messenger mMessenger=new Messenger(new MessengerHandler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();//返回Binder对象给客户端
}
}

客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Intent i=new Intent();
i.setComponent(new ComponentName("com.app.cczhr.myaidl","com.app.cczhr.myaidl.MessengerService"));//第一个是要启动应用的包名,第二个是具体服务。
bindService(i, mConnection, Context.BIND_AUTO_CREATE);//绑定服务
unbindService( mConnection);//解除绑定一般写在onDestroy()
private Messenger mReplyMessenger =new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
//客户端用来接收服务端的信息
super.handleMessage(msg);
switch (msg.what){
case MSG:
Log.d(TAG, "客户端收到服务端回复的的信息 :" + msg.getData().getString("reply"));
break;
}
}
} );
private ServiceConnection mConnection =new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessenger=new Messenger(service);
Message message=Message.obtain(null,MSG);
Bundle bundle=new Bundle();
bundle.putString("data","收到服务端返回的binder,尝试发送信息给服务端");
message.setData(bundle);
message.replyTo=mReplyMessenger;//发送Messenger给服务端,没有这句服务端将无法传回信息给客户端
try {
mMessenger.send(message);//客户端发送信息
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};

使用AIDL

首先 在客户端服务端都新建一个aidl文件夹,两边放的有关aidl的文件都要同包名,新建aidl文件当接口,自带可传以下类型数据。

1
2
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString)

如果要传输对象则需要实现Parcelable接口的同时,要定义一个同名的aidl引用它,如
Book.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Book implements Parcelable {
public int bookId;
public String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
protected Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeString(bookName);
}
}

Book.aidl

1
2
package com.app.cczhr.myaidl;
parcelable Book;

定义接口

IOnNewBookArrivedListener.aidl

1
2
3
4
5
package com.app.cczhr.myaidl;
import com.app.cczhr.myaidl.Book;
interface IOnNewBookArrivedListener {
void onNewBookArrived(in Book book);
}

IBookManager.aidl

1
2
3
4
5
6
7
8
9
10
package com.app.cczhr.myaidl;
import com.app.cczhr.myaidl.Book;
import com.app.cczhr.myaidl.IOnNewBookArrivedListener;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrivedListener listener);
void unregisterListener(IOnNewBookArrivedListener listener);
}

服务端

也是首先新建一个服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class AppService extends Service {
private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);//开多线程的时候检验服务是否停止
private CopyOnWriteArrayList<Book> mBooksList = new CopyOnWriteArrayList<Book>();//线程安全的ArrayList
private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList<IOnNewBookArrivedListener>();//绑定客户端用
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBooksList;
}
@Override
public void addBook(final Book book) throws RemoteException {
mBooksList.add(book);
new Thread(new Runnable() {
@Override
public void run() {
try {
onNewBookArrived(book);//调用客户端的onNewBookArrived(book)
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListenerList.register(listener);//注册
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListenerList.unregister(listener);//解除注册
}
};
private void onNewBookArrived(Book book) throws RemoteException {
if (!mIsServiceDestoryed.get()) {
final int N = mListenerList.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedListener listener = mListenerList.getBroadcastItem(i);
if (listener != null) {
listener.onNewBookArrived(book);
}
mListenerList.finishBroadcast();
}
}
}
@Override
public void onCreate() {
super.onCreate();
mBooksList.add(new Book(1, "Android"));
mBooksList.add(new Book(2, "ios"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
mIsServiceDestoryed.set(true);
super.onDestroy();
}
}

客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Intent i=new Intent();
i.setComponent(new ComponentName("com.app.cczhr.myaidl","com.app.cczhr.myaidl.AppService"));//第一个是要启动应用的包名,第二个是具体服务。
bindService(i, mConnection, Context.BIND_AUTO_CREATE);//绑定服务
//解除服务
private void unBind(){
if ( bookManager != null && bookManager.asBinder().isBinderAlive()) {
try {
bookManager.unregisterListener( mIOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
unbindService( mConnection);
}
}
.....
.....
private IBookManager bookManager;
.....
.....
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);
try {
List<Book> list = bookManager.getBookList();//假如服务端取数据慢可以在客户端开线程取避免arn
Log.e(TAG, "onServiceConnected: " + list.toString());
bookManager.registerListener(mIOnNewBookArrivedListener);
bookManager.addBook(new Book(4, "测试返回书本"));
bookManager.addBook(new Book(3, "python"));
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {//服务端被停止后回调
bookManager = null;
Log.e(TAG, "Disconnected");
}
};
private IOnNewBookArrivedListener mIOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
@Override
public void onNewBookArrived(Book book) throws RemoteException {
mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, book).sendToTarget();//message由handler创建,可直接向handler发送消息。msg.sendToTarget()
}
};
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_NEW_BOOK_ARRIVED:
Log.e(TAG, "receive new book :" + msg.obj);
break;
default:
super.handleMessage(msg);
}
}
};