项目地址:https://github.com/JoanZapata/base-adapter-helper

1. 功能介绍

1.1. base-adapter-helper

base-adapter-helper 是对传统的 BaseAdapter ViewHolder 模式的一个封装。主要功能就是简化我们书写 AbsListView 的 Adapter 的代码,如 ListView,GridView。

1.2 基本使用

  1. mListView.setAdapter(mAdapter = new QuickAdapter<Bean>(MainActivity.this, R.layout.item_list, mDatas) {
  2. @Override
  3. protected void convert(BaseAdapterHelper helper, Bean item) {
  4. helper.setText(R.id.tv_title, item.getTitle());
  5. helper.setImageUrl(R.id.id_icon, item.getUrl());
  6. helper.setText(R.id.tv_describe, item.getDesc());
  7. helper.setText(R.id.tv_phone, item.getPhone());
  8. helper.setText(R.id.tv_time, item.getTime());
  9. }
  10. });

1.3 长处

(1) 提供 QucikAdapter,省去类似 getCount() 等抽象函数的书写,仅仅需关注 Model 到 View 的显示。

(2) BaseAdapterHelper 中封装了大量用于为 View 操作的辅助方法,比如从网络载入图片:

helper.setImageUrl(R.id.iv_photo, item.getPhotoUrl());

1.4 缺点

(1) 与 Picasso 耦合,想替换为其它图片缓存须要改动源代码。

可通过接口方式。供三方依据自己的图片缓存库实现图片获取,或者直接去掉helper.setImageUrl(…)函数。

(2) 与内部加入的进度条偶尔,导致不支持多种类型布局

在本文最后给出不修改进度条的解决方法。更好的实现方式应该是通过接口方式暴露,供三方自己设置。

(3) 眼下的方案也不支持HeaderViewListAdapter

整体来说这个库比較简单,实现也有待改进。

2. 整体设计

因为 base-adapter-helper 本质上仍然是 ViewHolder 模式,以下各自是 base-adapter-helper 的整体设计图和 ViewHolder 模式的设计图,通过两图的比較。能够看出 base-adapter-helper 对传统的BaseAdapter进行了初步的实现(QuickAdapter),而且其子类仅需实现convert(…)方法,在convert(…)中能够拿到BaseAdapterHelper,BaseAdapterHelper就相当于ViewHolder。但其内部提供了大量的辅助方法。用于设置
View 上的数据及事件等。

base-adapter-helpr

ViewHolder Pattern

3. 具体设计

3.1 类关系图



这是 base-adapter-helper 库的主要类关系图。

(1) 在 BaseQucikAdapter 中实现了 BaseAdapter 中通用的抽象方法。

(2) BaseQuickAdapter 中两个泛型,当中 T 表示数据实体类(Bean)类型,H 表示 BaseAdapterHelper 或其子类。

(3) QucikAdapter 继承自 BaseQuickAdapter,而且传入 BaseAdapterHelper 作为 H 泛型;

(4) EnhancedQuickAdapter 主要为convert(…)方法加入了一个 itemChanged 參数。表示 item 相应数据是否发生变化;

(5) BaseAdapterHelper 为用于获取 View 并进行内容、事件设置等相关操作的辅助类。当中多数用于设置的方法都採用链式编程,方便书写。

(6) 能够依据自己须要继承 BaseAdapterHelper 来扩展,做为 BaseQuickAdapter 子类的 H 泛型。

3.2 核心类源代码分析

3.2.1 BaseQucikAdapter.java

该类继承自 BaseAdapter。完毕 BaseAdapter 中部分通用抽象方法的实现,类似ArrayAdapter

该类声明了两个泛型,当中 T 表示数据实体类(Bean)类型。H 表示 BaseAdapterHelper 或其子类,主要在扩展BaseAdapterHelper时使用。

(1) 构造方法
  1. public BaseQuickAdapter(Context context, int layoutResId) {
  2. this(context, layoutResId, null);
  3. }
  4. public BaseQuickAdapter(Context context, int layoutResId, List<T> data) {
  5. this.data = data == null ?
  6. new ArrayList<T>() : new ArrayList<T>(data);
  7. this.context = context;
  8. this.layoutResId = layoutResId;
  9. }

Adapter 的必须元素 ItemView 的布局文件通过 layoutResId 指定,待展示数据通过 data 指定。

