android饿了么源码
1. 饿了么网站外卖,手机订餐网站外卖系统源码
昨天出去收到这个网站的app应用宣传单。
黄岛区城市建设局昆仑山路无负压供水设备招标内幕! 第一、四家有效报价:1.上海熊猫:490万;2.北京威派格:816万;3.青岛三利:1292万;4.广东盛腾:1330万。中标厂家青岛三利。中标价格和最低报价相差802万元,和次低价相差476万元。第二、同样是有效报价,同样满足招标要求,1292万元足够买两套同样的设备,政府的资金就这样浪费吗?请问是如何监管的?何以防止腐败!本次采购的设备全国同行业的生产成本均在500万左右。第三、请问专家们中午休息时间在干什么,下午上班后20多分钟就评审完毕,每家的评分为什么不公开?请问你们的一分值多少钱?仅靠你们的分数就决定国家的损失500万到800万元!第四、按照开标程序,应该先公开报价后再评审商务标和技术标及资格标。第五、休息时间中标厂家的授权代表手拿一个纸袋子上去(看到某个人递给他),请问纸袋子给谁了?请公示录像。具备贿赂专家的嫌疑!请查实!第六、最高价广东盛腾具有陪标嫌疑,请核查。
答复意见:
尊敬的网友:您好!您反映的问题,黄岛区政府经调查处理,现答复如下:
经查,本次采购招标严格按照《政府采购货物和服务招标投标管理办法》规定进行。采购的评审办法为综合评分法,价格只是评分因素之一,并不能决定中标与否。本次评审专家是从依法取得政府采购评审专家资格的人员库库中随机抽取的,评审专家对各投标人的商务标书和技术标书的评审是没有先后顺序的,评审过程也没有规定休息时间。根据采购文件规定,商务部分打分需要交各供应商签字确认,而各供应商的技术打分则不予公布。以上在采购文件中已做出了详细的说明。对您提出中标厂家贿赂专家问题,黄岛区公共资源交易服务中心经查看了当天的监控录像,该项目整个评标期间评标委员会成员没有离开评标区域,也没有发现评标委员会成员与其他无关人员私下接触现象。最后,经与中标厂家授权代表进行核实,其表示当天中午确实有拎着装有材料的纸袋下楼吃饭的情况,与监控录像相符,不存在贿赂专家问题。
本项目开标后,您所在的北京威派格科技发展有限公司曾就以上问题提出书面质疑,黄岛区城市建设局、公共资源交易中心及采购代理青岛采购招标中心有限公司已给予了书面回复,并与您单位授权代表进行了沟通。公司代表已同意我们的回复意见。
绝对的注册的假公司,陪标。
2. 饿了么源码 百度外卖源码 美团外卖源码 外卖系统源码
http://www.aspku.com/php/47690.html
3. android studio饿了么源码 博客
tvSearchRlt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,SearchActivity.class);
int location[] = new int[2];
tvSearchRlt.getLocationOnScreen(location);
intent.putExtra("x",location[0]);
intent.putExtra("y",location[1]);
startActivity(intent);
overridePendingTransition(0,0);
}
});
4. 饿了么开源的Android跨进程事件分发框架HermesEventBus
原理
事件收发是基于EventBus,IPC通信是基于Hermes。Hermes是一个简单易用的Android IPC库。
首先选一个进程作为主进程,将其他进程作为子进程。
每次一个event被发送都会经过以下四步:
1、使用Hermes库将event传递给主进程。
2、主进程使用EventBus在主进程内部发送event。
3、主进程使用Hermes库将event传递给所有的子进程。
4、每个子进程使用EventBus在子进程内部发送event。
用法
能在app内实现多进程event收发,也可以跨app实现event收发。
单一app内的用法
如果你在单一app内进行多进程开发,那么只需要做以下三步:
Step 1
在gradle文件中加入下面的依赖:
dependencies {
compile 'xiaofei.library:hermes-eventbus:0.1.1'
}
Step 2
在Application的onCreate中加上以下语句进行初始化:
HermesEventBus.getDefault().init(this);
Step 3
每次使用EventBus的时候,用HermesEventBus代替EventBus。
HermesEventBus.getDefault().register(this);
HermesEventBus.getDefault().post(new Event());
HermesEventBus也能够在一个进程间传递event,所以如果你已经使用了HermesEventBus,那么就不要再使用EventBus了。
多个app间的用法(使用DroidPlugin的时候就是这种情况)
如果你想在多个app间收发event,那么就做如下几步:
Step 1
在每个app的gradle文件中加入依赖:
dependencies {
compile 'xiaofei.library:hermes-eventbus:0.1.1'
}
Step 2
选择一个app作为主app。你可以选择任意app作为主app,但最好选择那个存活时间最长的app。
在使用DroidPlugin的时候,你可以把宿主app作为主app。
在主app的AndroidManifest.xml中加入下面的service:
<service android:name="xiaofei.library.hermes.HermesService$HermesService0"/>
你可以加上一些属性。
Step 3
在app间收发的事件类必须有相同的包名、相同的类名和相同的方法。
务必记住在代码混淆的时候将这些类keep!!!
Step 4
在主app的application类的onCreate方法中加入:
HermesEventBus.getDefault().init(this);
在其他app的Application类的onCreate方法中加入:
HermesEventBus.getDefault().connectApp(this, packageName);
“packageName”指的是主app的包名。
Step 5
每次使用EventBus的时候,用HermesEventBus代替EventBus。
HermesEventBus.getDefault().register(this);
HermesEventBus.getDefault().post(new Event());
HermesEventBus也能够在一个进程间传递event,所以如果你已经使用了HermesEventBus,那么就不要再使用EventBus了。
5. 饿了么开源的Android跨进程事件分发框架Hermes EventBus
event究竟有多么复杂?可见前辈的6年前的努力:最佳的addEvent是怎样诞生的,后起之秀jQuery也付出了一千六百多行血汗代码(v 1 - MIT Licensed /** * 事件框架 * @namespace * @see /?p=1285 */ var myEvent = (function () { var _fid = 1, _guid = 1, _time = (new Date) - MIT Licensed /** * 事件框架 * @namespace * @see /?p=1285 */ var myEvent = (function () { var _ret, _name, _fid = 1, _guid = 1, _time = (new Date).getTime(), _nEid = '{$eid}' + _time, _nFid = '{$fid}' + _time, _DOM = document.addEventListener, _noop = function () {}, _create = function (guid) { return function (event) { event = myEvent.fix(event window.event); var type = (event (event = document.event)).type, elem = _cache[guid].elem, data = arguments, events = _cache[guid].events[type], i = 0, length = events.length; for (; i < length; i ++) { if (events[i].apply(elem, data) === false) event.preventDefault(); }; event = elem = null; }; }, _cache = {/* 1: { elem: (HTMLElement), events: { click: [(Function), (..)], (..) }, listener: (Function) }, (..) */}; var API = function () {}; API.prototype = { /** * 事件绑定 * @param {HTMLElement} 元素 * @param {String} 事件名 * @param {Function} 要绑定的函数 */ bind: function (elem, type, callback) { var events, listener, guid = elem[_nEid] (elem[_nEid] = _guid ++), special = this.special[type] {}, cacheData = _cache[guid]; if (!cacheData) cacheData = _cache[guid] = { elem: elem, listener: _create(guid), events: {} }; events = cacheData.events; listener = cacheData.listener; if (!events[type]) events[type] = []; if (!callback[_nFid]) callback[_nFid] = _fid ++; if (!special.setup special.setup.call(elem, listener) === false) { events[type].length === 0 && this.add(elem, type, listener); }; events[type].push(callback); }, /** * 事件卸载 * @param {HTMLElement} 元素 * @param {String} 事件名 * @param {Function} 要卸载的函数 */ unbind: function (elem, type, callback) { var events, special, i, list, fid, guid = elem[_nEid], cacheData = _cache[guid]; if (!cacheData) return; events = cacheData.events; if (callback) { list = events[type]; fid = callback[_nFid]; if (!list) return; for (i = 0; i < list.length; i ++) { list[i][_nFid] === fid && list.splice(i--, 1); }; if (!list.length) this.unbind(elem, type); } else if (type) { special = this.special[type] {}; if (!special.teardown special.teardown.call(elem) === false) { this.remove(elem, type, cacheData.listener); }; delete events[type]; } else { for (i in events) { this.remove(elem, i, cacheData.listener); }; delete _cache[guid]; }; }, /** * 事件触发 (注意:不会触发浏览器默认行为与冒泡) * @param {HTMLElement} 元素 * @param {String} 事件名 * @param {Array} (可选)附加数据 */ triggerHandler: function (elem, type, data) { var guid = elem[_nEid], cacheData = _cache[guid], event = { type: type, target: elem, currentTarget: elem, preventDefault: _noop, stopPropagation: _noop }; data = data []; data.unshift(event); cacheData && cacheData.events[type] && _cache[guid].listener.apply(elem, data); try { elem['on' + type] && elem['on' + type].apply(elem, data); //elem[type] && elem[type](); } catch (e) {}; }, // 自定义事件接口 special: {}, // 原生事件绑定接口 add: _DOM ? function (elem, type, listener) { elem.addEventListener(type, listener, false); } : function (elem, type, listener) { elem.attachEvent('on' + type, listener); }, // 原生事件卸载接口 remove: _DOM ? function (elem, type, listener) { elem.removeEventListener(type, listener, false); } : function (elem, type, listener) { elem.detachEvent('on' + type, listener); }, // 修正 fix: function (event) { if (_DOM) return event; var name, newEvent = {}, doc = document.documentElement, body = document.body; newEvent.target = event.srcElement document; newEvent.target.nodeType === 3 && (newEvent.target = newEvent.target.parentNode); newEvent.preventDefault = function () {event.returnValue = false}; newEvent.stopPropagation = function () {event.cancelBubble = true}; newEvent.pageX = newEvent.clientX + (doc && doc.scrollLeft body && body.scrollLeft 0) - (doc && doc.clientLeft body && body.clientLeft 0); newEvent.pageY = newEvent.clientY + (doc && doc.scrollTop body && body.scrollTop 0) - (doc && doc.clientTop body && body.clientTop 0); newEvent.relatedTarget = event.fromElement === newEvent.target ? event.toElement : event.fromElement; // !!直接写event IE导致内存泄漏,Firefox会报错 // 伪装event for (name in event) newEvent[name] = event[name]; return newEvent; } }; return new API(); })(); // DOM就绪事件 myEvent.ready = (function () { var readyList = [], DOMContentLoaded, readyBound = false, isReady = false; function ready () { if (!isReady) { if (!document.body) return setTimeout(ready, 13); isReady = true; if (readyList) { var fn, i = 0; while ((fn = readyList[i++])) { fn.call(document, {}); }; readyList = null; }; }; }; function bindReady () { if (readyBound) return; readyBound = true; if (document.readyState === 'complete') { return ready(); }; if (document.addEventListener) { document.addEventListener('DOMContentLoaded', DOMContentLoaded, false); window.addEventListener('load', ready, false); } else if (document.attachEvent) { document.attachEvent('onreadystatechange', DOMContentLoaded); window.attachEvent('onload', ready); var toplevel = false; try { toplevel = window.frameElement == null; } catch (e) {}; if (document.documentElement.doScroll && toplevel) { doScrollCheck(); }; }; }; myEvent.special.ready = { setup: bindReady, teardown: function () {} }; if (document.addEventListener) { DOMContentLoaded = function () { document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false); ready(); }; } else if (document.attachEvent) { DOMContentLoaded = function () { if (document.readyState === 'complete') { document.detachEvent('onreadystatechange', DOMContentLoaded); ready(); }; }; }; function doScrollCheck () { if (isReady) return; try { document.documentElement.doScroll('left'); } catch (e) { setTimeout(doScrollCheck, 1); return; }; ready(); }; return function (callback) { bindReady(); if (isReady) { callback.call(document, {}); } else if (readyList) { readyList.push(callback); }; return this; }; })(); // Hashchange Event v1.3 (function (window, undefined) { var config = { delay: 50, src: null, domain: null }, str_hashchange = 'hashchange', doc = document, isIE = !-[1,], fake_onhashchange, special = myEvent.special, doc_mode = doc.documentMode, supports_onhashchange = 'on' + str_hashchange in window && (doc_mode === undefined doc_mode > 7); function get_fragment(url) { url = url location.href; return '#' + url.replace(/^[^#]*#?(.*)$/, '$1'); }; special[str_hashchange] = { setup: function () { if (supports_onhashchange) return false; myEvent.ready(fake_onhashchange.start); }, teardown: function () { if (supports_onhashchange) return false; myEvent.ready(fake_onhashchange.stop); } }; /** @inner */ fake_onhashchange = (function () { var self = {}, timeout_id, last_hash = get_fragment(), /** @inner */ fn_retval = function (val) { return val; }, history_set = fn_retval, history_get = fn_retval; self.start = function () { timeout_id poll(); }; self.stop = function () { timeout_id && clearTimeout(timeout_id); timeout_id = undefined; }; function poll() { var hash = get_fragment(), history_hash = history_get(last_hash); if (hash !== last_hash) { history_set(last_hash = hash, history_hash); myEvent.triggerHandler(window, str_hashchange); } else if (history_hash !== last_hash) { location.href = location.href.replace(/#.*/, '') + history_hash; }; timeout_id = setTimeout(poll, config.delay); }; isIE && !supports_onhashchange && (function () { var iframe,iframe_src, iframe_window; self.start = function () { if (!iframe) { iframe_src = config.src; iframe_src = iframe_src && iframe_src + get_fragment(); iframe = doc.createElement('<IFRAME title=empty style="DISPLAY: none" tabIndex=-1 src="' + (iframe_src 'javascript:0') + '"></IFRAME>'); myEvent.bind(iframe, 'load', function () { myEvent.unbind(iframe, 'load'); iframe_src history_set(get_fragment()); poll(); }); doc.getElementsByTagName('html')[0].appendChild(iframe); iframe_window = iframe.contentWindow; doc.onpropertychange = function () { try { if (event.propertyName === 'title') { iframe_window.document.title = doc.title; }; } catch (e) {}; }; }; }; self.stop = fn_retval; /** @inner */ history_get = function () { return get_fragment(iframe_window.location.href); }; /** @inner */ history_set = function (hash, history_hash) { var iframe_doc = iframe_window.document, domain = config.domain; if (hash !== history_hash) { iframe_doc.title = doc.title; iframe_doc.open(); domain && iframe_doc.write('<SCRIPT>document.domain="' + domain + '"</SCRIPT>'); iframe_doc.close(); iframe_window.location.hash = hash; }; }; })(); return self; })(); })(this); ready事件是伪事件,调用方式: 复制代码 代码如下:myEvent.ready(function () { //[code..] }); hashchange事件可以采用标准方式绑定: 复制代码 代码如下: myEvent.bind(window, 'hashchange', function () { //[code..] }); 这里有一些文章值得阅读: javascript 跨浏览器的事件系统(司徒正美。他博客有一系列的讲解) 更优雅的兼容(BELLEVE INVIS)
6. 基于H5开发饿了么app源码
Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。
7. 饿了么开源的Android业务流框架
事件收发是基于EventBus,IPC通信是基于Hermes。Hermes是一个简单易用的Android IPC库。
首先选一个进程作为主进程,将其他进程作为子进程。
每次一个event被发送都会经过以下四步:
1、使用Hermes库将event传递给主进程。
2、主进程使用EventBus在主进程内部发送event。
3、主进程使用Hermes库将event传递给所有的子进程。
4、每个子进程使用EventBus在子进程内部发送event。
用法
8. recyclerview android 仿饿了么5.0
Android是一个不断进化的平台,Android 5.0的v7版本支持包中引入了新的RecyclerView控件,正如官方文档所言,RecyclerView是ListView的豪华增强版。它主要包含以下几处新的特性,如ViewHolder,ItemDecorator,LayoutManager,SmothScroller以及增加或删除item时item动画等。官方推荐我们采用RecyclerView来取代ListView。 ViewHolder ViewHolder是用来保存视图引用的类,无论是ListView亦或是RecyclerView。只不过在ListView中,ViewHolder需要自己来定义,且这只是一种推荐的使用方式,不使用当然也可以,这不是必须的。只不过不使用ViewHolder的话,ListView每次getView的时候都会调用findViewById(int),这将导致ListView性能展示迟缓。而在RecyclerView中使用 RecyclerView.ViewHolder 则变成了必须,尽管实现起来稍显复杂,但它却解决了ListView面临的上述不使用自定义ViewHolder时所面临的问题。RecyclerView.ViewHolder 被BaseAdapter使用,以将posiiton绑定到上面(可以通过API查看 RecyclerView.ViewHolder#getPosition() 方法)。 LayoutManager 我们知道ListView只能在垂直方向上滚动,Android API没有提供ListView在水平方向上面滚动的支持。或许有多种方式实现水平滑动,但是请想念我,ListView并不是设计来做这件事情的。但是RecyclerView相较于ListView,在滚动上面的功能扩展了许多。它可以支持多种类型列表的展示要求,主要如下: LinearLayoutManager ,可以支持水平和竖直方向上滚动的列表。 StaggeredGridLayoutManager ,可以支持交叉网格风格的列表,类似于瀑布流或者Pinterest。 GridLayoutManager ,支持网格展示,可以水平或者竖直滚动,如展示图片的画廊。 ItemAnimator 列表动画是一个全新的、拥有无限可能的维度。起初的Android API中,删除或添加item时,item是无法产生动画效果的。后面随着Android的进化,Google的Chat Hasse推荐使用 ViewPropertyAnimator 属性动画来实现上述需求。 相比较于ListView, RecyclerView.ItemAnimator 则被提供用于在RecyclerView添加、删除或移动item时处理动画效果。同时,如果你比较懒,不想自定义ItemAnimator,你还可以使用 DefaultItemAnimator 。 Adapter ListView的Adapter中,getView是最重要的方法,它将视图跟position绑定起来,是所有神奇的事情发生的地方。同时我们也能够通过registerDataObserver在Adapter中注册一个观察者。RecyclerView也有这个特性,RecyclerView.AdapterDataObserver 就是这个观察者。ListView有三个Adapter的默认实现,分别是ArrayAdapter、CursorAdapter和SimpleCursorAdapter。然而,RecyclerView的Adapter则拥有除了内置的内DB游标和ArrayList的支持之外的所有功能。 RecyclerView.Adapter 的实现的,我们必须采取措施将数据提供给Adapter,正如BaseAdapter对ListView所做的那样。 ItemDecoration 在ListView中如果我们想要在item之间添加间隔符,我们只需要在布局文件中对ListView添加如下属性即可。 View Code 有趣的是,RecyclerView在默认情况下并不在item之间展示间隔符。尽管Google的家伙有意地将这个问题遗留给我们去自定义间隔符,但这的确增加了开发人员的负担。如果你想要添加间隔符,你必须使用RecyclerView.ItemDecoration类来实现。或者,你可以应用官方示例中的 DividerItemDecoration.java 文件。 OnItemTouchListener ListView通过AdapterView.OnItemClickListener接口来探测点击事件。而RecyclerView则通过RecyclerView.OnItemTouchListener接口来探测触摸事件。它虽然增加了实现的难度,但是却给予开发人员拦截触摸事件更多的控制权限。 Others ListView可以设置选择模式,并添加MultiChoiceModeListener,而RecyclerView则没有此功能。
9. 饿了么 app 源码 android
在饿了么业务发展的早期,移动APP经历了从无到有的阶段。为了快速上线抢占市场,传统移动APP开发的MVC架构成了“短平快”思路的首选: MVC架构 这种架构因简单清晰,容易开发而被大多数人所接受。 在MVC的体系架构中,Controller层负责整个APP中主要逻辑功能的实现;Model层则负责数据结构的描述以及数据持久化的功能;而View层作为展现层负责渲染整个APP的UI。分工清晰,简洁明了。此外,这种系统架构在语言框架层就得到了Apple的支持,所以非常适用于APP的startup开发。 然后,这种架构在开发的后期会由于其超高耦合性,造成Controller层庞大,而这也是一直被人们所诟病。最终的MVC都从Model-View-Controller走向了Massive-View-Controller的终点。 2 Mole Decoupled “短平快”的MVC架构在早期可以满足饿了么移动APP的快速开发迭代,但是随着代码量的不断增加,臃肿的Controller层也在渐露头角;而业务上,饿了么移动APP也从单一APP发展为多APP齐头并进的格局。这时候,降低耦合,复用已有模块便成了架构的第一要务。 架构中,模块复用的第一要求便是代码的功能组件化。组件化意味着拥有独立功能的代码从系统中进行抽象并剥离,再以“插件”的形式插回原有系统中。这样剥离出来的功能组件,便可以供其他APP使用,从而降低系统中模块与模块之间的耦合性;也同时提高了APP之间代码的复用性。 饿了么移动对于组件有两种定义:公有组件和业务组件。公有组件指的是封装得比较好的一些SDK,包括一些第三方组件和自己内部使用的组件。如iOS中最着名的网络SDK AFNetworking,Android下OKHttp,都是这类组件的代表。业务组件,则定义为包含了一系列业务功能的整体,例如登录业务组件,注册业务组件,即为此类组件的典型代表。 对于公有组件,饿了么移动采取了版本化的管理方式,而这在iOS和Android平台上早有比较成熟的解决方案。例如,对于iOS平台,CocoaPods基本上成为了代码组件化管理的标配;在Android平台上,Gradle也是非常成熟和稳健的方案。采用以上管理工具的另一个原因在于,对企业开发而言,代码也是一种商业机密。基于保密的目的,支持内网搭建私有服务器成为了必需。以上的管理工具都能够很好地支持这些操作。 对于业务的组件化,我们采取了业务模块注册机制来达到解耦合的目的。每个业务模块对外提供相应的业务接口,同时在系统启动的时候向Excalibur系统注册自己模块的Scheme(Excalibur是饿了么移动用来保存Scheme与模块之间映射的系统,同时能根据Scheme进行Class反射返回)。 当其他业务模块对该业务模块有依赖时,从Excalibur系统中获取相关实例,并调用相应接口来实现调用,从而实现了业务模块之间的解耦目的。 而在业务组件,即业务模块的内部,则可以根据不同开发人员的偏好,来实现不同的代码架构。如现在讨论得比较火的MVVM, MVP等,都可以在模块内部进行而不影响整体系统架构。 这时候的架构看起来更像是这样: EMC架构 E(Excalibur)M(Moles)C(Common)架构以高内聚、低耦合为主要的特点,以面向接口编程为出发点,降低了模块与模块之间的联系。 该架构的另外一大好处则在于解决了不同系统版本的兼容性问题。这里以iOS平台下的WebView作为例子来进行说明。Apple从iOS8系统开始提供了一套更好的Web支持框架——WebKit,但在iOS7系统下却无法兼容,从而导致Crash。使用此类架构,可以在iOS7系统下仍然注册使用传统的WebView来渲染网页,而在iOS8及其以上系统注册WebKit来作为渲染网页的内核。既避免了Apple严格的审核机制,又达到了动态加载的目的。 3Hybrid 移动APP的开发有两种不同的路线,NativeAPP和Web APP。这两种路线的区别类似于PC时代开发应用程序时的C/S架构和 B/S架构。 以上我们谈到的都属于典型的Native APP,即所有的程序都由本地组件渲染完成。这类APP优点是显而易见的,渲染速度快、用户体验好;缺点同时也十分突出:出现了错误一定要等待下一次用户进行APP更新才能够修复。 Web APP的优点恰好就是Native APP的缺点所在,其页面全部采用H5撰写并存放在服务器端。每次进行页面渲染时都从服务器请求最新的页面。一旦页面有错误,服务器端进行更新便能立刻解决。不过其弊端也容易窥见:每次页面都需要请求服务器,造成渲染时等待时间过长,从而导致的用户体验不够完美,并且性能上较Native APP慢了1-2个数量级;与此同时还会导致更多的用户流量消耗。另一个缺点则在于,Web APP在移动端上调用本地的硬件设备存在一定的不便。不过这些弊端也都有相应的解决方案,如PhoneGap将网页提前打包在本地以减少网络的请求时间;同时也提供一系列的插件来访问本地的硬件设备。然而,尽管如此,其渲染速度上还是存在一定的差距。 Hybrid APP则是综合了二者优缺点的解决方案。饿了么移动对于此二类APP的观点在于,纯粹展示性的模块会更适合使用Web页面来达到渲染的目的;而更多的数据操作性、动画渲染性的模块则更适合采用Native的方式。
10. android开发仿美团饿了么选菜界面实现
对两个按钮的背景进行改变button、button2的选中和为选择状态.beijing1).drawable.setBackgroundResource(R,让后再button1和button2的点击事件中,分别为button1的选中和为选择状态;上面是改变按钮背景的代码可以做两组图片