Android: запуск потока, препятствующего запуску анимации

1

В настоящее время у меня есть активность Android, которая управляет некоторыми локальными RSS-каналами. В этом упражнении эти каналы обновляются в своем потоке через частный класс. Я также пытаюсь включить значок "обновления", который вращается с помощью RotateAnimation пока этот поток запущен.

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

Функция updateAllFeeds() вызывается из нажатия кнопки. Здесь соответствующий код:

/**
 * Gets the animation properties for the rotation
 */
protected RotateAnimation getRotateAnimation() {
    // Now animate it
    Log.d("RSS Alarm", "Performing animation");
    RotateAnimation anim = new RotateAnimation(359f, 0f, 16f, 21f);
    anim.setInterpolator(new LinearInterpolator());
    anim.setRepeatCount(Animation.INFINITE);
    anim.setDuration(700);
    return anim;
}

/**
 * Animates the refresh icon with a rotate
 */
public void setUpdating() {
    btnRefreshAll.startAnimation(getRotateAnimation());
}

/**
 * Reverts the refresh icon back to a still image
 */
public void stopUpdating() {
    Log.d("RSS Alarm", "Stopping animation");
    btnRefreshAll.setAnimation(null);
    refreshList();
}

/**
 * Updates all RSS feeds in the list
 */
protected void updateAllFeeds() {
    setUpdating();
    Updater updater = new Updater(channels);
    updater.run();

}

/**
 * Class to update RSS feeds in a new thread
 * @author Michael
 *
 */
private class Updater implements Runnable {

    // Mode flags
    public static final int MODE_ONE = 0;
    public static final int MODE_ALL = 1;

    // Class vars
    Channel channel;
    ArrayList<Channel> channelList;
    int mode;

    /**
     * Constructor for singular update
     * @param channel
     */
    public Updater(Channel channel) {
        this.mode = MODE_ONE;
        this.channel = channel;
    }

    /**
     * Constructor for updating multiple feeds at once
     * @param channelList The list of channels to be updated
     */
    public Updater(ArrayList<Channel> channelList) {
        this.mode = MODE_ALL;
        this.channelList = channelList;
    }

    /**
     * Performs all the good stuff
     */
    public void run() {
        // Flag for writing problems
        boolean write_error = false;

        // Check if we have a singular or list
        if(this.mode == MODE_ONE) {
            // Updating one feed only
            int updateStatus = channel.update(getApplicationContext());

            // Check for error
            if(updateStatus == 2) {
                // Error - show dialog
                write_error = true;
            }
        }
        else {
            // Iterate through all feeds
            for(int i = 0; i < this.channelList.size(); i++) {
                // Update this item
                int updateStatus = channelList.get(i).update(getApplicationContext());                
                 if(updateStatus == 2) {
                     // Error - show dialog
                     write_error = true;
                 }
            }
        }

        // If we have an error, show the dialog
        if(write_error) {
            runOnUiThread(new Runnable(){
                public void run() {  
                    showDialog(ERR_SD_READ_ONLY);
                }
             });
        }

        // End updater
        stopUpdating();
    }   // End run()
}   // End class Updater

(Я знаю, что updateStatus == 2 бит - это плохая практика, одна из следующих вещей, которую я планирую убрать).

Любая помощь очень ценится, большое спасибо заранее.

  • 0
    Просто чтобы уточнить: вы не должны пытаться обновить пользовательский интерфейс из потока, отличного от основного потока приложения. AsyncTask обрабатывает это для вас, выполняя onPostExecute и onPreExecute в главном потоке. Вы можете получить тот же результат, разместив логику обновления пользовательского интерфейса в главном потоке, используя Handler и Message .
Теги:
multithreading
animation
rotateanimation

3 ответа

0
Лучший ответ

Запустите программу обновления в отдельном потоке. Выполните следующие изменения.

protected void updateAllFeeds() {
    setUpdating();
    new Thread( new Updater(channels)).start();
}

Вызов stopUpdating() в блоке runOnUiThread.

private class Updater implements Runnable {
    .........
    .........    
    .........
    public void run() {
        .........
        .........

        // End updater
        runOnUiThread(new Runnable(){
                public void run() {  
                     stopUpdating();
                }
             });

    }   // End run()
}   // End class Updater
0

Мне удалось получить эту работу прошлой ночью, используя класс Android AsyncTask. Это было удивительно легко реализовать, хотя недостатком было то, что мне пришлось написать один класс для обновления отдельного фида, а другой для обновления всех каналов. Здесь код для обновления всех каналов сразу:

private class MassUpdater extends AsyncTask<ArrayList<Channel>, Void, Void> {

    @Override
    protected Void doInBackground(ArrayList<Channel>... channels) {
        ArrayList<Channel> channelList = channels[0];

        // Flag for writing problems
        boolean write_error = false;

            // Iterate through all feeds
            for(int i = 0; i < channelList.size(); i++) {
                // Update this item
                int updateStatus = channelList.get(i).update(getApplicationContext());                
                 if(updateStatus == FileHandler.STATUS_WRITE_ERROR) {
                     // Error - show dialog
                     write_error = true;
                 }
            }


        // If we have an error, show the dialog
        if(write_error) {
            runOnUiThread(new Runnable(){
                public void run() {  
                    showDialog(ERR_SD_READ_ONLY);
                }
             });
        }
        return null;
    }

    protected void onPreExecute() {
        btnRefreshAll.setAnimation(getRotateAnimation());
        btnRefreshAll.invalidate();
        btnRefreshAll.getAnimation().startNow();
    }

    protected void onPostExecute(Void hello) {
        btnRefreshAll.setAnimation(null);
        refreshList();
    }
}

Спасибо за ваши ответы. userSeven7s ответ также имеет большой смысл, поэтому я могу использовать это как резервное копирование, чтобы я столкнулся с любыми проблемами с AsyncTask.

0

Переместите все, что влияет на пользовательский интерфейс, на свой собственный Runnable а затем разместите его с помощью кнопки

btnRefreshAll.post(new StopUpdating());

Ещё вопросы

Сообщество Overcoder
Наверх
Меню