(2) 已经实现的主要方法
  1. @Override
  2. public int getCount() {
  3. int extra = displayIndeterminateProgress ? 1 : 0;
  4. return data.size() + extra;
  5. }
  6. @Override
  7. public int getViewTypeCount() {
  8. return 2;
  9. }
  10. @Override
  11. public int getItemViewType(int position) {
  12. return position >= data.size() ? 1 : 0;
  13. }
  14. @Override
  15. public View getView(int position, View convertView, ViewGroup parent) {
  16. if (getItemViewType(position) == 0) {
  17. final H helper = getAdapterHelper(position, convertView, parent);
  18. T item = getItem(position);
  19. helper.setAssociatedObject(item);
  20. convert(helper, item);
  21. return helper.getView();
  22. }
  23. return createIndeterminateProgressView(convertView, parent);
  24. }

上面列出了 BaseQucikAdapter 中已经实现的主要方法,跟一般 BaseAdapter 类似,我们重点看下面几个点:

a. 重写了getViewTypeCount()getItemViewType(),这里 type 为 2,通过getView(…)能够看出,主要是为了在 AbsListView 最后显示一个进度条。这里也暴露了一个弊端,无法支持多种 Item 样式的布局;

b. getView(…)方法的实现中首先通过抽象函数getAdapterHelper(…) 得到 BaseAdapterHelper 及 item,然后通过抽象函数convert(…)实现 View 和 数据的绑定。

这样BaseQucikAdapter子类仅仅须要实现抽象函数getAdapterHelper(…)convert(…)就可以。

(3) 待实现的抽象方法
  1. protected abstract void convert(H helper, T item);
  2. protected abstract H getAdapterHelper(int position, View convertView, ViewGroup parent);

a. convert(H helper, T item)

通过helper将 View 和 数据绑定。

helper參数表示 BaseQuickAdapter 或其子类。用于获取 View 并进行内容、事件设置等相关操作,由getAdapterHelper(…)函数返回;item表示相应的数据。

b. getAdapterHelper(int position, View convertView, ViewGroup parent)

返回 BaseQuickAdapter 或其子类,绑定 item,然后返回值传递给上面的convert(…)函数。

关于getAdapterHelper(…)的实现见以下QuickAdapter的介绍。

3.2.2 QucikAdapter.java

这个类继承自BaseQuickAdapter,没什么代码,主要用于提供一个可高速使用的 Adapter。

对于getAdapterHelper(…)函数直接返回了BaseAdapterHelper。普通情况下直接用此类作为 Adapter 就可以,如1.2 基本使用的演示样例。

但假设你扩展了BaseAdapterHelper,重写getAdapterHelper(…)函数将其返回。就可以实现自己的 Adapter。

3.2.3 EnhancedQuickAdapter.java

继承自QuickAdapter,不过为convert(…)加入了一个參数itemChanged。表示 item 相应数据是否发生变化。

  1. @Override
  2. protected final void convert(BaseAdapterHelper helper, T item) {
  3. boolean itemChanged = helper.associatedObject == null || !helper.associatedObject.equals(item);
  4. helper.associatedObject = item;
  5. convert(helper, item, itemChanged);
  6. }
  7. protected abstract void convert(BaseAdapterHelper helper, T item, boolean itemChanged);

能够看到它的实现是通过helper.associatedObjectequals()方法推断数据是否发生变化,associatedObject 即我们的 bean。

BaseQuickAdapter.getView(…)能够看到其赋值的代码。

3.2.4 BaseAdapterHelper.java

可用于获取 View 并进行内容设置等相关操作的辅助类,该类的功能有:

(1) 充当了 ViewHolder 角色,KV 形式保存 convertView 中子 View 的 id 及其引用,方便查找。

和 convertView 通过 tag 关联;

(2) 提供了一堆辅助方法,用于为子 View 设置内容、样式、事件等。

