我有一个扩展LinearLayout的类。我的课程在我的应用程序的许多地方使用。在课堂上我创建了一个处理程序:
Handler updateHandler = new Handler() {
public void handleMessage(Message msg) {
// Update image, other items, etc.
}
};
将此处理程序传递给静态方法并保存,以便在出现某些条件时,可以相应地更新与此句柄关联的所有视图。
问题在于我相信我会无限期地持有对视图的引用。因此,举个例子,我在ExtendedList中使用自定义类,用户折叠显示我的类视图的组。从技术上讲,它已不再使用,但它的处理程序仍会在条件出现时被解雇。
我有更好的方法吗?有没有办法知道视图何时被销毁/处置并且操作系统不再使用它?
BTW:我的目标是SDK版本7。
修改
为了更好地澄清,我将提供一个真实的场景,非常适合我正在尝试做的事情。这是一个人为的例子。
想象一下,你有一张国家的地图。在地图上,您可以看到每个城市的ImageView,显示城市的当前天气。当天气变化时,ImageView需要改变以反映新的天气状况 - 无论是晴天,下雨,下雪等等。
要将此应用于我原来的问题,我会创建一个名为WeatherView
的类,其扩展ImageView
。在WeatherView
里面,我有一个Handler,它被添加到某个静态列表中。在后台线程中并由计时器触发,我使用一个Web服务来提供给定城市的天气。当天气变化时,我会转到我的静态处理程序列表,找出哪些城市需要更新其图像,然后触发“事件”。
现在假设用户切换州或国家/地区,原始城市不再有效。他们的处理程序仍然存在于列表中,因此它们将继续占用内存和资源。
答案 0 :(得分:0)
将此处理程序传递给静态方法并保存,以便在出现某些条件时,可以相应地更新与此句柄关联的所有视图。
伊克。
我有更好的方法吗?
在Android中,您的用户界面由一个活动组成,持有视图(暂时忽略片段)。当“某些条件出现”时,无论是什么导致“某些条件”“出现”(Service
,BroadcastReceiver
,$DEITY
的行为,无论如何)都应该通知该事件的活动。反过来,该活动可以通知需要了解该事件的任何观点。
对于此,您不需要每个视图Handler
。只需让活动在自定义View
上调用方法即可。这样重量更轻,编码更少,更易于维护。
您不需要静态数据成员。虽然您可能希望在活动中维护(非静态)缓存以便于访问需要此事件的那些视图,但该活动已有其视图。这可以避免任何内存泄漏的可能性。
更新(基于已修改的问题)
想象一下,你有一张国家的地图。在地图上,您可以看到每个城市的ImageView,显示城市的当前天气。当天气变化时,ImageView需要改变以反映新的天气状况 - 无论是晴天,下雨,下雪等等。
这些都不需要一组Handlers
,也不需要静态数据成员。这一切都在一项活动中。
在后台线程中并由计时器触发,我使用一个Web服务来提供给定城市的天气。当天气变化时,我会转到我的静态处理程序列表,找出需要更新图像的城市,然后触发“事件”。
如果“后台线程”只是由活动分叉,则不需要静态数据成员,也不需要一堆Handlers
。您需要一个Handler
,由活动创建/拥有,传递到线程中(并且还在配置更改时在活动实例之间传递),并让线程向Handler发送一条消息。处理程序和活动协作以通知所有ImageViews
。
如果“后台线程”是IntentService
,则会保留相同的模型,除非您将Messenger
从活动传递到服务,因为您不能(也不应该)传递通过Handler
额外的组件之间的Intent
。再一次,您不需要静态数据成员,也不需要每个视图一个Handler
。
答案 1 :(得分:0)
首先,您不应该在静态字段中保留对contexts / activities / views的引用,以避免内存泄漏。 (见Avoiding Memory leaks)
我不知道你想要做什么,但应该可以在每个Activity中创建一个Handler并在Activity被销毁时销毁Handler。为此,请使用Activity生命周期方法。
如果我理解正确,您将更新整个应用程序中的所有视图(在所有活动中)。这在性能方面很可能并不好。
修改强>
视图应该只显示数据。他们永远不应该实现业务逻辑,比如获取数据。
要解决您的示例,您可以将所有WeatherView存储在HashTable / ArrayList或其他任何内容中,并且您的Activity会定期轮询天气服务。如果天气发生变化,则查看视图使用HashTable获取正确的WeatherView并进行更新。
public class WeatherMapActivity extends ListActivity {
class WeatherData{};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<WeatherData>(this,android.R.layout.simple_list_item_1, android.R.id.text1, new ArrayList<WeatherData>()));
}
class WeatherTask extends AsyncTask<String, Void, HashMap<String, WeatherData>> {
@Override
protected HashMap doInBackground(String... cities) {
HashMap<String, WeatherData> data = new HashMap<String, WeatherMapActivity.WeatherData>();
for (String city : cities) {
WeatherData fetchedData = null;
// fetch weather from server
data.put(city, fetchedData);
}
return data;
}
protected void onPostExecute(HashMap<String, WeatherData> fetchedData) {
ArrayAdapter<WeatherData> adapter = (ArrayAdapter<WeatherData>) getListAdapter();
// now remove/add/update data in the adapter
//update the list view
adapter.notifyDataSetChanged();
}
}
}