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

简介:

本篇文章将分享两个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” 的错误信息。

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

 



 本文转自 terry_龙 51CTO博客,原文链接:http://blog.51cto.com/terryblog/486341,如需转载请自行联系原作者


相关文章
|
25天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
1月前
|
XML 缓存 Android开发
Android开发,使用kotlin学习多媒体功能(详细)
Android开发,使用kotlin学习多媒体功能(详细)
101 0
|
1月前
|
设计模式 人工智能 开发工具
安卓应用开发:构建未来移动体验
【2月更文挑战第17天】 随着智能手机的普及和移动互联网技术的不断进步,安卓应用开发已成为一个热门领域。本文将深入探讨安卓平台的应用开发流程、关键技术以及未来发展趋势。通过分析安卓系统的架构、开发工具和框架,本文旨在为开发者提供全面的技术指导,帮助他们构建高效、创新的移动应用,以满足不断变化的市场需求。
18 1
|
2天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
20 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
11天前
|
存储 数据库 Android开发
构建高效安卓应用:采用Jetpack架构组件优化用户体验
【4月更文挑战第12天】 在当今快速发展的数字时代,Android 应用程序的流畅性与响应速度对用户满意度至关重要。为提高应用性能并降低维护成本,开发者需寻求先进的技术解决方案。本文将探讨如何利用 Android Jetpack 中的架构组件 — 如 LiveData、ViewModel 和 Room — 来构建高质量的安卓应用。通过具体实施案例分析,我们将展示这些组件如何协同工作以实现数据持久化、界面与逻辑分离,以及确保数据的即时更新,从而优化用户体验并提升应用的可维护性和可测试性。
|
16天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。
|
18天前
|
监控 算法 Android开发
安卓应用开发:打造高效启动流程
【4月更文挑战第5天】 在移动应用的世界中,用户的第一印象至关重要。特别是对于安卓应用而言,启动时间是用户体验的关键指标之一。本文将深入探讨如何优化安卓应用的启动流程,从而减少启动时间,提升用户满意度。我们将从分析应用启动流程的各个阶段入手,提出一系列实用的技术策略,包括代码层面的优化、资源加载的管理以及异步初始化等,帮助开发者构建快速响应的安卓应用。
|
18天前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
19 1
Android开发之使用OpenGL实现翻书动画
|
18天前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
15 1
Android开发之OpenGL的画笔工具GL10
|
25天前
|
Android开发
Android开发小技巧:怎样在 textview 前面加上一个小图标。
Android开发小技巧:怎样在 textview 前面加上一个小图标。
12 0