(1) 构造相关方法
  1. protected BaseAdapterHelper(Context context, ViewGroup parent, int layoutId, int position) {
  2. this.context = context;
  3. this.position = position;
  4. this.views = new SparseArray<View>();
  5. convertView = LayoutInflater.from(context) //
  6. .inflate(layoutId, parent, false);
  7. convertView.setTag(this);
  8. }
  9. public static BaseAdapterHelper get(Context context, View convertView, ViewGroup parent, int layoutId) {
  10. return get(context, convertView, parent, layoutId, -1);
  11. }
  12. /** This method is package private and should only be used by QuickAdapter. */
  13. static BaseAdapterHelper get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
  14. if (convertView == null) {
  15. return new BaseAdapterHelper(context, parent, layoutId, position);
  16. }
  17. // Retrieve the existing helper and update its position
  18. BaseAdapterHelper existingHelper = (BaseAdapterHelper) convertView.getTag();
  19. existingHelper.position = position;
  20. return existingHelper;
  21. }

QuickAdapter中,通过上面的 5 个參数的静态函数get(…)得到BaseAdapterHelper的实例。

4 个參数的get(…)方法,仅仅是将 position 默认传入了 -1。即不关注 postion 方法。

这里能够对照下我们平时在getView中编写的 ViewHolder 模式的代码。在一般的 ViewHolder 模式中,先推断convertView是否为空:

a. 假设是,则通过LayoutInflater inflate 一个布局文件。然后新建 ViewHolder 存储布局中各个子 View,通过 tag 绑定该 ViewHolder 到convertView,返回我们的convertView

b. 否则直接得到 tag 中的 ViewHolder。

结合BaseQuickAdaptergetView(…)代码。看下 base-adapter-helper 的实现。

  1. @Override
  2. public View getView(int position, View convertView, ViewGroup parent) {
  3. if (getItemViewType(position) == 0) {
  4. final H helper = getAdapterHelper(position, convertView, parent);
  5. T item = getItem(position);
  6. helper.setAssociatedObject(item);
  7. convert(helper, item);
  8. return helper.getView();
  9. }
  10. return createIndeterminateProgressView(convertView, parent);
  11. }

先利用getAdapterHelper(…)得到BaseAdapterHelper或其子类,对于QuickAdapter而言,这个函数直接调用上面BaseAdapterHelperget(…)函数。

我们能够看到相同是先推断convertView是否为空。以确定是否须要新建BaseAdapterHelper,否则从 tag
中获取更新 position 后重用。

在构造方法中 inflate 了一个布局作为convertView。而且保存 context 及 postion,将convertViewBaseAdapterHelper通过tag关联。

(2) 几个重要的方法

普通情况下,在我们重写BaseQuickAdapterconvert(…)时,须要得到 View。这时我们能够通过其入參BaseAdapterHelpergetView(int viewId)得到该View。代码例如以下:

  1. public <T extends View> T getView(int viewId) {
  2. return retrieveView(viewId);
  3. }
  4. @SuppressWarnings("unchecked")
  5. protected <T extends View> T retrieveView(int viewId) {
  6. View view = views.get(viewId);
  7. if (view == null) {
  8. view = convertView.findViewById(viewId);
  9. views.put(viewId, view);
  10. }
  11. return (T) view;
  12. }

通过 viewId 去 views 中进行寻找,找到则返回,找不到则加入并返回。

views 是一个 SparseArray。key为 view id,value 为 view。缓存已经查找到的子 view。

每一个convertView与一个BaseAdapterHelper绑定。每一个BaseAdapterHelper中包括一个views属性。views中存储convertView的子 View 的引用。

(3) 辅助方法

普通情况下,通过getView(int viewId)拿到该View,然后进行赋值就能够了。

可是此库考虑:既然是拿到 View 然后赋值。不如直接提供一些赋值的辅助方法。于是产生了一堆类似setText(int viewId, String value)的代码,内部首先通过 viewId 找到该 View,转为TextView然后调用setText(value)。部分代码例如以下:

  1. public BaseAdapterHelper setText(int viewId, String value) {
  2. TextView view = retrieveView(viewId);
  3. view.setText(value);
  4. return this;
  5. }
  6. public BaseAdapterHelper setImageResource(int viewId, int imageResId) {…}
  7. public BaseAdapterHelper setBackgroundRes(int viewId, int backgroundRes) {…}
  8. public BaseAdapterHelper setTextColorRes(int viewId, int textColorRes) {…}
  9. public BaseAdapterHelper setImageDrawable(int viewId, Drawable drawable) {…}
  10. public BaseAdapterHelper setImageUrl(int viewId, String imageUrl) {…}
  11. public BaseAdapterHelper setImageBitmap(int viewId, Bitmap bitmap) {…}
  12. @SuppressLint("NewApi")
  13. public BaseAdapterHelper setAlpha(int viewId, float value) {…}
  14. public BaseAdapterHelper setVisible(int viewId, boolean visible) {…}
  15. public BaseAdapterHelper linkify(int viewId) {…}
  16. public BaseAdapterHelper setProgress(int viewId, int progress, int max) {…}
  17. public BaseAdapterHelper setRating(int viewId, float rating, int max) {…}
  18. public BaseAdapterHelper setTag(int viewId, int key, Object tag) {…}
  19. public BaseAdapterHelper setChecked(int viewId, boolean checked) {…}
  20. public BaseAdapterHelper setAdapter(int viewId, Adapter adapter) {…}
  21. ……

