2013-03-21 1 views
5

Я пытаюсь реализовать обработчики, прослушивающие один и тот же Looper из разных потоков.Обработчики, инициализированные с помощью Looper.getMainLooper(), не отвечают на обратные вызовы сообщений

Ниже у меня есть два обработчика, один из которых создан в основном потоке, другой - в дочернем потоке, однако оба они инициализируются для прослушивания на Main Looper.

private Handler mMain; 
public static final ThreadPoolExecutor tpe = 
     (ThreadPoolExecutor) Executors.newCachedThreadPool(); 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    mMain = new Handler(Looper.getMainLooper()) { 
     @Override 
     public void handleMessage(Message msg) { 
      Log.wtf("", "main:" + msg); 
     } 
    }; 

    tpe.execute(new Runnable() { 
     private Handler tChild = new Handler(Looper.getMainLooper()) { 
      @Override 
      public void handleMessage(Message msg) { 
       Log.wtf("", "child:" + msg); 
      } 
     }; 

     @Override 
     public void run() { 
      Log.wtf("", "send msg to main looper"); 
      tChild.sendEmptyMessage(100); 
     } 
    }); 
} 

Но когда я отправляю сообщение, как показано ниже, только обработчик для детей печатает сообщение. Основной обработчик не получает сообщение.

03-20 22:02:26.754: A/(12857): send msg to main looper 
03-20 22:02:26.847: A/(12857): child:{ what=100 when=-8ms } 

Что я делаю неправильно? Спасибо за чтение.

ответ

10

Каждый экземпляр Handler контролирует цель Message, и нет возможности получить их для обмена, поэтому каждое сообщение или сообщение, отправленное в Handler, выполняется только этим экземпляром.

Looper указывает , в котором нить отправленные сообщения/исполняемые файлы будут выполнены. В вашем коде оба обработчика будут выполнять handleMessage() в основном потоке, несмотря на то, что они созданы на отдельных потоках. Это реальная причина, вы можете передать Looper экземпляр в Handler ... если вы передаете не Looper, затемHandler будет выполнять код на потоке, в котором он был создан (который сусло быть также Looper нить) ,

Кроме того, из-за этого нет оснований создавать несколько обработчиков для публикации данных таким образом. Один Handler предназначен для отправки сообщений из нескольких потоков, и все они сериализованы в MessageQueue и выполняются по выбранной теме Looper. Вы можете отправить сообщение прямо в mMain из фонового потока, чтобы выполнить код в этом потоке. В этом случае передача Looper избыточна при этом коде уже в основном потоке.

+0

Вижу, спасибо! Предположим, что если однажды Runnable был внешним классом вместо внутреннего класса, я должен передать инициализированный обработчик ему через свой конструктор, правильно? –

+0

Архитектура будет зависящей от приложения, но вам понадобится ссылка на «Обработчик», где бы вы ни планировали отправлять сообщения. – Devunwired

+0

Почему бы просто не использовать один обработчик (this.getMainLooper()) в контексте приложения (класс, расширяющий приложение)? Разве это не было бы чище, чем делать это в Управлении? –

1

Сообщения, отправленные на Handler, будут обрабатываться только этим Handler, даже если он делит Looper.

Похоронен в исходном коде для обработчика является линией

msg.target = this; 

Это не гарантирует никакого другого Handler тронет.