Фоновая задача Android для пользовательского интерфейса

Я разрабатываю приложение под Android, которое обрабатывает растровые изображения и применяет фильтры GPU к растровым изображениям. Поскольку это может быть медленно, я решил установить "изображение по умолчанию", например, поддельное изображение, которое будет отображаться до тех пор, пока изображение, которое я хочу отфильтровать, не будет готово.

До этого я ожидал, что растровое изображение будет изменено перед отображением, но оно не предлагает приятного пользовательского опыта.

Проблема в том, что у меня есть предупреждение на системном уровне:

System.err﹕ android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Я видел несколько тем, которые указывают, что я должен использовать runOnUiThread, но я не знаю, как заставить это работать.. вот код моих приложений

Активность FilterActivity, получает URI, который содержит путь к файлу. FilterPreview Метод обрабатывает класс, которому удастся поставить в очередь действие, которое я хочу сделать.

public class FiltersActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_filters);

        mFiltersView = (ListView) findViewById(R.id.filters_place_holder);
        ViewGroup.LayoutParams params = mFiltersView.getLayoutParams();

        Intent intent = getIntent();
        mSnapShotUri = intent.getData();
        getBitmapFromURI(mSnapShotUri);
        ....

    private void getBitmapFromURI(Uri uri) {
        try {
            mSnapShot = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
        }
        catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "File not found");
        }
        finally {
            mPreviewBitmap = Bitmap.createScaledBitmap(mBitmap, PreviewSizeWidth, PreviewSizeHeight, false);
            FiltersPreview();
        }
    }

    private void FiltersPreview() {

        boolean mPreview = true;
        mFiltersView.setAdapter(new CameraImageFiltersAdapter(this, mSnapShot, mPreviewBitmap, mPreview));
        mFiltersView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {

                CameraFiltersFactory effect = (CameraFiltersFactory) v.findViewById(R.id.filteredImage).getTag();
                effect.save(new GPUImage.OnPictureSavedListener() {

                   @Override public void onPictureSaved(Uri uri) {

                        Intent previewIntent = new Intent(FiltersActivity.this, PreviewActivity.class);
                        previewIntent.setData(uri);
                        startActivityForResult(previewIntent, 0);

                    }
                });
            }
        });
    }

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

        mFiltersView.setAdapter(new CameraImageFiltersAdapter(this, mSnapShot, mPreviewBitmap, mPreview));

CameraImageFiltersAdapter учебный класс (stub_id это поддельное изображение, отображаемое в процессе применения фильтров)

public CameraImageFiltersAdapter(Context c, Bitmap original, Bitmap current, boolean isPreview) {
        ....
        mExecutorService = Executors.newFixedThreadPool(5);

    }

    @SuppressLint("InflateParams")
    public View getView(int position, View convertView, ViewGroup parent) {

        ImageView filteredImage;

        if (convertView == null) {

            convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_filter, null);
            filteredImage = (ImageView) convertView.findViewById(R.id.filteredImage);
            filteredImage.setImageResource(stub_id);
            queueFiltered(filteredImage, position);
        }

        return convertView;
    }

    private void queueFiltered(ImageView imageView, int position) {
        CameraFiltersFactory holder = new CameraFiltersFactory(mContext, imageView);
        mExecutorService.submit(new FilterLoader(holder, position));

    }

    class FilterLoader implements Runnable {
        CameraFiltersFactory FilterToLoad;
        int FilterPosition;

        FilterLoader(CameraFiltersFactory FilterToLoad, int pos) {
            this.FilterToLoad = FilterToLoad;
            this.FilterPosition = pos;
        }

        @Override
        public void run() {
            try {
                FilterToLoad.setResources(mOriginalBitmap, mCurrentBitmap, mFilterIds[FilterPosition], mPreview);
            } catch (Throwable th) {
                th.printStackTrace();
            }
        }
    }

Любая идея?

2 ответа

Передать активность в качестве параметра для адаптера и затем вызвать:

activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //change the image here
                        }
                    });

Вы не можете вносить изменения в представления в потоках вашего ThreadPool, использовать обработчик основного потока, чтобы опубликовать сообщение и обработать его в основном потоке. Или используя AsyncTask, как эта Обработка растровых изображений вне потока пользовательского интерфейса

Другие вопросы по тегам