GFStableList Adapter

STL中,list的优点是插入、删除性能极佳(时间复杂度只需O(1)即可),而且非常重要的在删除节点后,其迭代器不失效,但list查找却不擅长。map由于其实现的数据结构为rb-tree,因此,其插入、删除以及查找的性能也都是非常不错的。如:插入、删除操作在多数情况下,可能只需要几个简单的数据交换、节点旋转即可达到目的,在这样情况下,时间复杂度也只有O(1)即可(当然,在最糟糕情况下,如插入、删除的时候产生上溯时,则时间复杂度最坏情况有可能达到2logN = O(logN),但由于rb-tree的性质原因,会产生最坏情况的机会也会比较少,而且大量试验证明,rb-tree的平均性能都是非常好的)。但是map容器在删除节点时,其迭代器是失效的

但在项目开发(尤其是在游戏项目开发)中,像设计角色管理器、技能管理器、buff管理器等等时候,经常会遇到这样一个问题(说明:此处以角色管理器为例说明)如下:

问题

游戏中(或战场中吧),每一个角色对象都有一个唯一Id,那么,这些游戏中的对象该如何维护?

解决

见过有的项目中是将这些角色对象用map来维护的。看上去好像是比较理想,因为它查找非常方便,而且在实际当中,也的的确确是需要频繁根据唯一Id查找对应的角色对象。但用map有个问题,在这些对象更新时,有可能会遇到角色死亡的情况,此时该如何处理这个对象?是立即移除?是先打标记然后再在全部更新之后,再一次性全部移除?又或者是都不移除只是不再更新它而已?事实上,这些处理方案都不理想。事实上,用这个方案的项目,最终的结果是:因为没办法在更新时移时移除掉这些“垃圾”角色对象,性能好坏且不说,整个代码最后都显得比较乱。因为用户在到处查找使用时,都是小心查看取出来的该对象是否是有效的。

另一种维护方案是使用list。该方案不必多说,数据组织与更新、移除都没啥大问题,就是查找效率不高。

