Android 用户界面解析

    用户界面
  在一个Android应用程序里,用户接口是一系列的View和ViewGroup对象组合而成。Android有很多种View和ViewGroup对象,他们都继承自View基类。
  View对象是Android平台用户接口的基本对象。这些view类作为与用户交互的widgets小部件的父类,像文本框和按钮。ViewGroup作为提供各种布局结构的layouts的父类,例如linear线性布局,表格布局和绝对布局。
  一个view对象是一个数据结构,他存储布局参数和屏幕特定区矩形区域的内容。一个view会处理自己所在屏幕区域的测量、布局、绘制、焦点改变、滚动、和按键手势交互。作为用户交互对象,一个view可以作为用户与系统的交互工具,接收事件。

   View 结构体系

  在Android平台,你要用到View或ViewGroup的层、节点的方式来定义一个Android用户界面,就像下面的图表,这个层次结构树可以按你的需求变得简单或者复杂。你可以用Android系统已经定义好的小控件或者布局,或者自定义一些。

   为了能让你的view层次结构在屏幕上渲染,你的activity需要调用setContentView()方法并且传递一个根节点对象的引用。Android系统接收这些配置,并使用他们来进行测量绘制这个树形的视图结构。这个视图结构的根节点要求他的孩子节点自我绘制,反过来说,每个viewGroup节点负责让他们的子节点自我绘制。子节点会在父节点哪里请求到尺寸和位置,但父对象会最终决定他们孩子有多大。Android按顺序解析你的布局上的所有元素,从顶端开始,实例化view并且把他们添加到父对象。因为他们都是按顺序被绘制的,如果某些view超出的显示范围,那么后来绘制的将会覆盖原来的。

  关于view结构体系怎样绘制,在后面会有详细的讨论。


  布局

  通常最多的布局是通过xml来定义。xml提供一个容易阅读的结构,很像html。xml中每个元素都是一个view或者viewGroup对象(或他们的子类)。view在树结构中是叶子节点,ViewGroup对象在非叶子节点。

  xml元素名代表着各个类。比如<TextView>元素会创建一个TextView控件,一个<LinearLayout>会创建一个LinearLayout的viewGroup,当你加载一个布局资源,Android系统会初始化运行时对象,即对应的布局元素。

  例如,一个简单的垂直布局,里面包含一个textView和一个Button。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <TextView android:id="@+id/text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello, I am a TextView" />
    <Button android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello, I am a Button" />
    </LinearLayout>
注意,linearLayout元素包含着TextView和Button。你可以嵌套另外的LinearLayout,来增加view的长度,或者增加一个更复杂的布局。

  你可以在你的布局里用很多种布局方式,使用很多不同类型的viewGroup,你可以定义无限多的子view或者子viewGroup。android提供一些预先定义好的布局,包括:LinearLayout-线性布局, RelativeLayout-关系布局, TableLayout-表格布局, GridLayout 网格布局等。他们提供一些独特的参数用来定义view的位置和布局结构。

  Widgets小部件

  widget是一个服务于用户与界面交互的view对象。Android提供很多视图小部件,如按钮、寻则狂、文本输入框、到呢个,你可以很快的构建自己的布局。一些小部件很复杂,像日期选择器,一个时钟,缩放控制。但你不会被Android平台所提供的UI部件所限制,你可以自定义UI部件,可以继承或者结合已经存在的UI部件。

  UI事件

  一旦你向界面添加了view或者widget,你可能会想他们怎样与用户进行交互的,这样你就可以执行一些操作。添加UI事件,你需要做两件事情:

  @ 定义事件监听器并注册给view。

  多半情况下,这就是你怎样监听事件:view 类包含了一些名如OnXXXListener的监听器,他们都有名为OnXXX()的回调方法。例如:View。onClickListener(这是处理点击事件的),View。onTouchListener(处理触摸事件),View.onKeyListener(处理按键事件),所以如果你想让view响应点击事件,比如按钮被选中,你需要实现OnClickListener接口并且定义回调方法,并且用setOnClickListener()方法来注册View。

  @ 覆盖一个已经存在的回调方法:

  如果你失信了自己的View类并且想要监听一些特殊的事件,那你应该用这种方法。例如,你可以处理屏幕触摸事件,处理滚动球事件,按键等事件。它允许你定义默认的事件,即自定义的view的每个事件,确定这个时间是否会传递到一些字view。然后,他们调用view类的回调函数,所以当你自定义一个组件时才有机会用到这种方法。

  菜单Menu

  应用程序菜单是UI的另一个很重要的部分。Menu提供一些可靠的借口来展示程序的功能和一些设置。通常menu是通过按menu键才显示的。然而,你可以让用户按下或者按住某一项时显示menu菜单。

  menu菜单也遵循view的层次结构,但不要自己定义。取而代之的是,你只需为你的activity定义onCreateOptionsMenu()和onCreateContextMenu()两个回调方法即可,在适当的时间,Android会自动的绘制必要的视图结构并且menu的所包含的子项的。

  Menu会处理他自己的时间。所以不需要注册事件监听器,当menu中的某一项被选中,系统会调用onOptionsItemSelected()方法或者onContextItemSelected()方法。

  和应用程序的布局很像,你可以用xml来配置你的menu项。

  高级特征

  一旦你了解了创建用户界面的基本原则。你可以浏览一些高级特征来创建更复杂的应用程序接口。

  适配器Adapters

  一些时候,你不想用“硬代码”来填充一些view的数据,相反,你想让view绑定额外的数据集。要这样的话,你要定义一个AdapterView,每个子View里的数据都会被适配器填充。

  适配器视图对象 AdapterView是实现的ViewGroup接口,子类是由被给出的适配器对象决定的。适配器就像你的adapter视图和数据源之间的适配器。这里有几种适配器类的实现方式,对于特殊的任务,例如自定义的适配器从一个Cursor来读取数据库的数据,或者一耳光数组适配器从任意一个数组读取数据。

  风格和主题 Styles、Themes

  你或许不满意标准控件的外观,你可以定制他们的风格和主题来改变他们。

  @ 一个style是一个格式化的属性集,你作为布局的其中一个单元来使用他们。例如,你可以定义某些文本的文字大小和颜色作为特殊的view元素。

  @ 一个theme主题是应用程序中整个activity的个格式化的属性集。例如,你可以定义窗体的边框和面板的背景,并且设置menu的字体大小和颜色。它可以应用在整个程序里。

   我们这次深入分析Android应用程序的布局文件,主要内容如下:

  1、用户界面及视图层次
  2、Android中布局定义方法
  3、编写XML布局文件及加载XML资源
  
   1、用户界面及视图层次  

       在通过“Hello World!”介绍Android中的布局问题之前,不得不先介绍一下Android中的用户界面,因为布局问题也是用户界面问题之一.在一个Android应用程序中,用户界面通过View和ViewGroup对象构建.Android中有很多种Views和ViewGroups,他们都继承自View类.View对象是Android平台上表示用户界面的基本单元.

   View类:
  extends Object
  implements Drawable.Callback KeyEvent.Callback AccessibilityEventSource


  这个类表示用户界面组件的基本构建块,一个View占据屏幕上的一个矩形区域,并负责绘图和事件处理.View类是widgets的基类,widgets用于创建交互式UI组件(buttons、text fields等).View类的直接子类ViewGroup类是layouts的基类,layouts是不可见的容器用户保持其他Views或者其他ViewGroups和定义它们的布局属性.

  一个View对象是一个数据结构,它的属性存储屏幕上一个特定矩形区域的布局参数和内容.一个View对象处理它自己的测度、布局、绘图、焦点改变、滚动、键/手势等与屏幕上矩形区域的交互.作为用户界面中的对象,View也是与用户交互的一个点且交互事件接收器.

  在Android平台上,你定义活动的UI使用的View和ViewGroup节点的层次结构如下图所示.根据你的需要这个层次树可以是简单的或复杂的,并且你能使用Android预定义的widgets和layouts集合,或者使用自定义的Views.

    为了将视图层次树呈现到屏幕上,你的活动必须调用setContentView()方法并且传递到根节点对象的引用.Android系统接收这个引用并使用它来验证、测度、绘制树.层次的根节点要求它的孩子节点绘制它自己——相应地每个试图组节点要求调用自己的孩子视图去绘制他们自己.子视图可能在父视图中请求指定的大小和位置,但是父视图对象有最终决定权(子视图在哪个位置及多大).因为它们是按序绘制的,如果元素有重叠的地方,重叠部分后面绘制的将在之前绘制的上面.

  2、Android中布局定义方法


  布局是一个活动中的用户界面的架构,它定义了布局结构且存储所有显示给用户的元素.有两种方式可以声明布局,这个我们在上文中已经用了(对应上文的“Hello World的手术(二)”、“Hello World的手术(三)”).我们再重温总结一下:

  方法一、在XML格式的布局文件中声明UI.Android提供了简易的XML词汇表对应视图类和其子类,诸如widgets和layouts.

  方法二、在运行时实例化布局元素.可以编程地创建View和ViewGroup对象,并操作他们的属性.

  Android框架给我们灵活地使用这两个方法之一或两个声明和管理你的应用程序的UI.例如,你可以用XML格式的布局文件定义应用程序默认的布局,包括将显示在屏幕的元素和属性.然后你可以编程地修改屏幕上对象的状态,包括定义在XML文件中的元素.


  最常用的是方法一,即用一个XML的布局文件定义自己的布局和表达层次视图.XML提供一种直观的布局结构,类似HTML.XML中的每个元素是一个View或者ViewGroup对象(或继承自他们的对象).View对象是树中的叶子,ViewGroup对象是树中的分支,这点可以从上面的视图层次树中可以看出.


  在XML布局文件中声明UI的优点是:使应用程序的界面与控制它行为的代码更好地分离了.UI描述在应用程序代码之外,这意味着你可以修改或调整它而不用修改你的源码并重新编译.例如,你可以为不同的屏幕方向、不同的屏幕大小、不同的语言创建XML布局文件.此外,在XML中声明布局更易地可视化你的UI结构,因此更容易调试问题.


  一个元素XML元素的名字对应到一个Java类,因此一个<TextView>元素在你的UI中创建一个TextView,一个<linearLayout>元素创建一个LinearLayout的视图组.当你加载一个布局资源时,Android系统初始化这些运行时对象,对应你的布局中的元素.XML元素的属性对应到一个Java类的方法.


     3、编写XML布局文件及加载XML资源


       使用Android的XML词汇,我们可以快速地设计UI布局及包含的屏幕元素,就像web页面的HTML。每个布局文件必须包含一个根元素,根元素必须是一个View或ViewGroup对象。一旦你已经定义了根元素,你可以添加额外的layout对象或widgets作为子元素,逐步地构建一个视图层次定义你的布局。例如,下面的XML布局文件使用了纵向的LinearLayout保存一个TextView和一个Button。