实现都是依据 viewId 找到 View。然后为 View 赋值的代码。

这里仅仅要注意下:setImageUrl(int viewId, String imageUrl) 这种方法,默认是通过Picasso去载入图片的,当然你能够更改成你项目中使用的图片载入框架 Volley,UIL 等,假设不希望继续耦合,可參考1.4 缺点的建议改法。

也能够为子 View 去设置一个事件监听,部分代码例如以下:

  1. public BaseAdapterHelper setOnClickListener(int viewId, View.OnClickListener listener) {
  2. View view = retrieveView(viewId);
  3. view.setOnClickListener(listener);
  4. return this;
  5. }
  6. public BaseAdapterHelper setOnTouchListener(int viewId, View.OnTouchListener listener) {…}
  7. public BaseAdapterHelper setOnLongClickListener(int viewId, View.OnLongClickListener listener) {…}

这里只列出一些经常使用的方法,假设有些控件的方法这里没有封装。能够通过BaseAdapterHelper.getView(viewId)得到控件去操作,或者继承BaseAdapterHelper实现自己的BaseAdapterHelper

4. 杂谈

4.1 耦合严重

(1) 与 Picasso 耦合,想替换为其它图片缓存须要改动源代码

可通过新增接口方式,供三方自己依据自己的图片缓存库实现图片获取,或者直接去掉helper.setImageUrl(…)函数。

(2) 与内部加入的进度条耦合。导致不支持多种类型布局

在以下给出不修改进度条的解决方法。更好的实现方式应该是通过接口方式暴露,供三方自己设置。

整体来说这个库比較简单。实现也有待改进。

4.2 眼下的方案也不支持HeaderViewListAdapter

4.3 扩展多种 Item 布局

通过3.2.1 BaseQucikAdapter.java的分析,能够看出 base-adapter-helper 并不支持多种布局 Item 的情况。尽管大多数情况下一个种样式就可以。可是要是让我用这么简单的方式写 Adapter,忽然来个多种布局 Item 的 ListView 又要 按传统的方式去写,这反差就太大了。以下我们介绍。怎样在本库的基础上加入多布局 Item 的支持。

(1) 分析

对于多种布局的 Item,大家都清楚。须要去复写BaseAdaptergetViewTypeCount()getItemViewType()。而且须要在getView()里面进行推断并选取不同布局文件。不同的布局也须要採用不同的ViewHolder

我们能够在构造QucikAdapter时。去设置getViewTypeCount()getItemViewType()的值,进一步将其抽象为一个接口。提供几个方法,假设须要使用多种 Item 布局,进行设置就可以。

(2) 扩展
  • 加入接口 MultiItemTypeSupport

    1. public interface MultiItemTypeSupport<T> {
    2. int getLayoutId(int position, T t);
    3. int getViewTypeCount();
    4. int getItemViewType(int postion, T t);
    5. }
  • 分别在QuickAdapterBaseQuickAdapter中加入新的构造函数

BaseQuickAdapter新增构造函数例如以下:

  1. protected MultiItemTypeSupport<T> multiItemSupport;
  2. public BaseQuickAdapter(Context context, ArrayList<T> data,
  3. MultiItemTypeSupport<T> multiItemSupport) {
  4. this.multiItemSupport = multiItemSupport;
  5. this.data = data == null ? new ArrayList<T>() : new ArrayList<T>(data);
  6. this.context = context;
  7. }