鉴于前面综述情况,特地设计一个容器适配器GFStableList,其功能类似list,但却具有map的查找性能,并且支持erase时,reverse_iterator参数。编码如下:

  1 #pragma once
  2
  3 #include "src/Common/IncludeHeaders.h"
  4
  5 /******************************************************************************
  6  * create   : (jacc.kim) [3-1-2016]
  7  * summary  : class GFStableList.
  8  * !!!note  : 01.该列表中的元素的"Id"是不可以重复的.
  9  *            02.该列表稳定、支持快速查找、类似std::list删除时迭代器有效.
 10  *            03.使用时必需要设置 IdGetter 与 ValueDeleter 两个参数!!!
 11  *               使用时必需要设置 IdGetter 与 ValueDeleter 两个参数!!!
 12  *               使用时必需要设置 IdGetter 与 ValueDeleter 两个参数!!!
 13 ******************************************************************************/
 14 template<typename TValue, typename TId>
 15 class GFStableList
 16 {
 17 public:
 18     typedef typename std::list<TValue>                          value_list;
 19     typedef typename value_list::value_type                     value_type;
 20     typedef typename value_list::pointer                        pointer;
 21     typedef typename value_list::const_pointer                  const_pointer;
 22     typedef typename value_list::reference                      reference;
 23     typedef typename value_list::const_reference                const_reference;
 24     typedef typename value_list::difference_type                difference_type;
 25     typedef typename value_list::size_type                      size_type;
 26     typedef typename value_list::iterator                       iterator;
 27     typedef typename value_list::const_iterator                 const_iterator;
 28     typedef typename value_list::reverse_iterator               reverse_iterator;
 29     typedef typename value_list::const_reverse_iterator         const_reverse_iterator;
 30
 31     typedef typename TId                                        id_type;
 32     typedef typename std::function<id_type(const_reference)>    TGFvalueIdGetter;
 33     typedef typename std::function<void(const_reference)>       TGFvalueDeleter;
 34
 35 public:
 36     GFStableList();
 37     explicit GFStableList(const TGFvalueIdGetter& getter);
 38     GFStableList(const TGFvalueIdGetter& getter, const TGFvalueDeleter& deleter);
 39     ~GFStableList();
 40
 41     void                                setValueIdGetter(const TGFvalueIdGetter& getter);
 42     void                                setValueDeleter(const TGFvalueDeleter& deleter);
 43
 44     // !!!note: only no exist items & valid items will be insert or push.
 45     const bool                          push_front(const_reference value);
 46     const bool                          push_back(const_reference value);
 47     iterator                            insert(const_iterator _where, const_reference value);
 48     iterator                            insert(const_iterator _where, const_iterator _first, const_iterator _last);
 49
 50     iterator                            erase(const_reference value);
 51     iterator                            erase(const id_type& id);
 52     iterator                            erase(const_iterator _first, const_iterator _last);
 53     iterator                            erase(const_iterator _where);
 54     reverse_iterator                    erase(reverse_iterator _first, reverse_iterator _last);
 55     reverse_iterator                    erase(reverse_iterator _where);
 56     const_reverse_iterator              erase(const_reverse_iterator _first, const_reverse_iterator _last);
 57     const_reverse_iterator              erase(const_reverse_iterator _where);
 58     void                                clear();
 59     iterator                            find(const id_type& id);
 60     const_iterator                      find(const id_type& id) const;
 61
 62     iterator                            begin();
 63     const_iterator                      begin() const;
 64     iterator                            end();
 65     const_iterator                      end() const;
 66
 67     reverse_iterator                    rbegin();
 68     const_reverse_iterator              rbegin() const;
 69     reverse_iterator                    rend();
 70     const_reverse_iterator              rend() const;
 71
 72     const_iterator                      cbegin() const;
 73     const_iterator                      cend() const;
 74     const_reverse_iterator              crbegin() const;
 75     const_reverse_iterator              crend() const;
 76
 77     reference                           front();
 78     reference                           back();
 79     const_reference                     front() const;
 80     const_reference                     back() const;
 81
 82     void                                pop_front();
 83     void                                pop_back();
 84
 85     bool                                empty();
 86     size_type                           size();
 87
 88 private:
 89     GFStableList(const GFStableList<TValue, TId>& listValues) = delete;
 90
 91 private:
 92     typedef typename std::map<id_type, iterator>        id_value_map;
 93
 94     void                                _clearValueList();
 95     void                                _clearMapping();
 96     iterator                            _locate(const_reference value);
 97     const_iterator                      _locate(const_reference value) const;
 98     iterator                            _locate(const id_type& id);
 99     const_iterator                      _locate(const id_type& id) const;
100     const bool                          _isExisted(const id_type& id);
101     const bool                          _isExisted(const_reference value);
102     const id_type                       _getValueId(const_reference value);
103
104 private:
105     TGFvalueIdGetter                    m_IdGetter;
106     TGFvalueDeleter                     m_ValueDeleter;
107     value_list                          m_listValues;
108     id_value_map                        m_mapMapping;
109
110 };//template<typename TValue, typename TId> class GFStableList
111
112 #include "src/Common/GFStableList.inl"

