안드로이드 구성 요소 내, 구성 요소 간 통신 모듈의 문제점 분석

7223 단어
하나의 앱에 대해 구성 요소 통신은 반드시 없어서는 안 된다. 통신 유형은 점대점과 점 맞은편의 통신으로 나눌 수 있다. 점대점은 유일한 수신자만 메시지에 응답할 수 있고 점 맞은편은 메시지 방송과 유사하다. 즉, 등록된 모든 것이 메시지에 응답할 수 있다.Android에서는 일반적으로 메시지 메커니즘을 사용하지만 메시지 메커니즘의 결합도가 비교적 높다.현재도 일부 통신 프레임워크, 예를 들어 Event Bus, Otto 등 이벤트 버스 프레임워크가 있는데 이런 프레임워크는 구성 요소 간의 결합을 크게 낮출 수 있지만 점대점 통신을 완벽하게 실현할 수 없기 때문에 메시지 메커니즘과 이벤트 버스 메커니즘을 결합하여 사용하는 것을 권장한다.
구성 요소 간의 통신
예를 들어fragment와fragment 간의 통신은 숙주activity를 간접적으로 사용해야 한다.주로 두 가지 방법이 있다.
  • A fragment에서 getActivity를 사용하여 숙주를 획득하여 숙주가 가지고 있는 B fragment를 획득하고 B fragment를 조작한다.
  • A 프레임워크에 인터페이스를 작성하여 숙주인 activity가 이 인터페이스를 실현하도록 한 다음에fragment에서 activity를 이 인터페이스로 사용한다.

  • 그리고 두 번째 방식을 추천합니다.
  • 실제 사용 체험에서 볼 때 이런 방식은 어느 정도에 결합을 만족시켰다. 만약에 숙주인activity를 바꾸면fragment의 코드는 변경할 필요가 없다.
  • 디자인 모델의 측면에서 볼 때 가장 기본적인 원칙은 개폐 원칙이다.개폐 원칙은 모듈은 확장에 대해 개방하고 수정에 대해서는 닫아야 한다는 것이다.모듈은 가능한 한 코드를 수정하지 않은 상태에서 확장해야 한다.
  • 첫 번째 방식은 통했지만 디자인 모델의 개폐 원칙을 현저히 위반했다.fragment 디자인 초기에는 독립된 개발 구성 요소였다. 만약에fragment가 숙주activity와 상호작용을 하려면 오랫동안 activity가 어떻게 작동하는지 알아야 하기 때문에 그 자체가fragment의 독립성을 파괴했다.즉 이fragment는 이activity에만 독점되고 다른 activity에서 사용할 수 없다는 것이다.만약 다른 B activity에도 이런fragment가 필요하다면 독점된fragment를 다시 쓸 수 밖에 없고 복용성이 파괴된다.
  • 두 번째 방식은fragment에서 인터페이스를 정의하고 숙주인activity가 인터페이스 처리 작업을 실현한다.숙주activity를 바꾸려면 새로운activity에서 인터페이스를 실현하면 됩니다.fragment는 시종일관 바꿀 필요가 없습니다.
  • 두 번째 방식은 사실상 디자인 모델 중의 대리 모델이다.하나의 대리류가 나와서 원 대상을 대신해서 약간의 조작을 진행한다.

  • EventBus
    유명한 틀이 왜 유명해?바로 그가 표준 디자인 모델을 따르는 기초 위에서 까다로운 문제를 우아하게 해결했기 때문이다.https://github.com/greenrobot/EventBus
    EventBus는 Android에 최적화된 게시/구독 이벤트 버스입니다.주요 기능은 Intent,Handler,BroadCast를 대체하여 Fragment,Activity,Service,선정 사이에서 메시지를 전달하는 것이다.장점은 비용이 적고 코드가 더욱 우아하다는 것이다.발송자와 수신자를 결합시킨다.
    사용
  • 메시지 클래스를 새로 만들고 문자열을 구성한 다음 getMsg () 를 통해 가져올 수 있습니다.
  • public class FirstEvent { 
     
        private String mMsg;  
        public FirstEvent(String msg) {  
            // TODO Auto-generated constructor stub  
            mMsg = msg;  
        }  
        public String getMsg(){  
            return mMsg;  
        }  
    }  
    
  • 메시지를 받는 Activity의 Oncreate() 함수에 이벤트Bus를 등록하고 OnDestroy() 함수에 반등록합니다.
  • public class MainActivity extends Activity {  
      
        Button btn;  
        TextView tv;  
      
        @Override  
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_main);  
                    //  EventBus  
            EventBus.getDefault().register(this);  
      
            btn = (Button) findViewById(R.id.btn_try);  
            tv = (TextView)findViewById(R.id.tv);  
      
            btn.setOnClickListener(new View.OnClickListener() {  
                @Override  
                public void onClick(View v) {  
                    // TODO Auto-generated method stub  
                    Intent intent = new Intent(getApplicationContext(), SecondActivity.class);  
                    startActivity(intent);  
                }  
            });  
        }  
    
        @Override  
        protected void onDestroy(){  
            super.onDestroy();  
            EventBus.getDefault().unregister(this);//   EventBus  
        }  
    }  
    
  • 메시지를 보내는 것은 이벤트버스의 Post 방법으로 보내는 것입니다. 보내는 것은 우리가 새로 만든 메시지 종류의 실례입니다!
  • public class SecondActivity extends Activity {  
        private Button btn_FirstEvent;  
      
        @Override  
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_second);  
            btn_FirstEvent = (Button) findViewById(R.id.btn_first_event);  
      
            btn_FirstEvent.setOnClickListener(new View.OnClickListener() {  
      
                @Override  
                public void onClick(View v) {  
                    // TODO Auto-generated method stub  
                    EventBus.getDefault().post(new FirstEvent("FirstEvent btn clicked"));  
                }  
            });  
        }  
    }  
    
  • 수신 메시지는 수신 메시지의activity에서 onEventMainThread(FirstEvent event)를 다시 쓰고 매개 변수는 사용자 정의 메시지 클래스
  • 이다.
    public class MainActivity extends Activity {  
      
        Button btn;  
        TextView tv;  
      
        @Override  
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_main);  
      
            EventBus.getDefault().register(this);  
      
            btn = (Button) findViewById(R.id.btn_try);  
            tv = (TextView)findViewById(R.id.tv);  
      
            btn.setOnClickListener(new View.OnClickListener() {  
                @Override  
                public void onClick(View v) {  
                    // TODO Auto-generated method stub  
                    Intent intent = new Intent(getApplicationContext(),  
                            SecondActivity.class);  
                    startActivity(intent);  
                }  
            });  
        }  
      
        public void onEventMainThread(FirstEvent event) {  
            String msg = "onEventMainThread     :" + event.getMsg();  
            Log.d("harvic", msg);  
            tv.setText(msg);  
            Toast.makeText(this, msg, Toast.LENGTH_LONG).show();  
        }  
      
        @Override  
        protected void onDestroy(){  
            super.onDestroy();  
            EventBus.getDefault().unregister(this);  
        }  
    }  
    

    상세하게 해석하다
    게시/구독 시간 버스란 두 가지가 있는데 한 쪽이 발표하고 한 쪽이 관찰하고 받아들이는 것이다.
  • 사건 발표: 관찰자 사건 발생 시 이벤트 Buss를 통해 알리기post 함수 구현, 이 과정을 이벤트의 발표라고 한다
  • 사건의 수신: 관찰자가 사건 발생을 사건의 수신이라고 알려짐
  • EventBus의 수신 함수: EventBus는 총 4개의 함수로post에서 온 메시지를 수신할 수 있습니다.
  • onEvent가 onEvent를 구독 함수로 사용하면 이 이벤트가 어느 라인에서 발표되었는지 onEvent는 이 라인에서 실행됩니다. 즉, 발표 이벤트와 수신 이벤트 라인이 같은 라인에서 실행됩니다.이 방법을 사용할 때 onEvent 방법에서는 시간 소모 작업을 수행할 수 없습니다. 시간 소모 작업을 실행하면 이벤트 분배가 지연되기 쉽습니다.
  • onEventMainThread가 onEventMainThread를 구독 함수로 사용하면 이벤트가 어느 라인에서 발표되었든지 간에 onEventMainThread는 UI 라인에서 실행되고 이벤트를 수신하면 UI 라인에서 실행된다. 이것은 안드로이드에서 매우 유용하다. 왜냐하면 안드로이드에서는 UI 라인에서만 새로운 UI를 사용할 수 있기 때문이다.그래서 onEvnetMainThread 방법에서는 시간 소모 작업을 수행할 수 없습니다.
  • onEvent Background Thread onEvent Backgrond를 구독 함수로 사용하면 이벤트가 UI 라인에서 발표되면 onEvent Background는 하위 라인을 새로 만들어서 onEvent Background를 실행합니다. 이벤트가 원래 하위 라인에서 발표된 경우 onEvent Background 함수는 이 하위 라인에서 직접 실행됩니다.
  • onEventAsync는 이 함수를 구독 함수로 사용하면 이벤트가 어느 라인에서 발표되든지 간에 새로운 하위 라인을 만들어서 onEventAsync를 실행합니다.

  • EventBus의 메시지 수신 메커니즘:
  • 이벤트버스는 어떻게 메시지를 받습니까?매개 변수 중류의 실례에 근거하여 판정하는 것이다!이렇게 말하면 이 메시지 클래스는 게시/구독 쌍방 간에 결합되어 있고 둘에 의해 독점되어 다른 메시지 통신에 복용될 수 없다.
  • 4개의 수신 함수가 수신기를 충당할 수 있기 때문에 우리가 수신할 때 같은 종류의 실례 매개 변수에 두 개의 함수가 수신하면 어떻게 됩니까?답은 두 가지 방법 모두 집행하는 것이다.EventBus는 4대 수신 방법의 인스턴스 매개변수만 인식하기 때문입니다.이 예에서 세 가지 방법이 모두 집행될 것이다.
  •     public void onEventMainThread(SecondEvent event) {  
            Log.d("harvic", "onEventMainThread     :" + event.getMsg());  
        }  
    
        public void onEventBackgroundThread(SecondEvent event){  
            Log.d("harvic", "onEventBackground     :" + event.getMsg());  
        }  
    
        public void onEventAsync(SecondEvent event){  
            Log.d("harvic", "onEventAsync     :" + event.getMsg());  
        }  
    

    총결산
    이벤트버스는 메시지를 보낼 때 intent,handler,broadcast의 조작을 간소화하고 통일시켰다.메시지를 받을 때 이벤트 처리를 어떻게 하는지 네 가지 방법으로 봉하여 사용합니다.

    좋은 웹페이지 즐겨찾기