Button的子类

     android.widget.Button最常用的按钮,继承自android.widget.TextView,在android.widget包中.

  他的常用子类CheckBox, RadioButton, ToggleButton.

  通常用法:

  super.findViewById(id)得到在layout中声明的Button 的引用,setOnClickListener(View.OnClickListener)添加监听.然后再View.OnClickListener 监听器中使用v.equals(View)方法判断哪个按钮被按下,进行分别处理.

  android.widget.CheckBox复选按钮,继承自android.widget.CompoundButton,在android.widget包中.
   常用方法:
  isChecked()检查是否被选中.
  监听按钮状态更改,需要添加setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener);

  android.widget. RadioButton单选按钮,继承自android.widget.CompoundButton,在android.widget包中.

  通常用法:

  单选按钮要声明在RadioGroup,RadioGroup是流式布局android.widget.LinearLayout的子类.

  单选按钮状态更改的监听,是要给他的RadioGroup添加setOnCheckedChangeListener(RadioGroup.OnCheckedChangeListener)监听器.注意监听器类型和CheckBox是不一样的.

    android.widget. ToggleButton开关形式的按钮,继承自android.widget.CompoundButton,在android.widget包中.

  常用属性设置:

  android:textOn=“” 选择状态文字

  android:textOff=“” 未选状态文字

TextView

android.widget.TextView一般用来文本展示,继承自android.view.View,在android.widget包中.

  他的常用子类有Button, CheckedTextView, Chronometer, DigitalClock, EditText.

  常用属性设置:

  android:text=“” 文字显示

  android:autoLink=”” 链接类型.Web网址,email邮件,phone电话,map地图.Linkify.

  链接状态时,Web情况可直接调用浏览器进行浏览.Email直接调用手机的Email软件,phone转到拨打电话页面.


       android.widget.EditText为输入框,继承自 android.widget.TextView,在android.widget包中.他的常用子类.AutoCompleteTextView和 MultiAutoCompleteTextView.ExtractEditText与输入法有关.

  常用属性设置:

  android:hint=”请输入用户名” 输入框的提示文字

  android:password=”" True为密码框

  android:phoneNumber=”" True为电话框

  android:numeric=”" 数字框.Integer正整数, signed整数(可带负号), decimal浮点数.

  android:digits 设置允许输入哪些字符.如“1234567890.+-*/%\n()”


       android.widget.AutoCompleteTextView带提示的输入框,继承自android.widget.EditText,在android.widget包中.

  AutoCompleteTextViewhe和MultiAutoCompleteTextView都是自动提示,一个是单选,一个多选.

  常用属性设置:

  android:completionThreshold 输入几个字符时提示

  AutoCompleteTextView就是一个带自动提示的EditText,当输入字符时,会出现提示窗口,点击选择即可.

  首先在layout中定义一个AutoCompleteTextView,然后需要在Activity设置数据源就可以了.

  ArrayAdapter的构造方法三个参数为:上下文的Context,每行的textView布局,数据源.

  this.autoCompleteTextView = (AutoCompleteTextView) super.findViewById(R.id.autoCompleteTextView);

  ArrayAdapter arrayAdapter = new ArrayAdapter(this, R.layout.arrayadapte_textview, CITY_NAMES);

  this.autoCompleteTextView.setAdapter(arrayAdapter);MultiAutoCompleteTextView和 AutoCompleteTextView的类似,也是带有提示的输入框.区别在于MultiAutoCompleteTextView可以连续提示,选择一个提示项后会自动添加一个分隔符,在输入时继续提示.AutoCompleteTextView则属于单选模式的.

  MultiAutoCompleteTextView使用时需要设置分隔符类CommaTokenizer.其他与AutoCompleteTextView一样.

  this.multiAutoCompleteTextView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());


       TextSwitcher

  android.widget.TextSwitcher文字切换.继承自android.widget.ViewSwitcher(ViewGroup),在android.widget包中.

  使用方法setInAnimation(Animation),setOutAnimation(Animation)设置动画.

  例子,设置ViewSwitcher的动画,并使用数字时钟更改ViewSwitcher的字符串

    public class SwitcherActivity extends Activity implements ViewSwitcher.ViewFactory, View.OnClickListener {

    private Button buttonChangeText;
    private TextSwitcher myTextSwitcher;
    private DigitalClock myDigitalClock;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.setContentView(R.layout.switcher);

    this.buttonChangeText = (Button) super.findViewById(R.id.buttonChangeText);
    this.myTextSwitcher = (TextSwitcher) super.findViewById(R.id.myTextSwitcher);
    this.myDigitalClock = (DigitalClock) super.findViewById(R.id.myDigitalClock);
    this.buttonChangeText.setOnClickListener(this);
    this.myTextSwitcher.setFactory(this);

    this.myTextSwitcher.setInAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
    this.myTextSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));

    }

    @Override
    public View makeView() {
    TextView textView = new TextView(this);
    textView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
    textView.setTextSize(36);
    return textView;
    }

    @Override
    public void onClick(View v) {
    this.myDigitalClock.addTextChangedListener(textWatcher);
    }

    private android.text.TextWatcher textWatcher = new android.text.TextWatcher() {

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
    SwitcherActivity.this.myTextSwitcher.setText(SwitcherActivity.this.myDigitalClock.getText());
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void afterTextChanged(Editable s) {
    }
    };
    }