GFStableList.h文件

  1 #include "src/Common/IncludeHeaders.h"
  2
  3 ///////////////////////////////////////////////////////////////////////////////
  4 // template<typename TValue, typename TId> class GFStableList
  5 template<typename TValue, typename TId>
  6 GFStableList<TValue, TId>::GFStableList() : m_IdGetter    (nullptr)
  7                                           , m_ValueDeleter(nullptr)
  8                                           , m_listValues  ()
  9                                           , m_mapMapping  ()
 10 {
 11
 12 }
 13
 14 template<typename TValue, typename TId>
 15 GFStableList<TValue, TId>::GFStableList(const TGFvalueIdGetter& getter) : m_IdGetter    (getter)
 16                                                                         , m_ValueDeleter(nullptr)
 17                                                                         , m_listValues  ()
 18                                                                         , m_mapMapping  ()
 19 {
 20
 21 }
 22
 23 template<typename TValue, typename TId>
 24 GFStableList<TValue, TId>::GFStableList(const TGFvalueIdGetter& getter, const TGFvalueDeleter& deleter) : m_IdGetter    (getter)
 25                                                                                                         , m_ValueDeleter(deleter)
 26                                                                                                         , m_listValues  ()
 27                                                                                                         , m_mapMapping  ()
 28 {
 29
 30 }
 31
 32 template<typename TValue, typename TId>
 33 GFStableList<TValue, TId>::~GFStableList() {
 34     this->clear();
 35 }
 36
 37 template<typename TValue, typename TId>
 38 void GFStableList<TValue, TId>::setValueIdGetter(const TGFvalueIdGetter& getter) {
 39     m_IdGetter = getter;
 40     //GFAssert(nullptr != m_IdGetter, "the id getter is nullptr.");
 41 }
 42
 43 template<typename TValue, typename TId>
 44 void GFStableList<TValue, TId>::setValueDeleter(const TGFvalueDeleter& deleter) {
 45     m_ValueDeleter = deleter;
 46 }
 47
 48 template<typename TValue, typename TId>
 49 const bool GFStableList<TValue, TId>::push_front(const_reference value) {
 50     return insert(begin(), value) != end();
 51 }
 52
 53 template<typename TValue, typename TId>
 54 const bool GFStableList<TValue, TId>::push_back(const_reference value) {
 55     return insert(end(), value) != end();
 56 }
 57
 58 template<typename TValue, typename TId>
 59 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::insert(const_iterator _where, const_reference value) {
 60     if (nullptr == value) {
 61         return end();
 62     }
 63
 64     const auto id = _getValueId(value);
 65     if (_isExisted(id)) {
 66         return end();// 已经存在了.
 67     }
 68
 69     auto iter = m_listValues.insert(_where, value);
 70     m_mapMapping[id] = iter;
 71     return iter;
 72 }
 73
 74 template<typename TValue, typename TId>
 75 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::insert(const_iterator _where, const_iterator _first, const_iterator _last) {
 76     if (_first == end() || _first == _last) {
 77         return;
 78     }
 79     auto insert_pos = end();
 80     iterator tmpResult;
 81     id_type id;
 82     for (auto iter = _first; iter != _last; ++iter) {
 83         id = _getValueId(*iter);
 84         if (_isExisted(id)) {
 85             continue;// id is existed.
 86         }
 87         tmpResult = m_listValues.insert(_where, *iter);
 88         m_mapMapping[id] = tmpResult;
 89
 90         if (insert_pos == end()) {
 91             insert_pos = tmpResult;
 92         }
 93     }
 94     return insert_pos;
 95 }
 96
 97 template<typename TValue, typename TId>
 98 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::erase(const_reference value) {
 99     auto iter = _locate(value);
100     return erase(iter);
101 }
102
103 template<typename TValue, typename TId>
104 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::erase(const id_type& id) {
105     auto iter = _locate(id);
106     return erase(iter);
107 }
108
109 template<typename TValue, typename TId>
110 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::erase(const_iterator _first, const_iterator _last) {
111     if (_first == end()) {
112         return end();
113     }
114     if (_first == begin() && _last == end()) {
115         this->clear();
116         return end();
117     }
118     iterator retIter = end();
119     auto iter = _first;
120     while (iter != _last && iter != end()) {
121         retIter = this->erase(iter);
122         iter = retIter;
123     }
124     return retIter;
125 }
126
127 template<typename TValue, typename TId>
128 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::erase(const_iterator _where) {
129     if (_where == end()) {
130         return end();
131     }
132     const auto id = _getValueId(*_where);
133     m_mapMapping.erase(id);
134     return m_listValues.erase(_where);
135 }
136
137 template<typename TValue, typename TId>
138 typename GFStableList<TValue, TId>::reverse_iterator GFStableList<TValue, TId>::erase(reverse_iterator _first, reverse_iterator _last) {
139     if (_first == rend()) {
140         return rend();
141     }
142     if (_first == rbegin() && _last == rend()) {
143         this->clear();
144         return rend();
145     }
146     reverse_iterator retIter = rend();
147     auto iter = _first;
148     while (iter != _last && iter != rend()) {
149         retIter = this->erase(iter);
150         iter = retIter;
151     }
152     return retIter;
153 }
154
155 template<typename TValue, typename TId>
156 typename GFStableList<TValue, TId>::reverse_iterator GFStableList<TValue, TId>::erase(reverse_iterator _where) {
157     if (_where == rend()) {
158         return rend();
159     }
160
161     auto ret_iter = _where; // 返回值.
162     ++ret_iter;
163
164     const auto id = _getValueId(*_where.base());
165     this->erase(id);
166
167     return ret_iter;
168 }
169
170 template<typename TValue, typename TId>
171 typename GFStableList<TValue, TId>::const_reverse_iterator GFStableList<TValue, TId>::erase(const_reverse_iterator _first, const_reverse_iterator _last) {
172     if (_first == rend()) {
173         return rend();
174     }
175     if (_first == rbegin() && _last == rend()) {
176         this->clear();
177         return rend();
178     }
179     const_reverse_iterator retIter = rend();
180     auto iter = _first;
181     while (iter != _last && iter != rend()) {
182         retIter = this->erase(iter);
183         iter = retIter;
184     }
185     return retIter;
186 }
187
188 template<typename TValue, typename TId>
189 typename GFStableList<TValue, TId>::const_reverse_iterator GFStableList<TValue, TId>::erase(const_reverse_iterator _where) {
190     if (_where == rend()) {
191         return rend();
192     }
193
194     auto ret_iter = _where; // 返回值.
195     ++ret_iter;
196
197     const auto id = _getValueId(*_where.base());
198     this->erase(id);
199
200     return ret_iter;
201 }
202
203 template<typename TValue, typename TId>
204 void GFStableList<TValue, TId>::clear() {
205     _clearValueList();
206     _clearMapping();
207 }
208
209 template<typename TValue, typename TId>
210 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::find(const id_type& id) {
211     return _locate(id);
212 }
213
214 template<typename TValue, typename TId>
215 typename GFStableList<TValue, TId>::const_iterator GFStableList<TValue, TId>::find(const id_type& id) const {
216     return _locate(id);
217 }
218
219 template<typename TValue, typename TId>
220 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::begin() {
221     return m_listValues.begin();
222 }
223
224 template<typename TValue, typename TId>
225 typename GFStableList<TValue, TId>::const_iterator GFStableList<TValue, TId>::begin() const {
226     return m_listValues.begin();
227 }
228
229 template<typename TValue, typename TId>
230 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::end() {
231     return m_listValues.end();
232 }
233
234 template<typename TValue, typename TId>
235 typename GFStableList<TValue, TId>::const_iterator GFStableList<TValue, TId>::end() const {
236     return m_listValues.end();
237 }
238
239 template<typename TValue, typename TId>
240 typename GFStableList<TValue, TId>::reverse_iterator GFStableList<TValue, TId>::rbegin() {
241     return m_listValues.rbegin();
242 }
243
244 template<typename TValue, typename TId>
245 typename GFStableList<TValue, TId>::const_reverse_iterator GFStableList<TValue, TId>::rbegin() const {
246     return m_listValues.rbegin();
247 }
248
249 template<typename TValue, typename TId>
250 typename GFStableList<TValue, TId>::reverse_iterator GFStableList<TValue, TId>::rend() {
251     return m_listValues.rend();
252 }
253
254 template<typename TValue, typename TId>
255 typename GFStableList<TValue, TId>::const_reverse_iterator GFStableList<TValue, TId>::rend() const {
256     return m_listValues.rend();
257 }
258
259 template<typename TValue, typename TId>
260 typename GFStableList<TValue, TId>::const_iterator GFStableList<TValue, TId>::cbegin() const {
261     return m_listValues.cbegin();
262 }
263
264 template<typename TValue, typename TId>
265 typename GFStableList<TValue, TId>::const_iterator GFStableList<TValue, TId>::cend() const {
266     return m_listValues.cend();
267 }
268
269 template<typename TValue, typename TId>
270 typename GFStableList<TValue, TId>::const_reverse_iterator GFStableList<TValue, TId>::crbegin() const {
271     return m_listValues.crbegin();
272 }
273
274 template<typename TValue, typename TId>
275 typename GFStableList<TValue, TId>::const_reverse_iterator GFStableList<TValue, TId>::crend() const {
276     return m_listValues.crend();
277 }
278
279 template<typename TValue, typename TId>
280 typename GFStableList<TValue, TId>::reference GFStableList<TValue, TId>::front() {
281     return m_listValues.front();
282 }
283
284 template<typename TValue, typename TId>
285 typename GFStableList<TValue, TId>::reference GFStableList<TValue, TId>::back() {
286     return m_listValues.back();
287 }
288
289 template<typename TValue, typename TId>
290 typename GFStableList<TValue, TId>::const_reference GFStableList<TValue, TId>::front() const {
291     return m_listValues.front();
292 }
293
294 template<typename TValue, typename TId>
295 typename GFStableList<TValue, TId>::const_reference GFStableList<TValue, TId>::back() const {
296     return m_listValues.end();
297 }
298
299 template<typename TValue, typename TId>
300 void GFStableList<TValue, TId>::pop_front() {
301     if (this->empty()) {
302         return;
303     }
304     auto iter = this->begin();
305     const auto id = _getValueId(*iter);
306     this->erase(id);
307 }
308
309 template<typename TValue, typename TId>
310 void GFStableList<TValue, TId>::pop_back() {
311     if (this->empty()) {
312         return;
313     }
314     auto riter = this->rbegin();
315     const auto id = _getValueId(*riter);
316     this->erase(id);
317 }
318
319 template<typename TValue, typename TId>
320 bool GFStableList<TValue, TId>::empty() {
321     return m_listValues.empty();
322 }
323
324 template<typename TValue, typename TId>
325 typename GFStableList<TValue, TId>::size_type GFStableList<TValue, TId>::size() {
326     return m_listValues.size();
327 }
328
329 template<typename TValue, typename TId>
330 void GFStableList<TValue, TId>::_clearValueList() {
331     if (nullptr != m_ValueDeleter) {
332         auto iter = m_listValues.begin();
333         auto iterend = m_listValues.end();
334         for (; iter != iterend; ++iter) {
335             m_ValueDeleter(*iter);
336         }
337     }
338     m_listValues.clear();
339 }
340
341 template<typename TValue, typename TId>
342 void GFStableList<TValue, TId>::_clearMapping() {
343     m_mapMapping.clear();
344 }
345
346 template<typename TValue, typename TId>
347 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::_locate(const_reference value) {
348     const auto id = m_IdGetter(value);
349     return _locate(id);
350 }
351
352 template<typename TValue, typename TId>
353 typename GFStableList<TValue, TId>::const_iterator GFStableList<TValue, TId>::_locate(const_reference value) const {
354     const auto id = m_IdGetter(value);
355     return _locate(id);
356 }
357
358 template<typename TValue, typename TId>
359 typename GFStableList<TValue, TId>::iterator GFStableList<TValue, TId>::_locate(const id_type& id) {
360     auto iter = m_mapMapping.find(id);
361     if (iter == m_mapMapping.end()) {
362         return end();
363     }
364     return iter->second;
365 }
366
367 template<typename TValue, typename TId>
368 typename GFStableList<TValue, TId>::const_iterator GFStableList<TValue, TId>::_locate(const id_type& id) const {
369     auto iter = m_mapMapping.find(id);
370     if (iter == m_mapMapping.end()) {
371         return end();
372     }
373     return iter->second;
374 }
375
376 template<typename TValue, typename TId>
377 const bool GFStableList<TValue, TId>::_isExisted(const id_type& id) {
378     auto iter = m_mapMapping.find(id);
379     return iter != m_mapMapping.end();
380 }
381
382 template<typename TValue, typename TId>
383 const bool GFStableList<TValue, TId>::_isExisted(const_reference value) {
384     auto id = _getValueId(value);
385     return _isExisted(id);
386 }
387
388 template<typename TValue, typename TId>
389 typename const GFStableList<TValue, TId>::id_type GFStableList<TValue, TId>::_getValueId(const_reference value) {
390     return m_IdGetter(value);
391 }