QuickAdapter 新增构造函数例如以下:

  1. public QuickAdapter(Context context, ArrayList<T> data,
  2. MultiItemTypeSupport<T> multiItemSupport) {
  3. super(context, data, multiItemSupport);
  4. }

同一时候肯定须要改写BaseQuickAdaptergetViewTypeCount()getItemViewType()以及getView()函数。

  1. @Override
  2. public int getViewTypeCount() {
  3. return multiItemSupport != null ? (mMultiItemSupport.getViewTypeCount() + 1) : 2);
  4. }
  5. @Override
  6. public int getItemViewType(int position) {
  7. if (position >= data.size()) {
  8. return 0;
  9. }
  10. return (mMultiItemSupport != null) ?
  11. mMultiItemSupport.getItemViewType(position, data.get(position)) : 1;
  12. }
  13. @Override
  14. public View getView(int position, View convertView, ViewGroup parent) {
  15. if (getItemViewType(position) == 0) {
  16. return createIndeterminateProgressView(convertView, parent);
  17. }
  18. final H helper = getAdapterHelper(position, convertView, parent);
  19. T item = getItem(position);
  20. helper.setAssociatedObject(item);
  21. convert(helper, item);
  22. return helper.getView();
  23. }

为了保留其原本提供的加入滚动栏的功能,我们在其基础上进行改动。

  • 改写BaseAdapterHelper的构造方法

由于我们不同的布局,肯定要相应不同的ViewHolder,这里BaseAdapterHelper事实上就扮演了ViewHolder的角色。

我们的BaseAdapterHelper是在QuickAdaptergetAdapterHelper中构造的。改动后代码:

QuickAdapter

  1. protected BaseAdapterHelper getAdapterHelper(int position,
  2. View convertView, ViewGroup parent) {
  3. if (mMultiItemSupport != null){
  4. return get(
  5. context,
  6. convertView,
  7. parent,
  8. mMultiItemSupport.getLayoutId(position, data.get(position)),
  9. position);
  10. } else {
  11. return get(context, convertView, parent, layoutResId, position);
  12. }
  13. }

BaseAdapterHelperget方法也须要改动。

  1. /** This method is package private and should only be used by QuickAdapter. */
  2. static BaseAdapterHelper get(Context context, View convertView,
  3. ViewGroup parent, int layoutId, int position) {
  4. if (convertView == null) {
  5. return new BaseAdapterHelper(context, parent, layoutId, position);
  6. }
  7. // Retrieve the existing helper and update its position
  8. BaseAdapterHelper existingHelper = (BaseAdapterHelper)convertView
  9. .getTag();
  10. if (existingHelper.layoutId != layoutId) {
  11. return new BaseAdapterHelper(context, parent, layoutId, position);
  12. }
  13. existingHelper.position = position;
  14. return existingHelper;
  15. }

我们在 helper 中存储了当前的 layoutId。假设 layoutId 不一致。则又一次创建。

(3) 測试

以下展示核心代码

  1. mListView = (ListView) findViewById(R.id.id_lv_main);
  2. MultiItemTypeSupport<ChatMessage> multiItemTypeSupport = new MultiItemTypeSupport<ChatMessage>() {
  3. @Override
  4. public int getLayoutId(int position, ChatMessage msg) {
  5. return msg.isComMeg() ? R.layout.main_chat_from_msg : R.layout.main_chat_send_msg;
  6. }
  7. @Override
  8. public int getViewTypeCount() {
  9. return 2;
  10. }
  11. @Override
  12. public int getItemViewType(int postion, ChatMessage msg) {
  13. return msg.isComMeg() ?
  14. ChatMessage.RECIEVE_MSG : ChatMessage.SEND_MSG;
  15. }
  16. };
  17. initDatas();
  18. mAdapter = new QuickAdapter<ChatMessage>(ChatActivity.this, mDatas,
  19. multiItemTypeSupport) {
  20. @Override
  21. protected void convert(BaseAdapterHelper helper, ChatMessage item) {
  22. switch (helper.layoutId) {
  23. case R.layout.main_chat_from_msg:
  24. helper.setText(R.id.chat_from_content, item.getContent());
  25. helper.setText(R.id.chat_from_name, item.getName());
  26. helper.setImageResource(R.id.chat_from_icon, item.getIcon());
  27. break;
  28. case R.layout.main_chat_send_msg:
  29. helper.setText(R.id.chat_send_content, item.getContent());
  30. helper.setText(R.id.chat_send_name, item.getName());
  31. helper.setImageResource(R.id.chat_send_icon, item.getIcon());
  32. break;
  33. }
  34. }
  35. };
  36. mListView.setAdapter(mAdapter);

