本篇文章将分享两个VIEW组件,一个天气组件和一个日期组件,这两个组件本来是一个App Widget 后来,我看着好玩,将他们弄成一个VIEW的组件,可以像使用Windows Phone 7 的用户控件一样拖放到你想要的项目中。本篇将演示这两个组件的编写过程,工程文件如下:

  

  包名介绍:

  • com.terry.weather  程序的入口包
  • com.yaomei.adapter  天气预报组件使用到的数据源
  • com.yaomei.model  天气预报使用到的模型包
  • com.yaomei.util  获取天气信息的工具包
  • com.yaomei.widget  天气预报组件、日期组件的存放位置

  从包名可以看出,编写一个天气预报所需要的代码量比编写一个日期VIEW所需要的代码量要多得多 ,那么我们先把天气预报的一些实现思路跟大家讲讲。

  首先,本实例使用的天气预报是一个可以自己国际化的天气组件VIEW,可以看上图,将所需要的URL都放入ANDROID 自己的国际化文件夹里面,比如中文的话就这样写:

<string name="googleWeatherApi">
 <![CDATA[http://www.google.com/ig/api?hl=zh-cn&weather=]]>
    </string>

那么是英语环境的就只需要在默认的VALUES里面的string.xml这样写即可:

    <string name="googleWeatherApi">
 <![CDATA[http://www.google.com/ig/api?hl=en&weather=]]>
    </string>

  这是本篇一个要注意的一点,另外还有需要注意的是,这个天气组件提供可供用户选择更新频率,这里比如我们使用3个小时更新一次,那么当用户退出程序时,再打开是否还要再去Google 上面读天气呢?答案是NO,因为既然用户选择了更新频率,那么在一定的时间内,我们最好不要自动去更新,除非用户自己点击更新才去执行。那么要如何得到之前的数据呢?

  这里使用到的是SharePreference 将一些天气的信息保存进去,连同天气的图片也一并保存。保存天气图片是将google 天气的图片使用Base64转成字符串,然后保存进Sharepreference ,如果更新频率条件未满足则进去SharePrference 将天气预报数据取出来 。因为Android 并未提供将图片转成字符串的API,这里使用到的是apache 的一个Jar包,可在这里下载:点击这里

  思路上面给出了,下面给出天气预报组件VIEW的核心代码,其他附属代码可在后面的附件下载得到,代码如下:

  

package com.yaomei.widget;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.commons.codec.binary.Base64;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.terry.weather.R;
import com.yaomei.adapter.weatherAdapter;
import com.yaomei.model.WeatherMdoel;
import com.yaomei.util.strHelpeUtil;

public class WeatherView extends LinearLayout {

private static final String Hour_COMPARE = "hour_compare";
    private static final String DAY_OF_WEEK = "day_of_week";
    private static final String LOW = "low";
    private static final String HIGH = "high";
    private static final String CONDITION = "condition";
    private static final String IMAGE = "image";
    private static final String DATE_COMPARE = "date_compare";
    private static final String CITYNAE_SHARE = "cityNameShare";

private ImageView iv_weather;
    private TextView tv_state, tv_position, tv;

WeatherMdoel model;
    private List<WeatherMdoel> weatherList = null;
    GridView gv;
    Timer timer;
    Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            if (msg.arg1 == 1) {
                if (weatherList.size() > 0) {
                    gv
                            .setAdapter(new weatherAdapter(getContext(),
                                    weatherList));
                    init();
                } else {
                    Toast.makeText(getContext(), "查询不到数据", 1000).show();
                }
                // msg.recycle();
            }
        };
    };

/**
     * 自动加载天气
     */
    private boolean autoLoad = false;

public boolean getAutoLoad() {
        return autoLoad;
    }

public void setAutoLoad(boolean isLoad) {
        this.autoLoad = isLoad;
    }

/**
     * 城市名称
     */
    private String cityName = "";

public String getCityName() {
        return cityName;
    }

public void setCityName(String cityName) {
        this.cityName = cityName;
    }

/**
     * 设置每几小时更新一次
     */
    private int updateHour;

public int getUpdateHour() {
        return updateHour;
    }

public void setUpdateHour(int hour) {
        this.updateHour = hour;
    }

public WeatherView(Context context) {
        this(context, null);
        // TODO Auto-generated constructor stub
    }

public WeatherView(Context context, AttributeSet attrs) {
        super(context, attrs);
        int resouceID = -1;
        TypedArray tyedArray = context.obtainStyledAttributes(attrs,
                R.styleable.WeatherView);
        int N = tyedArray.getIndexCount();
        for (int i = 0; i < N; i++) {
            int attr = tyedArray.getIndex(i);
            switch (attr) {
            case R.styleable.WeatherView_AutoLoad:
                setAutoLoad(tyedArray.getBoolean(
                        R.styleable.WeatherView_AutoLoad, false));
                break;

case R.styleable.WeatherView_CityName:
                resouceID = tyedArray.getResourceId(
                        R.styleable.WeatherView_CityName, 0);
                setCityName(resouceID > 0 ? tyedArray.getResources().getText(
                        resouceID).toString() : tyedArray
                        .getString(R.styleable.WeatherView_CityName));
                break;
            case R.styleable.WeatherView_UpdateHour:
                setUpdateHour(tyedArray.getInteger(
                        R.styleable.WeatherView_UpdateHour, 3));
                break;
            }
        }

View view = LayoutInflater.from(getContext()).inflate(
                R.layout.weather_layout, this);

tv = (TextView) view.findViewById(R.id.tv_temperature);

gv = (GridView) view.findViewById(R.id.grid);
        iv_weather = (ImageView) view.findViewById(R.id.iv_weather);
        tv_state = (TextView) view.findViewById(R.id.tv_state);
        tv_position = (TextView) view.findViewById(R.id.tv_position);
        timer = new Timer();

if (getAutoLoad()) {
            startLoadWeather();
        }
        tyedArray.recycle();
    }

/**
     * 开始加载
     */
    public void startLoadWeather() {
        timer.schedule(new TimerTask() {

@Override
            public void run() {

SharedPreferences share = getContext().getSharedPreferences(
                        "weather", Activity.MODE_PRIVATE);
                long time = System.currentTimeMillis();
                final Calendar mCalendar = Calendar.getInstance();
                mCalendar.setTimeInMillis(time);
                String tempDate = mCalendar.get(Calendar.YEAR) + "-"
                        + mCalendar.get(Calendar.MONTH) + "-"
                        + mCalendar.get(Calendar.DAY_OF_MONTH);
                if (share.contains(DATE_COMPARE)) {
                    if (share.getString(CITYNAE_SHARE, "").equals(cityName)) {
                        int time_cop = mCalendar.get(Calendar.HOUR)
                                - share.getInt(Hour_COMPARE, 0);
                        String date = share.getString(DATE_COMPARE, "");

if (time_cop >= getUpdateHour()
                                || !date.equals(tempDate)) {
                            saveWeatherList(mCalendar.get(Calendar.HOUR),
                                    tempDate);

} else if (time_cop < getUpdateHour()) {
                            weatherList = new ArrayList<WeatherMdoel>();
                            for (int i = 0; i < 4; i++) {
                                WeatherMdoel model = new WeatherMdoel();
                                model.setWeek(share.getString(DAY_OF_WEEK + i,
                                        ""));
                                model.setLowTemp(share.getString(LOW + i, ""));
                                model
                                        .setHighTemp(share.getString(HIGH + i,
                                                ""));
                                model.setConditions(share.getString(CONDITION
                                        + i, ""));
                                String image = share.getString(IMAGE + i, "");
                                byte[] base64Bytes = Base64.decodeBase64(image
                                        .getBytes());
                                ByteArrayInputStream bais = new ByteArrayInputStream(
                                        base64Bytes);
                                model.setImageUrl("");
                                model
                                        .setImageDrawable(Drawable
                                                .createFromStream(bais,
                                                        "weather_image"));

weatherList.add(model);
                            }
                        }
                    } else {
                        saveWeatherList(mCalendar.get(Calendar.HOUR), tempDate);
                    }

} else {
                    saveWeatherList(mCalendar.get(Calendar.HOUR), tempDate);
                }
                // 把必要的操作放在于线程中执行,不阻塞UI
                if (handler.hasMessages(1))
                    handler.obtainMessage().recycle();

else {
                    Message msg = handler.obtainMessage();
                    msg.arg1 = 1;
                    msg.sendToTarget();
                }
            }
        }, 0, getUpdateHour() * 3600 * 1000);
    }

/**
     * 第一次或者另外重新加载
     */
    void saveWeatherList(int hour, String day) {
        weatherList = new ArrayList<WeatherMdoel>();
        weatherList = strHelpeUtil.searchWeather(Html.fromHtml(
                getContext().getResources()
                        .getString(R.string.googleWeatherApi)).toString(),
                getCityName());

SharedPreferences.Editor shareEditor = getContext()
                .getSharedPreferences("weather", Activity.MODE_PRIVATE).edit();
        shareEditor.clear();
        int i = 0;
        for (WeatherMdoel model : weatherList) {

shareEditor.putString(DAY_OF_WEEK + i, model.getWeek());
            shareEditor.putString(LOW + i, model.getLowTemp());
            shareEditor.putString(HIGH + i, model.getHighTemp());
            shareEditor.putString(CONDITION + i, model.getConditions());
            /**
             * 将图片存入
             */
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ((BitmapDrawable) strHelpeUtil.loadImage(model.getImageUrl()))
                    .getBitmap().compress(CompressFormat.JPEG, 50, baos);

String ImageBase64 = new String(Base64.encodeBase64(baos
                    .toByteArray()));
            shareEditor.putString(IMAGE + i, ImageBase64);
            i++;
        }
        shareEditor.putString(DATE_COMPARE, day);
        shareEditor.putInt(Hour_COMPARE, hour);
        shareEditor.putString(CITYNAE_SHARE, cityName);
        shareEditor.commit();
    }

/**
     * 初始化组件 信息
     */
    void init() {
        model = weatherList.get(0);
        iv_weather.setImageDrawable(model.getImageUrl() == "" ? model
                .getImageDrawable() : strHelpeUtil.loadImage(model
                .getImageUrl()));
        tv_state.setText(model.getConditions());
        tv_position.setText(getCityName());
        tv.setText(getContext().getResources().getString(R.string.temp_format,
                model.getLowTemp(), model.getHighTemp()));
    }

/**
     * 释放对象
     */
    public void releaseTimer() {
        timer.cancel();
        weatherList = null;
    }

}

  学习这个类,你能够学到的知识点为:为应用程序添加属性,编写组件,SharePreference 的使用,Timer和Handler 异步处理UI等知识点。

  日期VIEW显示VIEW组件,是一个显示当前系统时间的组件,当第一次运行时,得到当前的秒数在以60秒减去当前秒,得到第一次运行时下一次运行需要的秒数,当这一次更新完毕后,下一次每次60秒更新一次时间,这个组件也是以分更新UI的操作,学习本类,你可以学到两个Handler 是如何协作处理UI,代码如下:

package com.yaomei.widget;

import java.util.Calendar;
import java.util.Date;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.terry.weather.R;
import com.yaomei.util.strHelpeUtil;

public class DateView extends FrameLayout {

private TextView tv_date_time, tv_week, tv_date;

int second;

Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            init();
            handler.sendMessageDelayed(handler.obtainMessage(), 60 * 1000);
        };
    };

public DateView(Context context) {
        this(context, null);
    }

public DateView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //this.setBackgroundDrawable(getContext().getResources().getDrawable(
            //    R.drawable.date_background));

View view = LayoutInflater.from(getContext()).inflate(
                R.layout.date_layout, this);

tv_date_time = (TextView) view.findViewById(R.id.tv_date_time);
        tv_week = (TextView) view.findViewById(R.id.tv_week);
        tv_date = (TextView) view.findViewById(R.id.tv_date);
        init();
        final Calendar calendar = Calendar.getInstance();
        second = calendar.get(Calendar.SECOND);
        handler.sendMessageDelayed(handler.obtainMessage(),
                (60 - second) * 1000);
    }