GFStableList.inl文件

时间: 2024-10-24 13:32:21

GFStableList Adapter的相关文章

Android开发--Adapter的应用

1.简介 Adapter的作用是为GridView,ListView等界面控件与数据之间搭建桥梁,每当列表里的每一项显示到页面时,都会调用到Adapter的getView方法 返回一个View.在Android API中内置了几个实现ListAdapter的Adapter,它们分别为BaseAdapter,SimpleAdapter(以Map形式存储静态数据), SimpleCursorAdapter.Adapter,数据和UI三者关系如下: 2.BaseAdapter 自定义BaseAdapt

设计模式之Adapter(适配器)(转)

定义: 将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和Adaptor(适配器)两个身份. 为何使用? 我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:修改各自类的接口,但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口. 怎么办? 使用Adapter,在这两种接口之间创建一个混合接口(混血儿). 如何使用? 实现Adapter方式,其实"think in Java"的"类再生"一节中已经提到,有两

适配器模式(Adapter)

1.定义: 适配器模式是将一个类的接口转换成客户端希望的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 结构与说明: Client:客户端,调用自己需要的领域接口Target. Target:定义客户端需要的跟特定领域相关的接口. Adaptee:已经存在的接口,但与客户端需要的特定领域接口不一致,需要被适配. Adapter:适配器,把Adaptee适配成Client需要的Target. 2.代码示例 (1)已经存在的应用接口,需要被适配的类Adaptee 1