RadioButton

       Android中RadioButton的使用同其它语言中的RadioButton使用相似..
  在Android中,RadioButton同其它继承于View的界面元素一样,可单独使用,OnClickListener,当然最常用的方式是以组合方使用,组合方式使用时,要使用RadioGroup类,这个类同时也是一个布局类(layout),可以使用布局参数(LayoutParams)对象来放置其中的RadioButton相对位置..

  一,单独使用RadiosButton
  在Activity类中可以如此使用..

    new RadioButton(this);
    rbtn.setOnClickListener( new OnClickListener(){public void onClick(View v){setTitle("test!")}});
  二, 组合使用

    public class Test extends Activity implements OnCheckedChangeListener
    {
    private RadioGroup mgroup = null;
    @Override public void onCreate(Bundle icicle)
    {
    super.onCreate(icicle);
    mgroup = new RadioGroup(this);
    mgroup.setOrientation(RadioGroup.VERTICAL);
    mgroup.setOnCheckedChangeListener(this);
    RadioButton btn1 = new RadioButton(this);
    btn1.setId(100);
    mgroup.addView(btn1);
    RadioButton btn2 = new RadioButton(this);
    btn2.setId(101);
    mgroup.addView(btn2);
    mgroup.setOnCheckedChangeListener(this);
    }
    public void onCheckedChanged(RadioGroup arg0, int arg1)
    {
    switch(arg0.getCheckedRadioButtonId())
    {
    case 100:
    setTitle("you cliecked RadioButton 1"); break;
    case 101:
    setTitle("you cliecked RadioButton 2"); break;
    default:
    break;

    }
    }
    }
    CheckBox

       既然是复选框,当然具备选中跟未选中状态,我们可以根据控件是否被选中来进行相应的操作,通过对复选框加载时间监听器,来对控件状态的改变作出Actions,当然也可以只对控件是否被选中做判断即可,而在其他控件的监听处理中执行其他操作,这个就根据具体的业务需求来选择。

  我们先在布局文件中声明创建3个复选框控件,分别称为“WWW”,“ATAAW”,“COM”。

    CheckBox android:text="WWW" android:id="@+id/ataaw1"
  android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>
  <CheckBox android:text="ATAAW" android:id="@+id/ataaw2"
  android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>
  <CheckBox android:text="COM" android:id="@+id/ataaw3"
  android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>

    为以上复选框添加时间监听器,为了方便起见,我们这里为三个复选框添加同一个时间监听器,通过判断其响应的ID确定哪一个复选框被选中。

  A、首先定义监听器

    OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    switch(buttonView.getId()){
    case R.id.ataaw1: //action
    break;
    case R.id.ataaw2: //action
    break;
    case R.id.ataaw3: //action
    break;
    }
    }
    }
B、指定监听器

    CheckBox www = (CheckBox) this.findViewById(R.id.ataaw1);
    CheckBox ataaw = (CheckBox) this.findViewById(R.id.ataaw2);
    CheckBox com = (CheckBox) this.findViewById(R.id.ataaw3);
    www.setOnCheckedChangeListener(listener);
    ataaw.setOnCheckedChangeListener(listener);
    com.setOnCheckedChangeListener(listener);
ImageView
       android..widget..ImageView图片控件,继承自android..view..View,在android..widget包中..
  最简单的使用方法..src设置图片路径,可引用drawable的图片..
  动态声明ImageView,设置src..

       ImageButton

       android..widget..ImageButton图片控件,继承自android..widget..ImageView,在android..widget包中..
  最简单的使用方法..src设置图片路径,可引用drawable的图片..
  动态声明ImageView,设置src..

       ImageSwitcher和Gallery

       android..widget.. ImageSwitcher图片控件,继承自android..widget..ViewSwitcher(ViewGroup)..在android..widget包中..
  ImageSwithcer是用来图片显示那块区域的控件,使用方法setInAnimation(Animation),setOutAnimation(Animation)设置动画..
  Gallery是来控制底下那个图标索引列表索引用的..ImageAdapter继承自BaseAdapter,设置Gallery的适配器..
  在layout添加ImageSwitcher和Gallery..定义 Activity,implements接口OnItemSelectedListener, ViewFactory..onCreate的时候定义要显示图片路径列表,设置Gallery的Adapter..onItemSelected事件触发 时,设置对应的图片..

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <ImageSwitcher android:id="@+id/switcher"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true" />

    <Gallery android:id="@+id/gallery"
    android:background="#55000000"
    android:layout_width="fill_parent"
    android:layout_height="60dp"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:gravity="center_vertical"
    android:spacing="16dp" />

    </RelativeLayout> 

    public class SwitcherActivity extends Activity implements OnItemSelectedListener, ViewFactory {

    private ImageSwitcher imageSwitcher;
    private Gallery gallery;

    private ArrayList<String> imageAssetPathList = new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.setContentView(R.layout.switcher);
    this.imageSwitcher = (ImageSwitcher) findViewById(R.id.switcher);
    this.gallery = (Gallery) findViewById(R.id.gallery);

    for (int i = 1; i <= 20; i++) {
    this.imageAssetPathList.add("images/" + i + ".jpg");
    }

    this.imageSwitcher.setFactory(this);
    this.gallery.setAdapter(new ImageAdapter(this, this.imageAssetPathList));
    this.gallery.setOnItemSelectedListener(this);

    }

    @Override
    public View makeView() {
    ImageView imageView = new ImageView(this);
    imageView.setBackgroundColor(0xFF000000);
    imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
    imageView.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    return imageView;
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    try {
    InputStream inputStream = super.getAssets().open(this.imageAssetPathList.get(position));
    imageSwitcher.setImageDrawable(Drawable.createFromStream(inputStream, "" + position));
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }

    }
    public class ImageAdapter extends BaseAdapter {

    private Context content;
    private ArrayList<String> imageAssetPathList;

    public ImageAdapter(Context content, ArrayList<String> imageAssetPathList) {
    this.content = content;
    this.imageAssetPathList = imageAssetPathList;
    }

    @Override
    public int getCount() {
    if (this.imageAssetPathList != null) {
    return this.imageAssetPathList.size();
    } else {
    return 0;
    }
    }

    @Override
    public Object getItem(int position) {
    return null;
    }

    @Override
    public long getItemId(int position) {
    return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    try {
    ImageView imageView;
    imageView = new ImageView(this.content);
    imageView.setAdjustViewBounds(true);
    imageView.setScaleType(ImageView.ScaleType.FIT_XY);
    imageView.setPadding(0, 0, 0, 0);

    InputStream inputStream = this.content.getAssets().open(this.imageAssetPathList.get(position));
    imageView.setImageDrawable(Drawable.createFromStream(inputStream, "" + position));

    return imageView;
    } catch (IOException e) {
    e.printStackTrace();
    return null;
    }
    }

    }
