Android 에서 자주 사용 하 는 디자인 모드 (1)

일례
개념: 하나의 인 스 턴 스 만 확보 하고 자체 적 으로 예화 하여 전체 시스템 에 전체 인 스 턴 스 를 제공 합 니 다.
장점:
1. 메모리 소모 유형 에 대해 한 번 만 예화 하여 성능 을 크게 향상 시킨다. 특히 모 바 일 개발 에서
2. 프로그램 실행 중 메모리 에 하나의 인 스 턴 스 만 유지 합 니 다.
public class Singleton {  
    private static volatile Singleton instance = null;  

    private Singleton(){  
    }  

    public static Singleton getInstance() {  
        if (instance == null) {  
            synchronized (Singleton.class) {  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
        return instance;  
    }  
}  

구조 함수 의 사유 화, 정적 함 수 를 정의 하여 인 스 턴 스 를 얻 는 것 은 더 이상 말 하지 않 겠 습 니 다. 여기 서 volatile 을 다시 말 하 겠 습 니 다.
volatile 본질은 jvm 에 현재 변수 가 레지스터 에 있 는 값 이 불확실 하 다 는 것 을 알려 주 는 것 입 니 다. 메모리 에서 읽 어야 합 니 다. synchronized 는 현재 변 수 를 잠 그 고 현재 스 레 드 만 이 변 수 를 방문 할 수 있 으 며 다른 스 레 드 가 막 혔 습 니 다.(우선 우 리 는 이러한 현상 을 의식 해 야 합 니 다. 컴 파 일 러 는 프로그램 이 실행 되 는 속 도 를 높이 기 위해 일부 변수 에 대한 쓰기 작업 은 레지스터 나 CPU 캐 시 에서 먼저 진행 되 고 마지막 에 메모리 에 기록 합 니 다. 이 과정 에서 변수의 새로운 값 은 다른 스 레 드 에 서 는 볼 수 없습니다. volatile 의 역할 은 변 수 를 수정 하 는 읽 기와 쓰기 작업 을 메모리 에서 해 야 합 니 다!)
그리고 이 이중 판단 null:
이것 은 만약 에 스 레 드 A 가 이 코드 에 들 어가 면 스 레 드 B 가 기다 리 고 있 기 때 문 입 니 다. 이것 은 A 스 레 드 가 하나의 인 스 턴 스 를 만 든 후에 스 레 드 B 가 자 물 쇠 를 얻어 동기 화 코드 에 들 어 갑 니 다. 인 스 턴 스 가 이미 존재 하고 나무 가 다시 만 들 필요 가 있 기 때문에 이중 판단 이 필요 합 니 다.
에이, 말 안 할 게 또 이렇게 많아.
Android 에 사용 되 는 부분 이 많 습 니 다. 예 를 들 어 Android - Universal - Image - oader 의 단일 예, EventBus 의 단일 예 입 니 다.
마지막 으로 우리 activity 를 관리 하 는 클래스 를 드 립 니 다. 간단 한 도구 클래스 로 사용 할 수 있 습 니 다.
public class ActivityManager {  

    private static volatile ActivityManager instance;  
    private Stack mActivityStack = new Stack();  

    private ActivityManager(){  

    }  

    public static ActivityManager getInstance(){  
        if (instance == null) {  
        synchronized (ActivityManager.class) {  
            if (instance == null) {  
                instance = new ActivityManager();  
            }  
        }  
        return instance;  
    }  

    public void addActicity(Activity act){  
        mActivityStack.push(act);  
    }  

    public void removeActivity(Activity act){  
        mActivityStack.remove(act);  
    }  

    public void killMyProcess(){  
        int nCount = mActivityStack.size();  
        for (int i = nCount - 1; i >= 0; i--) {  
            Activity activity = mActivityStack.get(i);  
            activity.finish();  
        }  

        mActivityStack.clear();  
        android.os.Process.killProcess(android.os.Process.myPid());  
    } 
} 

빌 더 모드
아니면 순서대로 정의, 인터넷 의 정 의 를 먼저 말 해 보 세 요.
복잡 한 대상 의 구축 과 그 표 시 를 분리 시 켜 같은 구축 과정 에서 서로 다른 표 시 를 만 들 수 있 습 니 다.
올 라 와 서 두 번 읽 어 본 다음 에 못 읽 었 다 는 것 을 알 게 되 었 습 니 다. 괜 찮 습 니 다. 모두 가 거의 읽 지 못 했 습 니 다. 개념 은 추상 적 이 고 이해 하기 어 려 운 것 입 니 다. 이 개념 에서 이 모델 을 간단하게 알 게 된다 면 자 료 를 찾 아 뒤의 물건 을 정리 하 는 데 힘 들 이지 않 아 도 됩 니 다. 여기 서 우 리 는 밤 하 나 를 통 해 Build 모델 을 끌 어 냅 니 다. 가설 에 하나 가 있다 고 가정 합 니 다.Person 류, 그의 일부 속성 은 null 일 수 있 습 니 다. 이 종 류 를 통 해 많은 사람 을 구성 할 수 있 습 니 다.
public class Person {  
    private String name;  
    private int age;  
    private double height;  
    private double weight;  

    public String getName() {  
        return name;  
    }  

    public void setName(String name) {  
        this.name = name;  
    }  

    public int getAge() {  
        return age;  
    }  

    public void setAge(int age) {  
        this.age = age;  
    }  

    public double getHeight() {  
        return height;  
    }  

    public void setHeight(double height) {  
        this.height = height;  
    }  

    public double getWeight() {  
        return weight;  
    }  

    public void setWeight(double weight) {  
        this.weight = weight;  
    }  
}  

그리고 편 의 를 위해 서 당신 은 이러한 구조 함 수 를 써 서 속성 을 입 을 수 있 습 니 다.
public Person(String name, int age, double height, double weight) {  
    this.name = name;  
    this.age = age;  
    this.height = height;  
    this.weight = weight;  
} 

아니면 좀 더 편리 하 게 빈 구조 함 수 를 쓸 수도 있어 요.
public Person() {  
} 

때로는 게 으 르 고 일부 매개 변수 만 들 어 오고 구조 함수 도 쓴다.
public Person(String name) {  
    this.name = name;  
}  

public Person(String name, int age) {  
    this.name = name;  
    this.age = age;  
}  

public Person(String name, int age, double height) {  
    this.name = name;  
    this.age = age;  
    this.height = height;  
} 

그래서 필요 한 종 류 를 만 들 수 있 습 니 다.
Person p1=new Person();  
Person p2=new Person("  ");  
Person p3=new Person("  ",18);  
Person p4=new Person("  ",21,180);  
Person p5=new Person("  ",17,170,65.4);

사실 이런 쓰기 의 나 쁜 점 은 당신 이 쓰 는 과정 에서 키 보드 를 떨 어 뜨리 려 고 할 때 생각해 야 합 니 다. 대상 을 만 드 는 과정 인 데 왜 이렇게 번 거 롭 고 구조 함수 파라미터 가 너무 많 습 니까? 다른 사람들 이 대상 을 만 들 때 각 매개 변수 가 무슨 뜻 을 의미 하 는 지 어떻게 알 겠 습 니까? 이때 우 리 는 코드 의 가 독성 을 위해 Builder 모드 를 사용 하여 Pers 에 게 줄 수 있 습 니 다.on 클래스 에 정적 Builder 클래스 를 추가 한 다음 Person 의 구조 함 수 를 수정 합 니 다. 다음 과 같 습 니 다.
public class Person {  
    private String name;  
    private int age;  
    private double height;  
    private double weight;  

    privatePerson(Builder builder) {  
        this.name=builder.name;  
        this.age=builder.age;  
        this.height=builder.height;  
        this.weight=builder.weight;  
    }  
    public String getName() {  
        return name;  
    }  

    public void setName(String name) {  
        this.name = name;  
    }  

    public int getAge() {  
        return age;  
    }  

    public void setAge(int age) {  
        this.age = age;  
    }  

    public double getHeight() {  
        return height;  
    }  

    public void setHeight(double height) {  
        this.height = height;  
    }  

    public double getWeight() {  
        return weight;  
    }  

    public void setWeight(double weight) {  
        this.weight = weight;  
    }  

    static class Builder{  
        private String name;  
        private int age;  
        private double height;  
        private double weight;  
        public Builder name(String name){  
            this.name=name;  
            return this;  
        }  
        public Builder age(int age){  
            this.age=age;  
            return this;  
        }  
        public Builder height(double height){  
            this.height=height;  
            return this;  
        }  

        public Builder weight(double weight){  
            this.weight=weight;  
            return this;  
        }  

        public Person build(){  
            return new Person(this);  
        }  
    }  
}  

위의 코드 에서 우 리 는 Builder 클래스 에서 Person 클래스 와 같은 속성 을 정의 하고 일련의 구성원 함 수 를 통 해 값 을 부여 하 는 것 을 볼 수 있 습 니 다. 그러나 돌아 오 는 것 은 모두 this 입 니 다. 마지막 으로 build 함 수 를 제공 하여 person 대상 을 만 들 었 습 니 다. 이에 대응 하 는 Person 의 구조 함수 에 Builder 대상 을 전송 한 다음 에 자신의 구성원 변 수 를 순서대로 할당 합 니 다. 그 밖 에Builder 의 구성원 함수 가 돌아 오 는 것 은 모두 this 의 또 다른 역할 은 바로 그 로 하여 금 체인 호출 을 지원 하 게 하고 코드 의 가 독성 을 크게 향상 시 키 는 것 이다. 그래서 우 리 는 이렇게 Person 대상 을 만 들 수 있다.
Person.Builder builder=new Person.Builder();  
Person person=builder  
        .name("  ")  
        .age(18)  
        .height(178.5)  
        .weight(67.4)  
        .build();  

약간 그런 느낌 이 들 지 않 나 요? Android 에서 Builder 모드 를 많이 사 용 했 습 니 다. 예 를 들 어 흔히 볼 수 있 는 대화 상자 생 성 등 입 니 다.
AlertDialog.Builder builder=new AlertDialog.Builder(this);  
AlertDialog dialog=builder.setTitle("  ")  
        .setIcon(android.R.drawable.ic_dialog_alert)  
        .setView(R.layout.myview)  
        .setPositiveButton(R.string.positive, new DialogInterface.OnClickListener() {  
            @Override  
            public void onClick(DialogInterface dialog, int which) {  

            }  
        })  
        .setNegativeButton(R.string.negative, new DialogInterface.OnClickListener() {  
            @Override  
            public void onClick(DialogInterface dialog, int which) {  

            }  
        })  
        .create();  
dialog.show();  

사실 자바 에 서 는 StringBuilder 와 StringBuffer 가 모두 Builder 모드 를 사 용 했 습 니 다. Gson 의 Gson Builder 에 서 는 조금 간단 할 뿐 입 니 다.
GsonBuilder builder=new GsonBuilder();  
Gson gson=builder.setPrettyPrinting()  
        .disableHtmlEscaping()  
        .generateNonExecutableJson()  
        .serializeNulls()  
        .create(); 

네트워크 프레임 워 크 OKHttp
Request.Builder builder=new Request.Builder();  
Request request=builder.addHeader("","")  
    .url("")  
    .post(body)  
    .build();  

대량의 프레임 워 크 가 Builder 디자인 모델 을 활용 한 것 을 알 수 있 습 니 다. 정리 해 보 세 요.
정적 내부 클래스 Builder 를 정의 합 니 다. 내부 구성원 변 수 는 외부 와 마찬가지 로 Builder 는 일련의 방법 으로 구성원 변수 에 값 을 부여 하고 현재 대상 (this) 을 되 돌려 줍 니 다.Builder 클래스 내부 에서 build 방법 이나 create 방법 을 제공 하여 해당 하 는 외부 클래스 를 만 드 는 데 사용 합 니 다. 이 방법 은 내부 에서 외부 클래스 의 사유 화 구조 방법 을 호출 했 습 니 다. 이 구조 방법의 매개 변 수 는 내부 클래스 Builder 외부 클래스 가 내부 클래스 를 호출 할 수 있 도록 사유 화 된 구조 방법 을 제공 하 는 것 입 니 다. 이 구조 함수 에서 구성원 변수의 할당 을 완성 합 니 다.
관찰자 모드
두말 하지 않 고 올 라 오 면 정의 다.
대상 간 의 다 중 의존 관 계 를 정의 합 니 다. 대상 의 상태 가 바 뀌 었 을 때 모든 의존 대상 은 알림 을 받 고 자동 으로 업 데 이 트 됩 니 다.
이 건 조금 은 이해 할 수 있 을 것 같 지만 상황 부터 말씀 드 리 겠 습 니 다.
일기예보 의 문자 서 비 스 는 일단 비용 을 지불 하고 구독 하면 매번 날씨 가 업 데 이 트 될 때마다 당신 에 게 제때에 보 냅 니 다.
사실은 우리 가 매 순간 우리 가 관심 이 있 는 것 에 관심 을 가 질 필요 가 없다 는 것 이다. 우 리 는 그것 을 구독 하면 된다. 우리 가 구독 하 는 업무 가 변화 하면 구독 하 는 업 무 는 즉시 우리 에 게 알려 줄 것 이다.
관찰자 모드 의 구성 을 살 펴 보 자.
  • 관찰 자 는 Observer 라 고 부 릅 니 다. 가끔 은 구독 자, 즉 Subscriber
  • 라 고도 부 릅 니 다.
  • 피 관찰자, 우 리 는 그것 을 Observable, 즉 관찰 할 수 있 는 것 이 라 고 부 르 고, 때로는 주제, 즉 Subject
  • 라 고도 부른다.
    관찰자 모델 의 구체 적 인 실현 에 대해 자바 에 서 는 Observable 류 와 Observer 인 터 페 이 스 를 제공 하여 이 모델 을 신속하게 실현 할 수 있 도록 해 주 었 습 니 다. 그러나 여기 서 인상 을 깊 히 기 위해 이 두 가지 유형 을 사용 하지 않 고 위의 장면 을 모 의 하여 Weather 류 를 정의 합 니 다.
    public class Weather {  
        private String description;  
    
        public Weather(String description) {  
            this.description = description;  
        }  
    
        public String getDescription() {  
            return description;  
        }  
    
        public void setDescription(String description) {  
            this.description = description;  
        }  
    
        @Override  
        public String toString() {  
            return "Weather{" +  
                    "description='" + description + '\'' +  
                    '}';  
        }  
    }  

    그 다음 에 우리 의 관찰 을 정의 합 니 다. 우 리 는 그것 이 통용 되 기 를 바 랍 니 다. 그래서 범 형 으로 정의 합 니 다. 내부 에 register 와 unRegister 가 관찰자 의 구독 과 구독 취 소 를 제공 해 야 합 니 다. 관찰자 의 저장 에 대해 우 리 는 Array List 를 사용 하면 됩 니 다. 또한 주제 가 변화 할 때 관찰자 에 게 응답 을 알려 야 합 니 다. notify Observer 방법 도 필요 합 니 다. 구체 적 인 방법 도 필요 합 니 다.다음 과 같이 구현:
    public class Observable {  
        List> mObservers = new ArrayList>();  
    
        public void register(Observer observer) {  
            if (observer == null) {  
                throw new NullPointerException("observer == null");  
            }  
            synchronized (this) {  
                if (!mObservers.contains(observer))  
                    mObservers.add(observer);  
            }  
        }  
    
        public synchronized void unregister(Observer observer) {  
            mObservers.remove(observer);  
        }  
    
        public void notifyObservers(T data) {  
            for (Observer observer : mObservers) {  
                observer.onUpdate(this, data);  
            }  
        }  
    
    }  

    그리고 우리 의 관찰 자 는 한 관찰자 의 인터페이스 Observer 만 실현 해 야 한다. 이 인터페이스 도 일반적이다.
    public interface Observer {  
        void onUpdate(Observable observable,T data);  
    }  

    구독 주제 에 변화 가 생기 면 이 인 터 페 이 스 를 사용 합 니 다. 우 리 는 날씨 변화의 주 제 를 정의 합 니 다. 즉, 피 관찰 자 를 정의 하고 두 관찰 자 를 정의 하여 날씨의 변 화 를 관찰 합 니 다. 변화 가 생기 면 날씨의 상황 을 인쇄 합 니 다. 주의 하 세 요. 반드시 register 방법 으로 등록 해 야 합 니 다. 그렇지 않 으 면 관찰자 가 변화 하 는 정 보 를 받 지 못 하고 관심 이 없 으 면unregister 방법 을 호출 할 수 있 습 니 다.
    public class Main {  
        public static void main(String [] args){  
            Observable observable=new Observable();  
            Observer observer1=new Observer() {  
                @Override  
                public void onUpdate(Observable observable, Weather data) {  
                    System.out.println("   1:"+data.toString());  
                }  
            };  
            Observer observer2=new Observer() {  
                @Override  
                public void onUpdate(Observable observable, Weather data) {  
                    System.out.println("   2:"+data.toString());  
                }  
            };  
    
            observable.register(observer1);  
            observable.register(observer2);  
    
    
            Weather weather=new Weather("    ");  
            observable.notifyObservers(weather);  
    
            Weather weather1=new Weather("    ");  
            observable.notifyObservers(weather1);  
    
            observable.unregister(observer1);  
    
            Weather weather2=new Weather("  ");  
            observable.notifyObservers(weather2);  
    
        }  
    }  

    출력 도 꺼 짐 문제 관찰자 1: Weather {description = '맑 음 에서 구름 이 많아 짐'} 관찰자 2: Weather {description = '맑 음 에서 구름 이 많아 짐'} 관찰자 1: Weather {description = '구름 이 많아 지면 흐 림'} 관찰자 2: Weather {description = '구름 이 많아 지면 흐 림'} 관찰자 2: Weather {description = '태풍'}
    자, 안 드 로 이 드 에서 의 응용 을 살 펴 보 겠 습 니 다. 가장 간단 한 것 부터 Button 의 클릭 이벤트 입 니 다.
    Button btn=new Button(this);  
    btn.setOnClickListener(new View.OnClickListener() {  
        @Override  
        public void onClick(View v) {  
            Log.e("TAG","click");  
        }  
    });  

    엄격 한 의미 에서 볼 때 이것 은 하나의 반전 이 라 고 할 수 있 지만 우 리 는 이 를 일대일 관찰자 모델 로 볼 수 있다. 사실은 set 시리즈 의 감청 사건 을 설정 하 는 방법 은 대부분이 반전 이 라 고 할 수 있 지만 일부 감청 기 는 add 를 통 해 추 가 된 것 이다. 이런 것들 은 관찰자 모델 이다. 예 를 들 어 RecyclerView 의 add Scroll Listener 방법 이다.
    private List mScrollListeners;  
    public void addOnScrollListener(OnScrollListener listener) {  
        if (mScrollListeners == null) {  
            mScrollListeners = new ArrayList();  
        }  
        mScrollListeners.add(listener);  
    }  
    public void removeOnScrollListener(OnScrollListener listener) {  
        if (mScrollListeners != null) {  
            mScrollListeners.remove(listener);  
        }  
    }  
    public void clearOnScrollListeners() {  
        if (mScrollListeners != null) {  
            mScrollListeners.clear();  
        }  
    }  

    그리고 스크롤 이벤트 가 있 을 때 관찰자 의 방법 을 터치 하여 리 셋 합 니 다.
    public abstract static class OnScrollListener {  
        public void onScrollStateChanged(RecyclerView recyclerView, int newState){}  
        public void onScrolled(RecyclerView recyclerView, int dx, int dy){}  
    }  
    
    void dispatchOnScrolled(int hresult, int vresult) {  
        //...  
        if (mScrollListeners != null) {  
            for (int i = mScrollListeners.size() - 1; i >= 0; i--) {  
                mScrollListeners.get(i).onScrolled(this, hresult, vresult);  
            }  
        }  
    }  
    void dispatchOnScrollStateChanged(int state) {  
        //...  
        if (mScrollListeners != null) {  
            for (int i = mScrollListeners.size() - 1; i >= 0; i--) {  
                mScrollListeners.get(i).onScrollStateChanged(this, state);  
            }  
        }  
    }  

    또한 방송 메커니즘 은 본질 적 으로 관찰자 모드 에서 registerReceiver 방법 으로 방송 을 등록 하고 unregisterReceiver 방법 으로 등록 을 취소 한 다음 에 sendbBroadcast 로 방송 을 보 내 고 그 후에 등 록 된 방송 은 해당 하 는 방송 정 보 를 받는다. 이것 이 바로 전형 적 인 관찰자 모드 이다.
    오픈 소스 프레임 워 크 EventBus 도 관찰자 모드 를 바탕 으로
    관찰자 모드 의 등록, 취소, 사건 발송 세 가지 전형 적 인 방법 이 모두 있다.
    EventBus.getDefault().register(Object subscriber);  
    EventBus.getDefault().unregister(Object subscriber);  
    
    EventBus.getDefault().post(Object event);  

    무 거 운 라 이브 러 리 RxJava 를 비교 하여 피 관찰 자 를 만 듭 니 다.
    Observable myObservable = Observable.create(    
        new Observable.OnSubscribe() {    
            @Override    
            public void call(Subscriber super String> sub) {    
                sub.onNext("Hello, world!");    
                sub.onCompleted();    
            }    
        }    
    );  

    구독 자
    Subscriber mySubscriber = new Subscriber() {    
        @Override    
        public void onNext(String s) { System.out.println(s); }    
    
        @Override    
        public void onCompleted() { }    
    
        @Override    
        public void onError(Throwable e) { }    
    };  
    

    관찰자 가 이벤트 구독 을 진행 합 니 다.
    myObservable.subscribe(mySubscriber);  

    좋은 웹페이지 즐겨찾기