В настоящее время у меня есть активность 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
бит - это плохая практика, одна из следующих вещей, которую я планирую убрать).
Любая помощь очень ценится, большое спасибо заранее.
Запустите программу обновления в отдельном потоке. Выполните следующие изменения.
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
Мне удалось получить эту работу прошлой ночью, используя класс 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.
Переместите все, что влияет на пользовательский интерфейс, на свой собственный Runnable
а затем разместите его с помощью кнопки
btnRefreshAll.post(new StopUpdating());
AsyncTask
обрабатывает это для вас, выполняяonPostExecute
иonPreExecute
в главном потоке. Вы можете получить тот же результат, разместив логику обновления пользовательского интерфейса в главном потоке, используяHandler
иMessage
.