时间控件

       android.widget. DigitalClock数字时钟,继承自android.widget.TextView。在android.widget包中。

       DigitalClock
       一般用法:
       调用方法getText(),可得到时间字符串。使用方法addTextChangedListener(android.text.TextWatcher)添加文字更改监听,则会每秒钟会激发一次事件。
      
     
       AnalogClock
       android.widget. AnalogClock模拟时钟,继承自android.view.View。在android.widget包中。
       模拟时钟。在界面显示一个带时针和分针的模拟时钟

        AnalogClock
        android.widget.TimePicker时间设置,继承自android.widget.FrameLayout(ViewGroup) 。在android.widget包中。
        TimePicker
        进行微调小时、分钟和 AM/PM(如果适用)。也可以键盘输入。AM/PM 下点击按钮选择。也可以使用此视图的对话框TimePickerDialog。
       方法getCurrentHour()得到当前小时(根据AM/PM),getCurrentMinute()得到当前分钟。
       方法setOnTimeChangedListener(TimePicker.OnTimeChangedListener),可对调节进行监听。

       DatePicker
       android.widget. DatePicker时间设置,继承自android.widget.FrameLayout(ViewGroup) 。在android.widget包中。
       进行微调年、月、日。也可以键盘输入。也可以使用此视图的对话框DatePickerDialog
       方法getYear()得到年, getMonth()月, getDayOfMonth()当月日。
       方法init(int year, int monthOfYear, int dayOfMonth, DatePicker.OnDateChangedListener onDateChangedListener),初始化年月日和调节监听。

       进度条

       android.widget. ProgressBar,继承自android.view.View 。在android.widget包中。对应对话框ProgressDialog。
ProgressBar有两种展示方式,表盘形式(普通、小、大)和条形填充形式。在layout定义时,需要通过设施style属性类设置展示方式。

常用属性设置:

style显示方式,取值:
?android:attr/progressBarStyleLarge / progressBarStyle / progressBarStyleSmall / progressBarStyleHorizontal
android:maxprogressBarStyleHorizontal方式时,进度条满时的值。
android:progressprogressBarStyleHorizontal方式时,进度条主进度当前值。
android:secondaryProgressprogressBarStyleHorizontal方式时,进度条次进度当前值。


       progressBarStyleHorizontal方式时,就需要指定进度条最大值,当前值,次要的当前值。还可以在代码中手动设置。

       通过按钮改变progress和secondaryProgress的代码:
    if (v.equals(this.buttonSubBar)) {
    this.myProgressBar.setProgress(this.myProgressBar.getProgress() - 10);
    } else if (v.equals(this.buttonAddBar)) {
    this.myProgressBar.setProgress(this.myProgressBar.getProgress() + 10);
    } else if (v.equals(this.buttonSubSecondaryBar)) {
    this.myProgressBar.setSecondaryProgress(this.myProgressBar.getSecondaryProgress() - 5);
    } else if (v.equals(this.buttonAddSecondaryBar)) {
    this.myProgressBar.setSecondaryProgress(this.myProgressBar.getSecondaryProgress() + 5);
    }

  android.widget. SeekBar拖动进度条,继承自android.widget.AbsSeekBar(android.widget. ProgressBar) 。在android.widget包中。
常用属性设置:

android:max进度条满时的值。
android:progress进度条主进度当前值。
android:thumb拇指跟随图标。
android:thumbOffset设置允许的轨道的范围扩展到拇指的拇指偏移量。

       方法setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener) 可进行监听,开始拖拽。

    this.mySeekBar = (SeekBar) super.findViewById(R.id.mySeekBar);

    this.mySeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener);

    *
    *
    /**
    * seekBar 监听器
    */
    private SeekBar.OnSeekBarChangeListener onSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    myTextSeekBar.setText(progress + "");
    Log.v(CommonConfig.LOG_TAG, "SeekBar onProgressChanged, progress: " + progress + ", fromUser: " + fromUser);
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    Log.v(CommonConfig.LOG_TAG, "SeekBar onStartTrackingTouch");
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    Log.v(CommonConfig.LOG_TAG, "SeekBar onStopTrackingTouch");
    }
    };

android.widget. RatingBar星式进度条,继承自android.widget.AbsSeekBar(android.widget. ProgressBar)。在android.widget包中。

常用属性设置:

android:isIndicator是否是评级栏,指示器作用。True为指示器,用户不可操作。
android:numStars总星数。
android:rating当前星数。
android:stepSize每次可以等加的最小单位。浮点数。


        setOnRatingBarChangeListener(RatingBar.OnRatingBarChangeListener),添加一个监听器,可以监听每次改变。

    this.myRatingBar = (RatingBar) super.findViewById(R.id.myRatingBar);

    this.myRatingBar.setOnRatingBarChangeListener(onRatingBarChangeListener);

    *
    *

    /**
    * ratingBar 监听器
    */
    private RatingBar.OnRatingBarChangeListener onRatingBarChangeListener = new RatingBar.OnRatingBarChangeListener() {

    @Override
    public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
    myTextRatingBar.setText(rating + " / " + ratingBar.getNumStars());
    Log.v(CommonConfig.LOG_TAG, "RatingBar onRatingChanged, rating: " + rating + ", fromUser: " + fromUser);
    }

    };

  Android系统里面有3种类型的菜单:options menu,context menu,sub menu..
  options menu 按Menu键就会显示,用于当前的Activity..
  它包括两种菜单项:
  因为options menu在屏幕底部最多只能显示6个菜单项,这些菜单项称为icon menu,icon menu只支持文字(title) 以及icon,可以设置快捷键,不支持checkbox以及radio控件,所以不能设置checkable选项..
  而多于6的菜单项会以“more” icon menu来调出,称为expanded menu..它不支持icon,其他的特性都和icon menu一样!
  在Activity里面,一般通过以下函数来使用options menu:
  Activity::onCreateOptionsMenu (Menu menu) 创建options menu,这个函数只会在menu第一次显示时调用..
  Activity::onPrepareOptionsMenu (Menu menu) 更新改变options menu的内容,这个函数会在menu每次显示时调用..
  Activity::onOptionsItemSelected (MenuItem item) 处理选中的菜单项..
  context menu 要在相应的view上按几秒后才显示的,用于view,跟某个具体的view绑定在一起..
  这类型的菜单不支持icon和快捷键!
  在Activity里面,一般通过以下函数来使用context menu:
  Activity::registerForContextMenu(View view) 为某个view注册context menu,一般在Activity::onCreate里面调用..
  Activity::onCreateContextMenu(ContextMenu menu, View v, ContextMenu..ContextMenuInfo menuInfo) 创建context menu,和options menu不同,context meun每次显示时都会调用这个函数..
  Activity::onContextItemSelected(MenuItem item) 处理选中的菜单项..
  sub menu
  以上两种menu都可以加入子菜单,但子菜单不能嵌套子菜单,这意味着在Android系统,菜单只有两层,设计时需要注意的!同时子菜单不支持icon..
  xml形式的menu定义及应用
  上述的三种类型的menu都能够定义为xml资源,但需要手动地使用MenuInflater来得到Menu对象的引用..
  一个菜单,对应一个xml文件,因为要求只能有一个根节点
  ..官方说声明可以不写,但我觉得还是写上好些,很多时候那个声明主要是为了声明编码格式utf-8之类的..xml文件保存为res/menu /some_file..xml..Java代码引用资源: R..menu..some_file
  接下来介绍相关的节点和属性(所有的属性都定义为android空间内,例如

android:icon=”@drawable/icon”):

 根节点,没有属性..
  表示在它里面的在同一group..相关属性包括:
  id:group id
  menuCategory:对应 常量Menu CATEGORY_* — 定义了一组的优先权,有
  效值:container,system,secondary,和alternative
  orderInCategory:定义这组菜单在菜单中的默认次序,int值
  checkableBehavior:这组菜单项是否checkable..有效值:none,all(单选/单选按钮radio button),single(非单选/复选类型checkboxes)
  visible:这组菜单是否可见 true or false
  enabled:这组菜单是否可用,true or false
  菜单项,可以嵌入
  作为子菜单..相关属性包括:
  id: item id
  menuCategory: 用来定义menu类别
  orderInCategory: 用来定义次序,与一个组在一起(Used to define the order of the item, within a group)
  title: 标题
  titleCondensed:标题摘要, 当原标题太长的时候,需要用简短的字符串来代替title
  icon: icon 图标
  alphabeticShortcut: 字母快捷键
  numericShortcut:数学快捷键
  checkable:是否为checkbox, true or false
  checked:是否设置为checked状态,true or false
  visible: 是否可见, true or false
  enabled:是否可用,true or false

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/item1"
    android:title="Item 1"
    android:icon="@drawable/icon"
    android:checkable="true"
    android:checked="false"
    />
    <group android:id="@+id/group_1"
    android:checkableBehavior="single">
    <item android:id="@+id/group_item1"
    android:title="Item 1 in group"
    />
    <item android:id="@+id/group_item2"
    android:title="Item 2 in group"
    android:checked="true"
    />
    </group>
    <item android:id="@+id/submenu"
    android:title="Sub Menu">
    <menu>
    <item android:id="@+id/submenu_item"
    android:title="Sub Menu Item"
    />
    </menu>
    </item>
    <item android:id="@+id/item3"
    android:title="item 3"
    android:checkable="true"
    android:checked="true"
    />
    </menu>

  1. public void onCreate(Bundle savedInstanceState) {
  2. ...
  3. registerForContextMenu(editText);
  4. }
  5. @Override
  6. public void onCreateContextMenu(ContextMenu menu, View v,
  7. ContextMenuInfo menuInfo) {
  8. super.onCreateContextMenu(menu, v, menuInfo);

  9. getMenuInflater().inflate(R.menu.menu1, menu);
  10. }
  由于这是contextMenu,所以可以看到即使xml定义里面的item1.seticon了,但还是没有显示出来的,即那语句是无效的!

       另外,要明确的是,要显示radio,需要用group,而group里面的item设置了checked = true即选中。而 checkable和checked的区别,一开始我是很困惑的,但写了代码并运行后,明白它们的区别了: checkable=true表示这个item是checkbox,checked则表示是否选中。所以对于checkbox item,最好先写 checkable=”true”,然后再写checked。

  1. private static final int MENU_GROUPITEM1 = Menu.FIRST + 8;
  2. private static final int MENU_GROUPITEM2 = Menu.FIRST + 9;
  3. private static final int MENU_ITEM1 = Menu.FIRST + 10;

  4. public void onCreate(Bundle savedInstanceState) {
  5. ...
  6. registerForContextMenu(findViewById(R.id.edittext));
  7. }

  8. @Override
  9. public void onCreateContextMenu(ContextMenu menu, View v,
  10. ContextMenuInfo menuInfo) {
  11. super.onCreateContextMenu(menu, v, menuInfo);

  12. menu.add(1,MENU_ITEM1,Menu.NONE, "Item 1").setCheckable(true).setChecked(false);

  13. // Group ID
  14. int groupId = 0;
  15. // The order position of the item
  16. int menuItemOrder = Menu.NONE;

  17. menu.add(groupId, MENU_GROUPITEM1, menuItemOrder, "Item 1 in group");
  18. menu.add(groupId, MENU_GROUPITEM2, menuItemOrder, "Item 2 in group")
  19. .setChecked(true);
  20. menu.setGroupCheckable(groupId, true, true); //这句要写在group item的最后

  21. SubMenu subMenu = menu.addSubMenu("Sub Menu 1");
  22. subMenu.add("Sub Menu Item")
  23. .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
  24. @Override
  25. public boolean onMenuItemClick(MenuItem item) {
  26. Toast.makeText(HelloDemo.this,
  27. "Sub Menu Item selected",
  28. Toast.LENGTH_SHORT).show();
  29. return true; //true表示完成当前item的click处理,不再传递到父类处理
  30. }
  31. });

  32. menu.add("Item 3").setCheckable(true).setChecked(true);
  33. }
在编写过程中,发现groupId的影响很大,不推荐使用Menu.add(int titleRes)和add(CharSequence title)方法来添加MenuItem,因为没有指定groupID,默认为0,这样子和后面的menu group 一组了,导致执行完menu.setGroupCheckable(groupId, true, true)后同一group的Item都变成radio。

  1. @Override
  2. public boolean onCreateOptionsMenu(Menu menu) {
  3. // Group ID
  4. int groupId = 0;
  5. // The order position of the item
  6. int menuItemOrder = Menu.NONE;

  7. menu.add(groupId, MENU_COPY, menuItemOrder, "Copy")
  8. .setIcon(R.drawable.icon);
  9. menu.add(groupId, MENU_EDIT, menuItemOrder, "Edit");
  10. menu.add(groupId, MENU_PASTE, menuItemOrder, "Paste");
  11. menu.add(groupId, MENU_DELETE, menuItemOrder, "Delete");
  12. menu.add(groupId, MENU_OK, menuItemOrder, "Ok");
  13. menu.add(groupId, MENU_CANCEL, menuItemOrder, "Cancel");
  14. menu.add(groupId, MENU_TEST, menuItemOrder, "Test");
  15. menu.add(groupId, MENU_DEMO, menuItemOrder, "Demo");
  16. // .setIcon(R.drawable.icon); more expand menu 不支持icon, setIcon不会报错,但运行时还是看不到icon的

  17. //return super.onCreateOptionsMenu(menu);
  18. return true; //true表示要显示menu; false表示不显示menu
  19. }
