Android 소스 코드 의 정적 공장 방법

우 리 는 공장 모델 에 세 형제 가 있다 는 것 을 알 고 있다. 보통 우리 가 말 하 는 공장 모델 은 공장 방법 모델 을 말 하 는데 그 응용 빈도 가 가장 높다.이 블 로그 가 공유 하 는 간단 한 공장 모델 은 공장 방법 모델 의 '동생' 으로 정확히 말 하면 디자인 모델 이 아니 라 방법 이다.그 밖 에 공장 방법 모델 에는 '형님' 인 추상 적 인 공장 모델 도 있다.
오늘 우 리 는 간단 한 공장 모델 의 일부 상황 과 안 드 로 이 드 소스 코드 에서 의 응용 을 공유 합 니 다.
단순 공장 모드
정의.
간단 한 공장 모델 은 클래스 의 생 성 모델 로 정적 공장 방법 (Static Factory Method) 모델 이 라 고도 부른다.간단 한 공장 모델 은 한 공장 대상 이 어떤 제품 류 의 인 스 턴 스 를 만 들 지 결정 하 는 것 이다.
구조
간단 한 공장 모델 과 관련 된 역할:
  • 제품 (추상 적 인 제품 역할): 제품 의 유 니 버 설 인터페이스, 제품 의 행 위 를 정의 합 니 다.
  • Concrete Product (구체 적 인 제품 역할): 구체 적 인 제품 류 는 제품 인 터 페 이 스 를 실현 했다.
  • Creator (공장 역할): 공장 류, 정적 공장 방법 factory Methord 를 통 해 대상 을 만 듭 니 다.

  • 이루어지다
    추상 적 인 제품 역할
    abstract class Product {  
        //              
        public void methodSame() {  
            //         
        }  
    
        //          
        public abstract void methodDiff();  
    }
    

    구체 적 인 제품 역할
    class ConcreteProduct extends Product {  
        //        
        public void methodDiff() {  
            //         
        }  
    }
    

    공장 역할
    class Creator {  
        //        
        public static Product getProduct(String arg) {  
            Product product = null;  
            if (arg.equalsIgnoreCase("A")) {  
                product = new ConcreteProductA();  
                //     product  
            }  
            else if (arg.equalsIgnoreCase("B")) {  
                product = new ConcreteProductB();  
                //     product  
            }  
            return product;  
        }  
    }
    

    필드 사용
    다음 과 같은 상황 에서 간단 한 공장 모델 을 사용 하 는 것 을 고려 할 수 있다.
  • 공장 류 는 설립 을 담당 하 는 대상 이 비교적 적 고 설립 대상 이 비교적 적기 때문에 공장 방법 중의 업무 논리 가 너무 복잡 하지 않다.
  • 클 라 이언 트 는 공장 류 에 들 어 오 는 매개 변수 만 알 고 대상 을 어떻게 만 드 는 지 에 관심 이 없다.

  • 장점.
  • 공장 류 는 필요 한 판단 논 리 를 포함 하고 언제 어떤 제품 류 의 인 스 턴 스 를 만 들 것 인 지 를 결정 할 수 있다. 클 라 이언 트 는 제품 대상 을 직접 만 드 는 직책 을 면제 할 수 있 고 '소비' 제품 만 있 으 며 간단 한 공장 모델 은 대상 의 설립 과 사용 의 분 리 를 실현 했다.
  • 클 라 이언 트 는 만 든 구체 적 인 제품 류 의 유형 을 알 필요 가 없고 구체 적 인 제품 류 에 대응 하 는 매개 변수 만 알 면 된다. 복잡 한 유형 에 대해 간단 한 공장 모델 을 통 해 사용자 의 기억 량 을 어느 정도 줄 일 수 있다.

  • 결점.
  • 시스템 확장 이 어렵 기 때문에 신제품 을 추가 하면 공장 논 리 를 수정 해 야 한다. 제품 유형 이 많 을 때 공장 의 논리 가 너무 복잡 하고 시스템 의 확장 과 유지 에 불리 할 수 있다.
  • 간단 한 공장 모델 은 정태 적 인 공장 방법 을 사 용 했 기 때문에 공장 역할 은 계승 을 바탕 으로 하 는 등급 구 조 를 형성 하지 못 한다.

  • Android 에서 간단 한 공장 모델 의 응용
    안 드 로 이 드 에서 우리 가 알 고 있 는 간단 한 공장 방법 을 사용 한 곳 은 비트 맵 대상 획득, Fragment 생 성 등 이 있다.이제 우리 따로 보 자.
    Bitmap 소스 코드 분석
    우선, 우 리 는 new 방법 을 통 해 Bitmap 대상 을 만 들 수 없습니다. Bitmap 류 의 구조 함 수 는 개인 적 이 고 JNI 를 통 해 만 예화 할 수 있 기 때 문 입 니 다.
    다음 에 우 리 는 마음대로 입 구 를 찾 아 보기 시작 했다. 예 를 들 어:
    Bitmap bmp = BitmapFactory.decodeFile(String pathName);
    

    우 리 는 소스 코드 중의 호출 관 계 를 다음 과 같이 찾 아 냈 다.
    public static Bitmap decodeFile(String pathName) {
        return decodeFile(pathName, null);
    }
    
    public static Bitmap decodeFile(String pathName, Options opts) {
        Bitmap bm = null;
        InputStream stream = null;
        try {
            stream = new FileInputStream(pathName);
            bm = decodeStream(stream, null, opts);
        } catch (Exception e) {
            /*  do nothing.
                If the exception happened on open, bm will be null.
            */
            Log.e("BitmapFactory", "Unable to decode stream: " + e);
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    // do nothing here
                }
            }
        }
        return bm;
    }
    
    public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
        // we don't throw in this case, thus allowing the caller to only check
        // the cache, and not force the image to be decoded.
        if (is == null) {
            return null;
        }
    
        Bitmap bm = null;
    
        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
        try {
            if (is instanceof AssetManager.AssetInputStream) {
                final long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
                bm = nativeDecodeAsset(asset, outPadding, opts);
            } else {
                bm = decodeStreamInternal(is, outPadding, opts);
            }
    
            if (bm == null && opts != null && opts.inBitmap != null) {
                throw new IllegalArgumentException("Problem decoding into existing bitmap");
            }
    
            setDensityFromOptions(bm, opts);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
        }
    
        return bm;
    }
    
    private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
            Rect padding, Options opts);
    
    /**
     * Set the newly decoded bitmap's density based on the Options.
     */
    private static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
        if (outputBitmap == null || opts == null) return;
    
        final int density = opts.inDensity;
        if (density != 0) {
            outputBitmap.setDensity(density);
            final int targetDensity = opts.inTargetDensity;
            if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
                return;
            }
    
            byte[] np = outputBitmap.getNinePatchChunk();
            final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
            if (opts.inScaled || isNinePatch) {
                outputBitmap.setDensity(targetDensity);
            }
        } else if (opts.inBitmap != null) {
            // bitmap was reused, ensure density is reset
            outputBitmap.setDensity(Bitmap.getDefaultDensity());
        }
    }
    

    호출 과정 을 분석 해 보면 decodeFile (String pathName) 이 decodeFile (String pathName, Options opts) 을 호출 한 것 을 볼 수 있 습 니 다. 두 매개 변수의 decodeFile 방법 에서 decodeStream (InputStream is, Rect outPadding, Options opts) 방법 을 호출 한 다음 에 nativeDecodeAsset 또는 nativeDecodeStream 을 호출 하여 Bitmap 대상 을 구축 합 니 다.이 두 가 지 는 모두 native 방법 입 니 다.setDensity FromOptions 방법의 디 코딩 밀 도 를 설정 하 는 작업 을 통 해 우리 가 원 하 는 Bitmap 대상 을 되 돌려 줍 니 다.
    /** * Creates Bitmap objects from various sources, including files, streams, and byte-arrays. */
    BitmapFactory 의 설명 을 보면 이 공장 은 서로 다른 자원 에서 Bitmap 대상 을 만 드 는 것 을 지원 합 니 다. files, streams, by te - arrays 를 포함 하지만 호출 관 계 는 대동소이 합 니 다.
    Fragment 생 성
    가끔 은 간단 한 공장 모델 을 간소화 하기 위해 우 리 는 추상 적 인 제품 류 와 공장 류 를 합병 하여 정태 적 인 공장 방법 을 추상 적 인 제품 류 로 옮 길 수 있다.Fragment 의 설립 은 간단 한 공장 방법 으로 추상 적 인 제품 류 가 없 기 때문에 공장 류 는 실현 제품 류 에 넣 었 다.
    AndroidStudio 에 new Instance 를 입력 하면 Fragment 의 간단 한 공장 방법 을 자동 으로 보완 합 니 다.
    public static TasksFragment newInstance() {
    
        Bundle args = new Bundle();
    
        TasksFragment fragment = new TasksFragment();
        fragment.setArguments(args);
        return fragment;
    }
    

    정적 공장 방법 을 사용 하면 외부 에서 들 어 오 는 인 자 를 Fragment. setArgument 를 통 해 자신 에 게 저장 할 수 있 습 니 다. 그러면 우 리 는 Fragment. onCreate (...) 호출 할 때 이 인 자 를 꺼 낼 수 있 습 니 다.
    이렇게 쓰 면 무슨 좋 은 점 이 있 습 니까?
  • Fragment 를 만 들 때 클래스 외부 에서 필요 한 인 자 를 알 수 없 는 문 제 를 피 할 수 있 습 니 다.
  • Fragment 는 가로 세로 화면 전환 시 Fragment 가 자신의 무 참 구조 함 수 를 자동 으로 호출 하여 데 이 터 를 잃 어 버 리 지 않도록 setArguments 를 사용 하여 인 자 를 전달 하 는 것 을 추천 합 니 다.
  • 좋은 웹페이지 즐겨찾기