Android:正在运行的线程阻止动画启动

发布于 2024-12-02 12:01:24 字数 3336 浏览 1 评论 0原文

我目前有一个 Android 活动,它管理一些本地存储的 RSS 提要。在此活动中,这些提要通过私有类在其自己的线程中更新。我还尝试添加一个“更新”图标,该图标在该线程运行时随 RotateAnimation 旋转。

动画本身可以工作,但在线程运行时不起作用,尽管日志条目表明代码正在执行。我怀疑这是因为线程不完全安全,并且占用了大部分 CPU 时间。不过我只是想知道是否有更好的方法来实现这一目标。

函数 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 位是不好的做法,这是我计划整理的接下来的事情之一)。

非常感谢任何帮助,非常感谢。

I currently have an Android activity which manages some locally-stored RSS feeds. In this activity, these feeds are updated in their own thread via a private class. I'm also trying to include an "updating" icon that rotates with a RotateAnimation while this thread is running.

The animation works by itself, but doesn't work while the thread is running despite the log entries stating the code is being executed. I suspect this is due to the thread not being entirely safe, and taking up most of the CPU time. However I'd just like to know if there's a better way of achieving this.

The function updateAllFeeds() is called from a button press. Here's the relevant code:

/**
 * 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

(I know the updateStatus == 2 bit is bad practice, that's one of the next things I plan to tidy up).

Any help is greatly appreciated, many thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

北笙凉宸 2024-12-09 12:01:24

在单独的线程中运行可运行的更新程序。进行以下更改。

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

runOnUiThread 块中调用 stopUpdating()

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

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

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

Run the updater runnable in a separate thread. Do the following changes.

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

Call stopUpdating() in runOnUiThread block.

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

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

    }   // End run()
}   // End class Updater
深巷少女 2024-12-09 12:01:24

将影响 UI 的所有内容移至其自己的 Runnable 中,然后使用按钮将其发布

btnRefreshAll.post(new StopUpdating());

Move anything that affects the UI off into its own Runnable and then post it with your button

btnRefreshAll.post(new StopUpdating());

阳光下的泡沫是彩色的 2024-12-09 12:01:24

我昨晚设法使用 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 的任何问题,我可以将其用作备份。

I managed to get this working last night using Android's AsyncTask class. It was surprisingly easy to implement, though the downside was I had to write one class for updating an individual feed, and another for updating all feeds. Here's the code for updating all feeds at once:

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();
    }
}

Thanks for your answers guys. userSeven7s' reply also makes a lot of sense so I may use that as a backup should I run into any problems with AsyncTask.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文