处理菜单点击事件
       方法一:
       利用菜单自带的监听器功能,直接监听,就象处理控件事件一样,像上面的ContextMenu的subMenu.add(“Sub Menu Item”)设置MenuItem.OnMenuItemClickListener。

       方法二:
       在Activity和View都直接提供了一个菜单点击统一处理函数,
       Activity:onOptionsItemSelected (MenuItem item) ;
       Activity::onContextItemSelected(MenuItem item) ;

  1. @Override
  2. public boolean onOptionsItemSelected(MenuItem item) {
  3. switch(item.getItemId()){
  4. case MENU_COPY:
  5. Toast.makeText(this, "Copy Item selected", Toast.LENGTH_SHORT).show();
  6. break;

  7. default: break;
  8. }
  9. return false;//false表示继续传递到父类处理
  10. }

通知用户

  某些情况下需要通知用户你的应用程序中发生了一个事件。一些事件请求用户应答而另外一些则不需要。比如:
  * 当一个事件比如保存文件结束时,应该出现一条消息确认保存成功。(Toast适用)
  * 如果一个后台运行的应用程序需要用户关注,这个应用程序应该创建一个通知来允许用户在方便时进行应答。(后台程序,状态栏通知适用)
  * 如果这个应用程序在执行一个用户必须等待的任务(比如加载一个文件),那么应用程序应该显示一个盘旋的进度轮或进度条。(进度条Dialog适用)
  所有这些通知任务可以通过一个不同的技术获取到:
  * 一个消息条通知Toast Notification, 用于从后台出现的简短信息。for brief messages that come from the background。
  * 一个状态条通知A Status Bar Notification, 用于来自后台的持续提醒并请求用户应答。
  * 一个对话框通知A Dialog Notification, 用于活动相关的通知。

  消息条通知Toast Notification

  一个消息条通知是一个在窗口表面弹出的信息。它只填充内容所需的空间并且用户当前活动仍然保持可见和可交互。这个通知自动渐入渐出,而且不接受交互事件。因为消息条可以从一个后台服务Service中创建,即便应用程序不可见,它也将呈现出来。

       Toast的创建和显示都很简单,如果不使用自定义的view,只是显示文字,makeText函数就能做到了:

  1. Toast.makeText(getApplicationContext(), // Context context

  2. "This is a simple toast!", //显示的text或者引用resource.string的id

  3. Toast.LENGTH_LONG) //显示的时间长度,

  4. //LENGTH_LONG - 时间长些,>1s;

  5. //LENGTH_SHORT- 时间短

  6. .show(); //显示出来
自定义Toast
       而如果想使用custom view,首先要写个custom Layout xml文件(toastlayout.xml):

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <LinearLayout xmlns:android=http://schemas.android.com/apk/res/android
  3. android:id="@+id/toast_layout"
  4. android:orientation="horizontal"
  5. android:layout_width="fill_parent"
  6. android:layout_height="fill_parent"
  7. android:padding="10dp"
  8. android:background="#DAAA"
  9. >

  10. <ImageView
  11. android:id="@+id/toast_icon"
  12. android:layout_width="wrap_content"
  13. android:layout_height="fill_parent"
  14. android:layout_marginRight="10dp"
  15. android:src="@drawable/icon"
  16. />
  17. <TextView
  18. android:id="@+id/toast_text"
  19. android:layout_width="wrap_content"
  20. android:layout_height="fill_parent"
  21. android:textColor="#FFF"
  22. />
  23. </LinearLayout>
  注意: TextView的layout_height设置为wrap_content的话,发现左边的图片会跟随文字内容的高度而变化,就是说当文字只有一行的时候,图片的高度就变得只有一行的高度,不好看!图片的src可以不在xml文件里面定义,可以在真正显示时用以下语句来设置:

  1. ImageView image = (ImageView) layout.findViewById(R.id.image);
  2. image.setImageResource(R.drawable.android);

 以下是显示custom toast view:

  1. //加载Layout

  2. View view = getLayoutInflater().inflate(R.layout.toastlayout, //resource id
  3. (ViewGroup) findViewById(R.id.toast_layout)); //ViewGroup对象

  4. //设置Text
  5. ((TextView) view.findViewById(R.id.toast_text)).setText("This is a custom toast!");

  6. //创建Toast
  7. Toast toast = new Toast(getApplicationContext());

  8. // 设置显示的位置
  9. toast.setGravity( Gravity.CENTER_VERTICAL, //垂直居中
  10. 0, //xOffset
  11. 0 //yOffset
  12. );

  13. toast.setDuration(Toast.LENGTH_LONG);
  14. toast.setView(view); // ** 这个很重要
  15. toast.show();
