Android 프로젝트 재구성의 길:아키텍처 편

안드로이드 프로젝트 재구성 길: 구조편 안드로이드 프로젝트 재구성 길: 인터페이스편 안드로이드 프로젝트 재구성 길: 실현편
지난해 10월 말 새 회사로 옮겨 모바일 연구개발팀의 책임자로 일하다 안드로이드 프로젝트를 처음 맡았을 때 이 프로젝트는 정말 엉망진창이었다.먼저 그 구조는 기능 모듈에 따라 구분된 것이다. 원래는 모듈에 따라 구분하는 것도 좋았지만 그는 너무 세밀하게 나누어서 모두 17개의 모듈로 나뉘었고 여러 개의 모듈도 두세 개의 종류에 불과했다.그러나 응용 자체는 사실 비교적 간단하다. 기능 모듈에 따라 나누려면 최대 다섯 개의 모듈이면 충분하다.또한 많은 모듈의 구분도 모호하고 그 기능에 따라 여러 모듈에 속할 수 있는 것도 많으며 정의가 명확하지 않아 하지 말아야 할 일을 한 것도 많다.때때로 나는 인터페이스의Activity를 찾아야 한다. 그 기능에 따라 A모듈에 속해야 하는데 A모듈에서 찾을 수 없다. 그래서 나는 안드로이드 매니페스트 파일에서 찾았는데 찾아서야 원래 B모듈에 있었다는 것을 발견했다.가끔은 다른 인터페이스의Activity를 찾으려고 했지만 모든 모듈을 다 보았지만 이 인터페이스가 어느 모듈에 속해야 하는지 알 수 없었다. 어쩔 수 없이 안드로이드 매니페스트 파일에서 찾았는데 찾아보니 C 모듈에 있었다.코드도 어지럽고 악취가 나서 한 무더기의 버그가 생겼고 찾기도 어려웠고 한 버그를 고치면 또 다른 버그가 생겼다.전체 프로젝트가 구조부터 코드까지 모두 구리고 어지러워서 개발자들은 끊임없이 버그를 고칠 뿐 새로운 기능을 할 수 없고 확장은 말할 것도 없다.당시 회사는 서로 다른 고객을 위해 맞춤형 앱에 대한 수요가 있었고 기존의 구조는 이런 수요를 충족시키지 못했다.그래서 저는 재구성하여 유지보수가 쉽고 확장이 쉬우며 맞춤형 프로젝트를 구축하기로 결정했습니다.
나는 프로젝트를 네 개의 층으로 나눌 것이다. 그것이 바로 모델 층, 인터페이스 층, 핵심 층, 인터페이스 층이다.모델층은 모든 모델을 정의한다.인터페이스 레이어는 서버에서 제공하는 API를 캡슐화합니다.핵심층은 모든 업무 논리를 처리한다.인터페이스 층은 인터페이스의 전시를 처리한다.여러 계층 간의 관계는 다음 그림과 같이 확장되어 각 계층에 대해 설명합니다.
인터페이스 계층
인터페이스 레이어는 네트워크 하단의 API를 캡슐화하여 코어 레이어에 호출합니다.처음에 이 층의 핵심 클래스를 간단하게 하기 위해 나는 4개만 정의했다.
  • PostEngine, 요청 엔진 클래스로 요청의 발송과 응답 결과를 처리합니다.
  • Response, 응답 클래스, Http 요청이 되돌아오는 데이터 구조를 봉인합니다.
  • Api, 인터페이스 클래스, 모든 인터페이스 방법을 정의했다.
  • ApiImpl, 인터페이스 실현 클래스, 모든 인터페이스 방법을 실현한다.

  • PostEngine은 요청을 서버에 봉하여 보내고 응답 결과의 json 데이터를 Response 대상으로 되돌려줍니다.Response는 응답 결과의 json 데이터 실체 클래스입니다. json 데이터는 고정된 구조를 가지고 세 가지 클래스로 나뉘는데 다음과 같습니다.
    {"event": "0", "msg": "success"}
    {"event": "0", "msg": "success", "obj":{...}}
    {"event": "0", "msg": "success", "objList":[{...}, {...}], "currentPage": 1, "pageSize": 20, "maxCount": 2, "maxPage": 1}
    

    이벤트는 반환 코드이고 0은 성공을 의미하며 msg는 반환된 정보이고obj는 반환된 단일 데이터 대상이며objList는 반환된 데이터 대상의 수조이고currentPage는 현재 페이지를 의미하며 페이지Size는 현재 페이지의 최대 대상 수량을,maxCount는 대상 데이터의 총량을,maxPage는 총 몇 페이지가 있는지 나타낸다.이 구조에 따라 Response의 기본 정의는 다음과 같습니다.
    public class Response<T> {
        private String event;
        private String msg;
        private T obj;
        private T objList;
        private int currentPage;
        private int pageSize;
        private int maxCount;
        private int maxPage;
    
        //getter setter  
        ...    
    }
    

    모든 속성 이름은 json 데이터에 대응하는 이름과 일치해야 합니다. 그렇지 않으면 전환할 수 없습니다.obj와 objList는 범형을 사용하면 상응하는 구체적인 대상으로 전환할 수 있다.
    Api 인터페이스 클래스는 다음과 같이 모든 인터페이스 방법을 정의합니다.
    public Response<Void> login(String loginName, String password);
    public Response<VersionInfo> getLastVersion();
    public Response<List<Coupon>> listNewCoupon(int currentPage, int pageSize);
    

    ApiImpl은 다음과 같이 모든 Api 인터페이스를 구현합니다.
    @Override
    public Response<Void> login(String loginName, String password) {
        try {
            String method = Api.LOGIN;
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("loginName", loginName));
            params.add(new BasicNameValuePair("password", EncryptUtil.makeMD5(password)));
            TypeToken<Response<Void>> typeToken = new TypeToken<Response<Void>>(){};
            return postEngine.specialHandle(method, params, typeToken);
        } catch (Exception e) {
            //    
        }
    }
    

    요청 매개변수와 반환 유형을 정의하고 PostEngine 객체를 호출하여 처리합니다.인터페이스층의 핵심은 기본적으로 이것들이다.
    핵심층
    핵심 층은 인터페이스 층과 인터페이스 층 사이에 있고 주로 업무 논리를 처리하고 데이터 처리에 집중한다.상향, 인터페이스 층에 데이터 처리를 제공하는 인터페이스를 Action이라고 한다.아래로 인터페이스 층을 호출하여 서버에 데이터를 요청합니다.위의 Action에 정의된 메서드는 다음과 같습니다.
    public void getCustomer(String loginName, CallbackListener<Customer> callbackListener);
    

    이것은 사용자 정보를 얻는 방법으로 인터페이스 층에 서버 Api 데이터를 요청해야 하기 때문에 콜백 감청기를 추가하여 콜백에서 되돌아오는 데이터 결과를 조작한다.CallbackListener는 다음과 같은 성공 및 실패 방법을 정의합니다.
    public interface CallbackListener<T> {
        /**
         *              
         * @param data       
         */
        public void onSuccess(T data);
    
        /**
         *              
         * @param errorEvent    
         * @param message        
         */
        public void onFailure(String errorEvent, String message);
    }
    

    인터페이스의 실현은 기본적으로 두 단계로 나뉜다.
  • 파라미터 검사, 검사 파라미터의 합법성은 비공식 검사, 경계 검사, 유효성 검사 등을 포함한다.
  • 비동기 작업으로 인터페이스 층의 Api를 호출하여 응답 결과를 되돌려줍니다.

  • 주의해야 할 것은 Action은 인터페이스를 대상으로 하는 것이기 때문에 인터페이스의 데이터는 상황에 따라 서로 다른 Api를 호출해야 할 수도 있다.후속 확장은 여기에 캐시를 추가할 수 있지만 상황에 따라 결정해야 한다. 예를 들어 변화가 너무 빠른 데이터가 있으면 캐시를 추가하는 것은 적합하지 않다.
    계면층
    인터페이스 층은 최상층에 있는데 그 핵심은 바로 인터페이스의 전시를 담당하는 것이다.회사가 서로 다른 상점을 위해 서로 다른 앱을 맞춤 제작하는 수요가 있기 때문에 여기에는 여러 개의 앱의 인터페이스를 구축해야 한다. 이것은 매우 번거로운 일이다. 다행히 안드로이드스튜디오는 편리한 방법을 제공하여 작업량을 크게 줄일 수 있다. 주로Gradle을 설정하면 서로 다른 앱에 서로 다른 제품 Flavors를 추가할 수 있다.인터페이스 계층 패키지의 정의는 나도 구판의 기능 모듈에 따라 구분하지 않고 서로 다른 유형에 따라 다음과 같은 몇 가지 가방으로 나뉜다. 그 중에서activity,adapter,fragment는 각각 하나의 기류를 가지고 통일된 처리를 한다. 예를 들어 공용된 상량, 대상과 방법 등을 정의했다.인터페이스 층은 가장 복잡하고 혼란스러워지기 쉬우며 문제가 발생하기 쉬운 층이다.그래서 구조부터 코드까지 많은 것들이 잘 설계되고 규범화되어야만 프로그램이 쉽게 유지보수되고 확장될 수 있다.후속 글에서는 이 방면의 경험을 상세하게 공유할 것이다.
    모델 레이어
    모델 층은 모든 층을 가로지르고 모든 데이터 실체 클래스를 봉인한다. 기본적으로 json의obj 데이터와 일치한다. 인터페이스 층에서obj를 해당하는 실체 클래스로 바꾸고 Action을 통해 인터페이스 층으로 전달한다.또한 모델층은 사용자 상태, 지불 상태 등 상수도 정의했다.Api에서 되돌아오는 것은 1, 2, 3으로 정의된 것이고 나는 매거류로 이러한 상태를 정의했다.매거류로 정의하면 경계의 검사를 피할 수 있을 뿐만 아니라 1, 2, 3이 어떤 상태를 대표하는지 누가 더 잘 기억할 수 있겠는가.그러나 매거류로 정의하면 1, 2, 3을 상응하는 매거 상량으로 바꿀 수 있어야 한다.여기서는 두 가지 방법을 제공합니다.
  • gson의 @SerializedName 라벨을 사용합니다. 예를 들어 0이 FALSE이고 1이 TRUE라면 다음과 같이 정의할 수 있습니다.
  • public enum BooleanType {
        @SerializedName("0")
        FALSE,
        @SerializedName("1")
        TRUE
    }
    
  • value를 정의하여 다음과 같이 한다:
  • public enum BooleanType {
        FALSE("0"),
        TRUE("1");
    
        private String value;
    
        BooleanType(String value) {
            this.value = value;
        }
    
        public String getValue() {
            return value;
        }
    }
    

    gson의 방식으로 TRUE 또는 FALSE에 직접 접근하면 자동으로 1 또는 0으로 서열화됩니다.두 번째 방식을 통해 서열화되지 않았기 때문에 getValue 방식으로 1 또는 0을 가져와야 합니다.
    끝맺다
    이상은 가장 기본적인 구조로 비교적 간단하게 말하고 몇 가지 핵심적인 것만 열거했다.더 이상 확장하지 않았습니다. 확장은 다음 단계입니다. 후속 글은 천천히 전개될 것입니다.
    Keegan 스틸에서 옮겨 싣기

    좋은 웹페이지 즐겨찾기