Android中适用于ListView、GridView等组件的通用Adapter

今天随便逛逛CSDN,看到主页上推荐了一篇文章Android 快速开发系列 打造万能的ListView GridView 适配器,刚好这两天写项目自己也封装了类似的CommonAdapter,以前也在github上看到过这样的库,于是自己也把自己的代码再次整理出来与大家分享,也希望能够在CSDN这个平台上学到更多的东西,下面就一起来看看吧. 平时我们在项目中使用到ListView和GridView组件都是都会用到Adapter,比较多的情况是继承自BaseAdapter,然后实现getCount

ViewPager的Adapter中视图重用

ViewPager的PagerAdapter不像ListView/GridView的BaseAdapter,它是没有内部视图重用机制的,也就是说我先inflate出来一个,然后调用destroyItem后,这个视图就被抛弃了,如果需要更多的视图,则需要再次inflate.如果ViewPager中的所有视图基本相同,就存在内存的浪费了.这里使用一个非常简单的方法实现视图的重用: List<View> mViewList = new ArrayList<View>(); public

设计模式之四:适配器模式(Adapter Pattern)

在软件系统中,由于应用环境的变化,常常需要将"一些现存的对象"放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的.如果能既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?这就是适配器模式要解决的问题. 目的:将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 下面以日志记录程序为例子说明Adapter模式.假设我们在软件开发中要记录日志,包括数据库记录日志DatabaseLog和文本文件

Android开发笔记(12)——ListView &amp; Adapter

转载请注明:http://www.cnblogs.com/igoslly/p/6947225.html 下一章是关于ListFragment的内容,首先先介绍ListView的相关配置,理解ListFragment也相较容易. 在fznpcy专栏:http://blog.csdn.net/fznpcy/article/details/8658155/有较为详尽的讲解和范例. ListView & Adapter 一.Adapter Adapter是连接后端数据和前端显示的适配器接口,是数据和UI

ListView和Adapter信息显示

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" andr

Listview和Adapter作业

安卓作业:使用ListView和自定义Adapter完成列表信息显示 1.XML主布局文件代码 <?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"