消息条Toast是用来显示简短文本信息的最好方法,比如“文件已保存”,当你很确信用户正在关注屏幕时。一个消息条不能接受用户交互事件;如果你希望用户应答并采取相应动作,请考虑使用一个状态条通知Status Bar Notification。

   状态条通知Status Bar Notification

  一个状态条通知添加一个图标到系统状态栏上(以及一个可选的滚动条文本信息)以及在这个“通知”窗口中的一个扩展消息。当用户选择这个扩展消息时,Android发出这个通知所定义的一个意图(通常是启动一个活动)。你也可以配置这个通知来通过一个声音,震动和设备上的闪烁灯来警告用户。

  当你的应用程序以后台服务运行并需要通知用户事件时,这类通知是一个理想的方式。如果你需要在活动仍处于焦点下时警告用户一个发生的事件,请考虑使用对话框通知Dialog Notification 。

  1. // 获取NotificationManager

  2. mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

  3. // 创建PendingIntent, 明确响应后转向的Activity
  4. contentIntent = PendingIntent.getActivity(
  5. getApplicationContext(),0,new Intent(getApplicationContext(),FrameDemo.class), //响应Notification转向的Activity
  6. 0);

  7. //实例化一个Notification,并指定其图标和标题(在提示栏上显示)

  8. mNotification = new Notification(R.drawable.icon, // icon
  9. "Notification", // 状态栏上显示的滚动提示文字tickerText
  10. System.currentTimeMillis());//Notification计划执行的开始时间


  11. //设置Notification的Title和详细内容(打开提示栏后在通知列表中显示)
  12. mNotification.setLatestEventInfo(
  13. getApplicationContext(),"Notification open", // Title
  14. "This is a simple notification", //content
  15. contentIntent); //PendingIntent是在这时候用的

  16. //100 毫秒延迟后,震动 250 毫秒,暂停 100 毫秒后,再震动 500 毫秒
  17. mNotification.vibrate = new long[] { 100, 250, 100, 500 };
  18. //mNotification.defaults |= Notification.DEFAULT_VIBRATE; //或者设置默认的震动效果

  19. //设置闪灯绿光,也可以设置默认的效果,请参考API DOC
  20. mNotification.ledARGB = 0xff00ff00;
  21. mNotification.ledOnMS = 300;
  22. mNotification.ledOffMS = 1000;
  23. mNotification.flags |= Notification.FLAG_SHOW_LIGHTS;

  24. //设置声音,可以选择以下任一方式,但要注意,当defaults已经包含了DEFAULT_SOUND,将覆盖之前指定的音频文件的设置

  25. mNotification.defaults |= Notification.DEFAULT_SOUND; //系统默认的通知声音
  26. //mNotification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3"); //或者指定某个音频文件

  27. //设置声音持续重复,直至用户点击或者清除通知
  28. mNotification.flags |= Notification.FLAG_INSISTENT;

  29. //最后一步: NotificationManager发出通知
  30. mNotificationManager.notify(R.id.notice1, //该Notification的IDmNotification);
  清除通知Clear

  如果需要把Notification清除(clear),则调用NotificationManager。cancel(Notification的 ID),或者直接NotificationManager。clearAll()清除所有。也可以添加Notification对象的 FLAG_AUTO_CANCEL属性来自动清除。

   更新通知Update the notification
  可以通过notification对象的setLatestEventInfo()方法来修改/更新信息,也可以通过其他函数来修改notification对象的属性,最后是调用NotificationManager。notify(原来的ID, 修改/更新后的notification对象)完成的。

  1. //修改Title & content

  2. mNotification.setLatestEventInfo(
  3. getApplicationContext(),"Notification update", // Title
  4. "This is the second notification", //content
  5. contentIntent);

  6. //修改Icon
  7. mNotification.icon = R.drawable.robot;

  8. //设置自动清除
  9. mNotification.flags |= Notification.FLAG_AUTO_CANCEL;

  10. //重新发出通知
  11. mNotificationManager.notify(R.id.notice1, mNotification);
自定义view的Notification
       首先定义Layout xml文件(notifylayout.xml):

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  3. android:id="@+id/notify_layout"
  4. android:orientation="horizontal"
  5. android:layout_width="fill_parent"
  6. android:layout_height="fill_parent"
  7. android:padding="3dp"
  8. >

  9. <ImageView
  10. android:id="@+id/notify_image"
  11. android:layout_width="wrap_content"
  12. android:layout_height="fill_parent"
  13. android:layout_marginRight="10dp"
  14. />

  15. <TextView
  16. android:id="@+id/notify_text"
  17. android:layout_width="wrap_content"
  18. android:layout_height="fill_parent"
  19. android:textColor="#000"
  20. />

  21. </LinearLayout>
  然后使用RemoteView加载Layout,并设置Image,Text:

  1. RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notifylayout);
  2. contentView.setImageViewResource(R.id.notify_image, R.drawable.robot);
  3. contentView.setTextViewText(R.id.notify_text, "Hello, this message is in a custom expanded view");

  4. Notification notification = new Notification(
  5. R.drawable.icon, //icon
  6. "Notification", // 状态栏上显示的提示文字
  7. System.currentTimeMillis());

  8. notification.contentIntent = contentIntent;
  9. notification.contentView = contentView; //就是这里不同,set view

  10. // 以R.layout.notify_layout为ID
  11. mNotificationManager.notify(R.layout.notifylayout, notification);
对话框通知Dialog Notification
       一个对话框通常是出现在当前活动前面的一个小窗口。背后的活动丢失焦点而由这个对话框接受所有的用户交互。对话框通常用做和运行中应用程序直接相关的通知和短暂活动。

  一、Broadcast Receiver简介

  Android中的四大组件是 Activity、Service、Broadcast和Content Provider。而Intent是一个对动作和行为的抽象描述,负责组件之间程序之间进行消息传递。那么Broadcast Receiver组件就提供了一种把Intent作为一个消息广播出去,由所有对其感兴趣的程序对其作出反应的机制。

  二、Broadcast Receiver接收系统自带的广播

  我们做一个例子,功能是在系统启动时播放一首音乐。
  1、建立一个项目Lesson21_BroadcastReceiver,拷贝一首音乐进res/raw目录
  2、建立HelloBroadcastReceiver。java 内容如下:

  1. import android.content.BroadcastReceiver;
  2. import android.content.Context;
  3. import android.content.Intent;
  4. import android.media.MediaPlayer;
  5. import android.util.Log;

  6. public class HelloBroadReciever extends BroadcastReceiver {

  7. //如果接收的事件发生
  8. @Override
  9. public void onReceive(Context context, Intent intent) {
  10. //则输出日志
  11. Log.e("HelloBroadReciever", "BOOT_COMPLETED!!!!!!!!!!!!!!!!!!!!!!!!!");
  12. Log.e("HelloBroadReciever", ""+intent.getAction());

  13. //则播放一首音乐
  14. MediaPlayer.create(context, R.raw.babayetu).start();
  15. }
  16. }
  3、在AndroidManifest.xml中注册此Receiver :
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionname="1.0" android:versioncode="1" package="android.basic.lesson21">
  3. <application android:icon="@drawable/icon" android:label="@string/app_name">
  4. <activity android:label="@string/app_name" android:name=".MainBroadcastReceiver">
  5. <intent -filter="">
  6. <action android:name="android.intent.action.MAIN">
  7. <category android:name="android.intent.category.LAUNCHER">
  8. </category></action></intent>
  9. </activity>
  10. <!-- 定义Broadcast Receiver 指定监听的Action -->
  11. <receiver android:name="HelloBroadReciever">
  12. <intent -filter="">
  13. <action android:name="android.intent.action.BOOT_COMPLETED">
  14. </action></intent>
  15. </receiver>
  16. </application></manifest>
     三、自定义广播

  下面我们学习自己制作一个广播.我们接着刚才的例子,继续写下去.
  5、在MainBroadcastReceiver.java中填写如下代码:

  1. import android.app.Activity;
  2. import android.content.Intent;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.widget.Button;

  6. public class MainBroadcastReceiver extends Activity {
  7. /** Called when the activity is first created. */
  8. @Override
  9. public void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.main);

  12. Button b1 = (Button) findViewById(R.id.Button01);

  13. b1.setOnClickListener(new View.OnClickListener() {

  14. @Override
  15. public void onClick(View v) {
  16. //定义一个intent
  17. Intent intent = new Intent().setAction(
  18. "android.basic.lesson21.Hello").putExtra("yaoyao",
  19. "yaoyao is 189 days old ,27 weeks -- 2010-08-10");
  20. //广播出去
  21. sendBroadcast(intent);
  22. }
  23. });
  24. }
  25. }
6、更改 HelloBroadReceiver.java 内容如下:

  1. import android.content.BroadcastReceiver;
  2. import android.content.Context;
  3. import android.content.Intent;
  4. import android.media.MediaPlayer;
  5. import android.util.Log;

  6. public class HelloBroadReciever extends BroadcastReceiver {

  7. //如果接收的事件发生
  8. @Override
  9. public void onReceive(Context context, Intent intent) {
  10. //对比Action决定输出什么信息
  11. if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")){
  12. Log.e("HelloBroadReciever", "BOOT_COMPLETED !!!!!!!!!!!!!!!!!!!!!!!!!");
  13. }

  14. if(intent.getAction().equals("android.basic.lesson21.Hello")){
  15. Log.e("HelloBroadReciever", "Say Hello to Yaoyao !!!!!!!!!!!!!!!!!!!!!!!!!");
  16. Log.e("HelloBroadReciever", intent.getStringExtra("yaoyao"));
  17. }

  18. //播放一首音乐
  19. MediaPlayer.create(context, R.raw.babayetu).start();
  20. }
  21. }
