Как обработчик влияет на способ вызова onReceiveResult (ResultReceiver)? - PullRequest
9 голосов
/ 13 ноября 2011

Смотри, у меня есть следующий код:

Мое действие:

final Intent intent = new Intent(getApplicationContext(), MyService.class)
.putExtra(UploadService.EXTRA_RESULT_RECEIVER, new ResultReceiver(null) {
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                super.onReceiveResult(resultCode, resultData);
                String result = resultData.getString(MyService.EXTRA_RESULT_SUCCESS);
                ...
                imageView.setBackgroundDrawable(bitmap);// here my code fails
            }
        })

MyService:

    Bundle b = new Bundle();
    b.putString(EXTRA_RESULT_SUCCESS, response.toString());
    resultReceiver.send(0, b);

И мое приложение не работает в режиме "(растровое изображение) "со следующим исключением:

11-13 16:25:38.986: ERROR/AndroidRuntime(3586): FATAL EXCEPTION: IntentService[MyService]
    android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Но этого не происходит, когда я определяю приемник следующим образом (с обработчиком):

new ResultReceiver(new Handler()){.../*here goes the same code as in the first example. nothing has been changed*/}

Итак.Это не сбой, когда я передаю обработчик по умолчанию.И я спрашиваю Почему ?Мой код вызывается обоими способами, но когда не указан ни один обработчик, происходит сбой.Какое влияние оказывает Хэндлер?

Ответы [ 3 ]

8 голосов
/ 13 ноября 2011

Обработчик связывается с платформой Android и гарантирует, что любой код, выполняемый в обратных вызовах обработчика, выполняется в основном потоке Looper родительского действия, в котором выполняются все обратные вызовы жизненного цикла действия и вызовы пользовательского интерфейса.Если вы действительно хотите понять, как это работает, вы можете пройтись по исходному коду на Github, но выполнение кода в Handler в значительной степени гарантирует, что все будет в нужном месте.

3 голосов
/ 13 ноября 2011

Проблема в том, что imageView.setBackgroundDrawable () вызывается из потока вашей службы.Это неверноВы должны убедиться, что любое обновление пользовательского интерфейса выполняется из потока пользовательского интерфейса.

Трудно точно объяснить, что необходимо изменить из предоставленных вами фрагментов.

Android предоставляет ряд методов.разрешить потокам, не являющимся пользовательским интерфейсом, взаимодействовать с компонентами пользовательского интерфейса (и одним из параметров является класс Handler).ИМХО, это одна из самых важных концепций, которую нужно решить, если вы хотите разрабатывать хорошие приложения для Android.

Некоторые полезные ссылки:

http://developer.android.com/resources/articles/painless-threading.html

Что такое Android UiThread (нить пользовательского интерфейса)

http://www.vogella.de/articles/AndroidPerformance/article.html

0 голосов
/ 20 марта 2016

У меня работает следующее. Вы можете запустить обновление растрового изображения в том же потоке действия вашего пользовательского интерфейса, используя метод runOnUiThread. Вы должны определить следующий класс как внутренний класс вашей пользовательской деятельности:

class UpdateUI implements Runnable
{
    Bitmap newBitmap;

    public UpdateUI(Bitmap newBitmap) {
        this.newBitmap = newBitmap;
    }
    public void run() {
         imageView.setBackgroundDrawable(newBitmap);
    }
}

Тогда в вашем результате получатель:

@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
    // after get your bitmap
    runOnUiThread(new UpdateUI(receivedBitmap));
    ...
}
...