2011-01-28 3 views
3

В моем приложении Android NDK библиотека C++ работает в другом потоке, чем поток ui. Вызов JNI из C++ создает экземпляр класса Java Foo. Я хотел бы иметь еще одну панель объектов Java, созданную в потоке пользовательского интерфейса, для вызова методов на Foo. Как мне это сделать?Android/Java: Как вызвать методы объекта, созданные в другом потоке?

Difficulty bonus: Foo имеет несколько собственных методов, которые вызывают соответствующие функции JNI из библиотеки C++. Как обеспечить, чтобы эти вызовы были потокобезопасными?

Сопротивление сложности 2: Некоторые из методов Бар фактически перекрывают методы обратного вызова, в частности WebViewClient. Код возврата некоторых методов зависит от результата вызова метода Foo. Таким образом, звонок в Foo должен был произойти немедленно.

+0

Фактически, вся конструкция, в которой требуются синхронные результаты из потока, вероятно, воняет. Если библиотека JNI не является устаревшей или третьей стороной, рассмотрите возможность перемещения Foo в поток пользовательского интерфейса. –

+0

Вы, вероятно, должны начать с игнорирования того факта, что методы вызывают через JNI. Проблемы безопасности нитей не сильно зависят от того, какой язык программирования вы используете. – fadden

+0

Трудность 3! Все это является частью кросс-платформенной библиотеки. Клиент в основном использует интерфейс C++, который на Android работает в другом потоке, чем пользовательский интерфейс.Эта часть дизайна является неизменной и недоступной для меня. Отсюда и трудность в реализации этого. – djcouchycouch

ответ

0

Пробуйте класс обработчика. Построить обработчик в конструкторе Foo. Передайте ссылку на класс Bar каким-то образом. Вызов Bar Handler.post().

Для этого в потоке должна быть очередь сообщений. Если это чисто рабочий поток, то вызов методов напрямую не является ответом; нет механизма прерывания потока AFAIR. Для передачи материала в рабочий поток вам нужно некоторое время имитировать очередность сообщений - иметь очередь объектов Runnnable (к которой добавляется Bar) и время от времени проверять ее.

Обеспечение безопасности резьбы - отдельный большой вопрос. SO недостаточно велико для всего, что было сказано и сделано по этой теме.

+0

Я думал о том, чтобы использовать какую-то очередь сообщений, но я столкнулся с showstopper: некоторые из методов Bar на самом деле переопределяют методы обратного вызова, в частности WebViewClient. Код возврата некоторых методов зависит от результата вызова метода Foo. Таким образом, звонок в Foo должен был произойти немедленно. Я добавлю эту деталь к своему основному сообщению. – djcouchycouch

+0

Так что блокировка потоков в порядке. Это отстойно; заставляя поток пользовательского интерфейса ждать ответа рабочего потока, убивает всю цель потоковой передачи. Не говоря уже о очень хрупкой (что, если рабочий НЕ отвечает?). При этом методы Object.wait() и notify() - ваши друзья (иногда враги). –

0

Так у вас есть нить 1 и 2, поток 2 создает объект и нить 1 имеет объект, который хочет вызвать методы объекта в потоке 2.

Могли бы вы не имеете в основном объект на нить 2, написанной в java со стандартными технологиями синхронизации потоков Java, например, с использованием синхронизированного ключевого слова?

например Java код на резьбе:

// object of this type instantiated on thread 2 and called from thread 1 
public class thread2Class { 
    public void doSomething(...) { 
     synchronized (this) { 
      // call java or jni mthod 
     } 
    } 
} 
0

Дважды очереди сообщений с Уведомитель обратного вызова подпрограммы вложенной в сообщении. Тема сообщения 1 сообщения с обратным адресом в очереди Thread 2. Thread 2 обрабатывает сообщение и отправляет уведомление о результатах в очереди Thread 1. Thread 1 вызывает процедуру обратного вызова, связанную с отправленным исходным сообщением. Резьба 1 очередь - очередь сообщений UI, а Thread 2 - ваша собственная реализация очереди. Тема 2 - это менеджер/обертка для вызовов библиотеки. Без блокировки, без ожидания. Если Thread 1 должен управлять состоянием, тогда обновите модель состояния, которая контролирует, какое сообщение отправляется после получения ответа.

0

Я бы попытался использовать что-то вроде beginInvoke(), чтобы отправить сообщение в поток соответствующим образом. Было отмечено here, что beginInvoke() можно издеваться либо с Activity.runOnUiThread(), либо с надлежащим образом использованным AsyncTask().