7、更改 AndroidManifest.xml 内容如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="" android:versionname="1.0" android:versioncode="1">
  3. <application android:icon="@drawable/icon" android:label="@string/app_name">
  4. <activity android:label="@string/app_name" android:name=".MainBroadcastReceiver">
  5. <intent -filter="">
  6. <action android:name="android.intent.action.MAIN">
  7. <category android:name="android.intent.category.LAUNCHER">
  8. </category></action></intent>
  9. </activity>
  10. <!-- 定义Broadcast Receiver 指定监听的Action 这里我们的接收器,接收了2个Action,一个系统的一个我们自定义的 -->
  11. <receiver android:name="HelloBroadReciever">
  12. <intent -filter="">
  13. <action android:name="android.intent.action.BOOT_COMPLETED">
  14. </action></intent>
  15. <intent -filter="">
  16. <action android:name="android.basic.lesson21.HelloYaoYao">
  17. </action></intent>

  18. </receiver>
  19. </application>
  20. <uses -sdk="" android:minsdkversion="8">
  21. </uses></manifest>
  由于SMSNotifyActivity 方法中listview中有按钮提交事件普通的listview不能响应事件,ListViewButtonAdapter
扩展BaseAdapter 方法重写getView 方法,添加BUTTON 并添加按钮响应事件

  1. import java.util.ArrayList;
  2. import java.util.HashMap;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.database.Cursor;
  6. import android.util.Log;
  7. import android.view.LayoutInflater;
  8. import android.view.View;
  9. import android.view.View.OnClickListener;
  10. import android.view.ViewGroup;
  11. import android.widget.BaseAdapter;
  12. import android.widget.Button;
  13. import android.widget.TextView;

  14. /**
  15. */
  16. public class ListViewButtonAdapter extends BaseAdapter {
  17. private DiaryDbAdapter mDbHelper;
  18. private static final String TAG = "lvButtonAdapter";
  19. public static final String ACTION_INTENT_TASKRECEIVER= "com.gift.android.TaskReceiver";
  20. private class buttonViewHolder {
  21. // ImageView appIcon;
  22. TextView appName1;
  23. TextView appName2;
  24. TextView appName3;
  25. TextView appName4;
  26. TextView appName5;
  27. Button buttonClose;
  28. Button buttonView;
  29. }


  30. private ArrayList<HashMap<String, Object>> mAppList;
  31. private LayoutInflater mInflater;
  32. private Context mContext;
  33. private String[] keyString;
  34. private int[] valueViewID;
  35. private buttonViewHolder holder;
  36. public ListViewButtonAdapter(Context c,
  37. ArrayList<HashMap<String, Object>> appList, int resource,
  38. String[] from, int[] to, DiaryDbAdapter mDbHelper) {
  39. mAppList = appList;
  40. mContext = c;
  41. mInflater = (LayoutInflater) mContext
  42. .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  43. keyString = new String[from.length];
  44. valueViewID = new int[to.length];
  45. System.arraycopy(from, 0, keyString, 0, from.length);
  46. System.arraycopy(to, 0, valueViewID, 0, to.length);
  47. this.mDbHelper = mDbHelper;
  48. }


  49. @Override
  50. public int getCount() {
  51. return mAppList.size();
  52. }


  53. @Override
  54. public Object getItem(int position) {
  55. return mAppList.get(position);
  56. }


  57. @Override
  58. public long getItemId(int position) {
  59. return position;
  60. }
  61. public void removeItem(int position) {
  62. mAppList.remove(position);
  63. this.notifyDataSetChanged();
  64. }


  65. @Override
  66. public View getView(int position, View convertView, ViewGroup parent) {
  67. if (convertView != null) {
  68. holder = (buttonViewHolder) convertView.getTag();
  69. } else {
  70. convertView = mInflater.inflate(R.layout.list, null);
  71. holder = new buttonViewHolder();
  72. holder.appName1 = (TextView) convertView
  73. .findViewById(valueViewID[0]);
  74. holder.appName2 = (TextView) convertView
  75. .findViewById(valueViewID[1]);
  76. holder.appName3 = (TextView) convertView
  77. .findViewById(valueViewID[2]);
  78. holder.appName4 = (TextView) convertView
  79. .findViewById(valueViewID[3]);
  80. holder.appName5 = (TextView) convertView
  81. .findViewById(valueViewID[4]);
  82. holder.buttonClose = (Button) convertView
  83. .findViewById(valueViewID[5]);
  84. holder.buttonView = (Button) convertView
  85. .findViewById(valueViewID[6]);
  86. convertView.setTag(holder);
  87. }


  88. HashMap<String, Object> appInfo = mAppList.get(position);
  89. if (appInfo != null) {
  90. Long aname1 = (Long) appInfo.get(keyString[0]);
  91. String aname2 = (String) appInfo.get(keyString[1]);
  92. String aname3 = (String) appInfo.get(keyString[2]);
  93. String aname4 = (String) appInfo.get(keyString[3]);
  94. String aname5 = (String) appInfo.get(keyString[4]);
  95. holder.appName1.setText(String.valueOf(aname1));
  96. holder.appName2.setText(aname2);
  97. holder.appName3.setText(aname3);
  98. holder.appName4.setText(aname4);
  99. holder.appName5.setText(aname5);
  100. holder.buttonClose
  101. .setOnClickListener(new lvButtonListener(position));
  102. holder.buttonView
  103. .setOnClickListener(new lvButtonListener(position));
  104. }
  105. return convertView;
  106. }
  107. class lvButtonListener implements OnClickListener {
  108. private int position;
  109. lvButtonListener(int pos) {
  110. position = pos;
  111. }


  112. @Override
  113. public void onClick(View v) {
  114. int vid = v.getId();
  115. if (vid == holder.buttonClose.getId()) {
  116. boolean flag = mDbHelper.deleteDiary(Long
  117. .parseLong((holder.appName1.getText().toString())));
  118. Log.i(TAG, "[SMSApp] deletesql: " + flag);
  119. removeItem(position);
  120. }
  121. if (vid == holder.buttonView.getId()) {
  122. // 查看短信详细
  123. ShowView(Long.parseLong((holder.appName1.getText().toString())));
  124. }
  125. }


  126. private void ShowView(long id) {
  127. Cursor mDiaryCursor = mDbHelper.getDiary(id);
  128. if (mDiaryCursor != null) {
  129. boolean flag = mDbHelper.updateDiary(id,
  130. mDiaryCursor.getString(1), mDiaryCursor.getString(2),
  131. mDiaryCursor.getString(3), "1",mDiaryCursor.getString(6));
  132. Log.i(TAG, "[SMSApp] updatesql: " + flag);


  133. // 广播消息
  134. Intent intent = new Intent(ACTION_INTENT_TASKRECEIVER);
  135. intent.putExtra("TaskContent", mDiaryCursor.getString(2)+"#"+mDiaryCursor.getString(6));
  136. mContext.sendBroadcast(intent);
  137. }
  138. }
  139. }

  140. }



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值