1.觀察者模式簡介
觀察者模式(Observer)又叫做發(fā)布-訂閱模式(Publish/Subscribe),定義對(duì)象之間的一對(duì)多關(guān)系,使得對(duì)象的狀態(tài)發(fā)生改變的時(shí)候,所有依賴它的對(duì)象都會(huì)得到通知并且更新狀態(tài)
2.多進(jìn)程中觀察者模式
單進(jìn)程觀察者模式的使用,在此不做介紹,我們繼續(xù) AIDL通信這個(gè)例子里面的代碼,
首先定義一個(gè)aidl,文件IStudentListener.aidl
// IStudentListener.aidl
package cc.funeay.sepprocesswebview.aidl;
import cc.funeay.sepprocesswebview.aidl.Student;
// Declare any non-default types here with import statements
interface IStudentListener {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
void onStudentChange(in Student student);
}
private List<IStudentListener> listeners = new ArrayList<>();//監(jiān)聽列表
private StudentManager.Stub binder = new StudentManager.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
...//此處省略一萬字
/**
* 注冊(cè)listener
* @param listener
*/
@Override
public void registerListener(IStudentListener listener) throws RemoteException {
if(!listeners.contains(listener)){
listeners.add(listener);
}
}
/**
* 移除listener
* @param listener
* @throws RemoteException
*/
@Override
public void unRegisterListener(IStudentListener listener) throws RemoteException {
if(listeners.contains(listener)){
listeners.remove(listener);
}
}
};
修改如下代碼,當(dāng)add完成以后調(diào)用監(jiān)聽者的方法
@Override
public void addStudentInout(Student s) throws RemoteException {
//s.setName("update");
students.add(s);
//通知listener更新
if(listeners != null){
int size = listeners.size();
for(int i = 0;i<listeners.size();i++){
if(listeners.get(i) != null){
listeners.get(i).onStudentChange(s);
}
}
}
}
//MainActivity.java實(shí)現(xiàn)IStudentListener接口 注冊(cè)監(jiān)聽者
private IStudentListener.Stub listener = new IStudentListener.Stub() {
@Override
public void onStudentChange(Student student) throws RemoteException {
displayStudent(student);
}
};
我們運(yùn)行一下,看到能正常地回調(diào)客戶端的接口,但是解綁listener的時(shí)候發(fā)現(xiàn)listener不是原來的了,
public class StudentService extends Service {
private List<Student> students = new ArrayList<>();
private List<IStudentListener> listeners = new ArrayList<>();//監(jiān)聽列表
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
/**
* 實(shí)現(xiàn)StudentManager接口
*/
private StudentManager.Stub binder = new StudentManager.Stub() {
...
/**
* 注冊(cè)listener
*
* @param listener
*/
@Override
public void registerListener(IStudentListener listener) throws RemoteException {
Log.d("addStudentIn","listener at " + listener);
if(!listeners.contains(listener)){
listeners.add(listener);
}
}
/**
* 移除listener
* @param listener
* @throws RemoteException
*/
@Override
public void unRegisterListener(IStudentListener listener) throws RemoteException {
Log.d("addStudentIn","remove listener0 at " + listener);
if(listeners.contains(listener)){
Log.d("addStudentIn","remove listener at " + listener);//走不到這里 listener已經(jīng)改變了
listeners.remove(listener);
}
}
};
}
這個(gè)時(shí)候就需要用到RemoteCallbackList,這個(gè)是支持跨進(jìn)程的,修改后的完整代碼
//StudentService.java
public class StudentService extends Service {
private List<Student> students = new ArrayList<>();
//private List<IStudentListener> listeners = new ArrayList<>();//監(jiān)聽列表
private RemoteCallbackList<IStudentListener> remoteCallbackList = new RemoteCallbackList<>();//支持跨進(jìn)程
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
/**
* 實(shí)現(xiàn)StudentManager接口
*/
private StudentManager.Stub binder = new StudentManager.Stub() {
@Override
public void addStudentInout(Student s) throws RemoteException {
//s.setName("update");
students.add(s);
onStudentListenerChange(s);
}
@Override
public void addStudentIn(Student s) throws RemoteException {
Log.d("addStudentIn", s.toString());
s.setName("update");
students.add(s);
onStudentListenerChange(s);
}
private void onStudentListenerChange(final Student student) throws RemoteException {
int count = remoteCallbackList.beginBroadcast();
for (int i = 0; i < count; i++) {
IStudentListener listener = remoteCallbackList.getBroadcastItem(i);
if (listener != null) {
listener.onStudentChange(student);
}
}
remoteCallbackList.finishBroadcast();
}
@Override
public List<Student> getStudents() throws RemoteException {
return students;
}
@Override
public void clear(int isClear) throws RemoteException {
students.clear();
}
/**
* 注冊(cè)listener
*
* @param listener
*/
@Override
public void registerListener(IStudentListener listener) throws RemoteException {
Log.d("addStudentIn", "listener at " + listener);
remoteCallbackList.register(listener);
Log.d("addStudentIn", "listsize " + remoteCallbackList.beginBroadcast());
remoteCallbackList.finishBroadcast();
}
/**
* 移除listener
* @param listener
* @throws RemoteException
*/
@Override
public void unRegisterListener(IStudentListener listener) throws RemoteException {
Log.d("addStudentIn", "remove listener0 at " + listener);
remoteCallbackList.unregister(listener);
Log.d("addStudentIn", "listsize " + remoteCallbackList.beginBroadcast());
remoteCallbackList.finishBroadcast();
}
};
}
//MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String BOOK_SERVICE_ACTION = "android.intent.action.StudentService";
private Button btnStartService;
private StudentManager studentManager;//從service進(jìn)程獲取的實(shí)例
private TextView tvDisplay;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
findViewById(R.id.tv_go_webview).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
goWebView();
}
});
btnStartService = findViewById(R.id.btn_start_service);
btnStartService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
tryStartService();
}
});
findViewById(R.id.btn_add_book).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (studentManager != null) {
try {
Student student = new Student(1, "Student-" + System.currentTimeMillis());
studentManager.addStudentInout(student);
disPlayStudents(studentManager.getStudents());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
/* findViewById(R.id.btn_add_book_out).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (studentManager != null) {
try {
Student student = new Student(1, "Student-" + System.currentTimeMillis());
// studentManager.addStudentOut(student);
disPlayStudents(studentManager.getStudents());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});*/
findViewById(R.id.btn_add_book_in).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (studentManager != null) {
try {
Student student = new Student(1, "Student-" + System.currentTimeMillis());
studentManager.addStudentIn(student);
// disPlayStudents(studentManager.getStudents());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
findViewById(R.id.btn_clear).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (studentManager != null) {
try {
studentManager.clear(1);
disPlayStudents(studentManager.getStudents());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
findViewById(R.id.btn_unregister).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(studentManager != null &&studentManager.asBinder() != null &&studentManager.asBinder().isBinderAlive()){
try {
studentManager.unRegisterListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
tvDisplay = findViewById(R.id.tv_dispaly);
}
private void disPlayStudents(List<Student> list) {
List<Student> students = new ArrayList<>();
if (list != null) {
students.addAll(list);
}
StringBuffer sbf = new StringBuffer("*************學(xué)生列表***********\n");
if (students != null) {
int size = students.size();
for (int i = 0; i < size; i++) {
sbf.append(" ");
sbf.append(students.toString());
sbf.append("\n");
}
}
tvDisplay.setText(sbf.toString());
//Log.d("disPlayStudents ", sbf.toString());
}
private void displayStudent(Student student){
tvDisplay.setText(student.toString());
}
@Override
protected void onDestroy() {
stopService();
super.onDestroy();
}
private void tryStartService() {
String isConnected = btnStartService.getTag() != null ? btnStartService.getTag().toString() : "0";
if ("0".equals(isConnected)) {
//未連接
startService();
}
}
/**
* 啟動(dòng)service
*/
private void startService() {
Intent intent = new Intent();
intent.setAction(BOOK_SERVICE_ACTION);
intent.setPackage(getPackageName());//Android 5.0開始不再支持 隱式啟動(dòng)service 需要寫成包名
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
/**
* 停止/解綁service
*/
private void stopService() {
if(studentManager != null &&studentManager.asBinder() != null &&studentManager.asBinder().isBinderAlive()){
try {
studentManager.unRegisterListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(connection);
}
private void goWebView() {
Intent intent = new Intent();
intent.setClass(MainActivity.this, WebViewActivity.class);
startActivity(intent);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
studentManager = StudentManager.Stub.asInterface(iBinder);
if(studentManager != null){
try {
studentManager.registerListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
updateBtnStart();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
//異常的時(shí)候才會(huì)回調(diào)
try {
studentManager.unRegisterListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
studentManager = null;
updateBtnStart();
}
};
private void updateBtnStart() {
btnStartService.setTag(studentManager != null ? "1" : "0");
btnStartService.setText(studentManager != null ? "已連接" : "未連接");
}
private IStudentListener.Stub listener = new IStudentListener.Stub() {
@Override
public void onStudentChange(Student student) throws RemoteException {
Log.d("disPlay student", "student " + student);
displayStudent(student);
}
};
}