void init() {
        java.text.DateFormat df = new java.text.SimpleDateFormat("HH:mm");
        tv_date_time.setText(df.format(new Date()));
        tv_week.setText(strHelpeUtil.getWeekOfDate(new Date()));
        strHelpeUtil str = new strHelpeUtil(getContext());
        tv_date.setText(str.toString());
    }

}

上篇运行效果如下:

  由于没有为其提供背景颜色,使用的同学可以自己为它们加上一个好看的背景颜色,效果会更加。

  上面的天气组件,其实可以使用AsyncTask也是起到同样的效果,AsyncTask使用起来会觉得优雅一点,这里也顺便把一些AsyncTask在使用上一些注意事项跟大家谈一谈:

  • 在doInBackground 里面不要直接操作UI,比如设置UI的可见性操作。
  • 在doInBackground 所在的操作只负责帮你得到数据,然后把UI处理都放在onPostExecute 里面。
  • 同时启动几个AsyncTask 注意线程加锁,使用synchronized
  • 必须每次都创建一个新的AsyncTask 对象,否则会提示“a task can be executed only once” 的错误信息。

本篇的所有源码下载地址:组件

Android 分享两个你学习android 平台开发必须碰到的几个知识点的组件【天气预报、日期】View 组件...相关推荐

  1. 分享两个超实用的Android开源UI框架——QMUI和XUI

    目录 QMUI_Android 功能特性 全局 UI 配置 丰富的 UI 控件 高效的工具方法 功能列表 支持 Android 版本 使用方法 QMUI Demo APP 安装包下载 XUI 特征 演 ...

  2. 作为 Android 开发者,如何深入学习 Android UI?

    前言 Android 新技术层出不穷,要想不落后不被淘汰我们只能不停的学! 作为好的安卓开发,首先明确Android是前端,重点是UI,做出稳定的应用是关键. Compose 是 Android UI ...

  3. android分享图片功能实现原理,Android:简单实现并理解图片三级缓存

    学习Android网络开发的过程中,势必会经历很多痛苦的过程,其中一个大坑就是图片缓存,当然现在有很多现成的库非常方便,常常几行代码就可以实现想要的功能,但不懂其中的原理是不行的,所以对于刚开始学习网 ...

  4. android 分享小程序到微信,Android 分享微信小程序之图片优化

    小菜上周接入了微信分享小程序的入口,基本功能实现都没问题,有需要的朋友可以了解一下 Android 分享微信小程序失败二三事,虽然功能都正常,但整体测试发现图片展示效果不佳.于是小菜整理了一个简单的小 ...

  5. android 分享微信 不审核,ShareSDK Android 微信分享 绕过审核与不绕过审核

    首先,微信在android平台有两种方式:一种是绕过审核分享,一种是不绕过审核分享. 绕过审核和不绕过审核的对比图如下: 1.微信好友对比图: 绕过审核分享分享给微信好友时看到的只是图片文件,显示的是 ...

  6. android mvc使用方法,详细学习android mvc设计模式教程

    MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 web 应用程序的模式.其分层有助于管理复杂的应用程序,因为可以在一个时间内专门关注一个方面.例如 ...

  7. Android安装两次才成功,Android应用从市场安装完成打开与桌面打开,被启动两次的问题...

    问题描述: 1.从Android应用市场下载并安装应用,安装完成后,当前界面下方会出现"打开"按钮,这时候我们点击"打开",会启动应用,进入到应用的启动页面,然 ...

  8. android分开两个线程做事,android开发教程之handle实现多线程和异步处理

    这次浅谈一下Handler,为什么会出现Handler这个功能特性呢?首先,在之前的基本控件,基本都是在Activity的onCreate(Bundle savedInstanceState)方法中调 ...

  9. android分享到新浪微博客户端吗,Android调用手机新浪微博客户端分享

    通过Action_Send以及Intent.createChoose()调用系统分享功能时,是可以显示当前手机上已安装的能分享的客户端列表,当然,开发者也可以指定单独某一个平台来分享,代码如下: pu ...

  10. 2014 android 新技术,向友商学习 Android 12新功能前瞻:似曾相识

    2月过半,春节假期结束,世界进入了"万物复苏"的阶段. 手机圈也是如此,更多搭载新芯片的手机将会陆续露面,占据移动操作系统市场71.93%份额的安卓也将迎来最新版本安卓12的开发者 ...