当遇到多种布局 Item 的时候,首先构造一个MultiItemTypeSupport接口对象,然后在convert中依据 layoutId。获取不同的布局进行设置。

贴张效果图:

Android万能适配器base-adapter-helper的源代码分析的更多相关文章

  1. Android进阶笔记10:Android 万能适配器

    1. Android 万能适配器      项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...

  2. Android进阶笔记09:Android 万能适配器

    1. Android 万能适配器      项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...

  3. Android万能适配器Adapter-android学习之旅(74)

    万能适配器的代码的github地址是https://github.com/fengsehng/CommonAdapter 万能适配器的代码的github地址是https://github.com/fe ...

  4. Android应用程序进程启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址: http://blog.csdn.net/luoshengyang/article/details/6747696 Android 应用程序框架层创 ...

  5. Android实现多个倒计时优化与源代码分析

    由于之前有个项目需求是须要时时刻去更新UI倒计时,之前想到的,这简单嘛,用计时或者Handler就能够搞定,并且性能也不错,可是需求要ListView,什么,?大量的View都须要,那Handle处理 ...

  6. Android系统进程Zygote启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6768304 在Android系统中,所有的应用 ...

  7. Android应用程序安装过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6766010 Android系统在启动的过程中, ...

  8. Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setCont ...

  9. Android—万能ListView适配器

    ListView是开发中最常用的控件了,但是总是会写重复的代码,浪费时间又没有意义. 最近参考一些资料,发现一个万能ListView适配器,代码量少,节省时间,总结一下分享给大家. 首先有一个自定义的 ...

随机推荐

  1. Swift实现糗事百科Demo(实战项目)

    在这里,你将会学习到解析JSON数据,网络请求功能,动态调整cell内容等功能!!! 最终的结果 是这样的,项目相对简单,很适合入门!下面让我们一起开始教程之旅吧! 1.先看下项目工程结构: 第一步: ...

  2. STL之iterator(迭代器)

    3.迭代器简单介绍 除了使用下标来訪问vector对象的元素外,标准库还提供了訪问元素的方法:使用迭代器.迭代器是一种检查容器内元素而且遍历元素的数据类型. 百科释义: 迭代器(iterator)是一 ...

  3. OC中线程的状态相关

    1.线程的状态NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; ...

  4. 正确处理Windows电源事件

    简介为系统挂起与恢复而进行的应用准备步骤 曾几何时,当您正要通过应用提交或发布一些重要数据时,突然遇到一些急事需要处理,而且会耽误很长时间.当您完成任务回到电脑前时,发现电脑已经自动进入 了挂起状态, ...

  5. linux命令:ftp

    1. 登录: ftp IP_ADDR    : 根据提示输入USER_NAME    PASS_WORD 或: ftp -i -n IP_ADDR    user  USER_NAME    PASS ...

  6. tq2440+fedora安装qt4.5

    1. make[1]: arm-none-linux-gnueabi-g++:命令未找到 make[1]: *** [.obj/release-shared-emb-arm/qatomic_arm.o ...

  7. Python爬虫入门三之Urllib库的基本使用

    转自http://cuiqingcai.com/947.html 1.分分钟扒一个网页下来 怎样扒网页呢?其实就是根据URL来获取它的网页信息,虽然我们在浏览器中看到的是一幅幅优美的画面,但是其实是由 ...

  8. GDI GDI+ 的区别

    GDI+是GDI的下一个版本,它进行了很好的改进,并且易用性更好.GDI的一个好处就是你不必知道任何关于数据怎样在设备上渲染的细节,GDI+更好的实现了这个优点,也就是说,GDI是一个中低层API,你 ...

  9. js显示时间

    function nowTime(){ var data= new Date(); var y=data.getFullYear(); var m=parseInt(data.getMonth())+ ...

  10. 基于visual Studio2013解决C语言竞赛题之1084完全平方数

        题目 解决代码及点评 /************************************************************************/ /* ...