最新文章

  1. Spring boot异常统一处理方法:@ControllerAdvice注解的使用、全局异常捕获、自定义异常捕获
  2. node python 速度_Java,Node,Python 运行速度比较
  3. MySQL 服务器变量 数据操作DML-视图
  4. C# 中打印、预览、打印机设置和打印属性的方法
  5. 修改、读取txt文档
  6. JQuery Datatables editor进行增删改查操作(二)
  7. Kafka和的安装与配置
  8. hdu5800_dp
  9. Eclipse无法DEBUG
  10. java上路系列之一
  11. 答题小程序 服务器,开源的基于云开发的在线答题小程序
  12. QQ群排名技术讲解、实战分析、核心要点 盗引结合篇
  13. 周志华----机器学习2
  14. 计算机程序中的自省程序(反射程序)(introspective program)是什么?(introspectable、introspection)
  15. 数据库——JDBC基本连接步骤
  16. C语言:字符串数组与字符串指针数组
  17. 10本营销好书!游戏营销、增长黑客、算法、数据分析、内容营销,总有一款你喜欢
  18. 建筑与建筑群综合布线系统工程施工及验收规范
  19. sql 子查询及基本语句 挺全的收录
  20. SQLServer找不到配置管理器,如何打开配置管理器

热门文章

  1. AdGuard for Mac(专业的广告拦截工具)
  2. Python基础_字符串的格式化
  3. 【Flutter】基础组件【09】Button
  4. jq 实现头像(气泡式浮动)
  5. 英特尔:我们解决VR体验所需的强大计算量
  6. 【数据库】sql连表查询
  7. Processing-基础小坑-
  8. AngularJs依赖注入的研究
  9. 从何润东代言团宝,看团购行业逐渐成熟
  10. Internet Explorer无法下载