系统架构与开发环境搭建          3月2日Android Activities代码练习     3月5日

Intent的应用与传值 3月9日
1:显式Intent与隐式Intent的区别
        显式Intent直接用组件的名称定义目标组件,这种方式很直接。但是由于开发人员往往并不清楚别的应用程序的组件名称,因此,显式Intent更多用于在应用程序内部传递消息。比如在某应用程序内,一个Activity启动一个Service。
         隐式Intent恰恰相反,它不会用组件名称定义需要激活的目标组件,它更广泛地用于在不同应用程序之间传递消息。
在显式Intent消息中,决定目标组件的唯一要素就是组件名称,因此,如果你的Intent中已经明确定义了目标组件的名称,那么你就完全不用再定义其他Intent内容。
2:Intent对象如何传递数据,需要用到什么方法​
(1)一般方式传值跳转:startActivity()方法一般方式传值跳转:startActivity()方法
(2)​回调数据式传值跳转:startActivityForResult()方法 
(3)调用在下个activity自定义的方法“actionStart()”
3:Android日志工具Log
     Log.v( ):打印意义最小的日志信息
      Log.d( ):打印调试信息
      Log.i() :打印比较重要的数据
      Log.w( ):打印警告信息
      Log.e( ):打印错误信息
4:向下一个活动传递数据
      第1个Activity中处理事件的代码中书写步骤        onclick
       1、创建Intent对象
            2、传值: intent.putExtra("键” ,”值”);
    第2个Activity获取Intent对象,并取出其中        封装数据
             1、getIntent( )
       2、intent.getStringExtra("键”);
5:返回数据给上一个活动
      一、第1个Activity中startActivity方法换成  startActivityForResult(intent,请求码)
   二、第 2个Activity中:
              1、创建Intent对象
              2、调用intent.putExtra方法传入数据
              3、setResult(Result OK,intent);
           4、finish():销毁当前活动
     三、第1个Activity重写onActivityResult()                   获取返回数据
一.一般方式传值跳转:startActivity()方法
/* 在MainActivity中定义如下代码 /
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent _intent = new
Intent(MainActivity.this,TwoActivity.class);
//在Intent对象当中添加一个键值对
_intent.putExtra(key,value);
startActivity(_intent);
}
});
1234567891011121314
public class TwoActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.second_layout);
Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//取得从上一个Activity当中传递过来的Intent对象
Intent _intent = getIntent();
//从Intent当中根据key取得value
if (_intent != null) {
String _value = _intent.getStringExtra(key);
Toast.makeText(TwoActivity.this,_value, Toast.LENGTH_SHORT).show();
}
}
});
}
}
1234567891011121314151617181920212223
二、回调数据式传值跳转:startActivityForResult()方法
1、在第一个页面(MainActivity.java)中以方法startActivityForResult( )启动第二个页面。
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent _intent = new Intent(MainActivity.this,TwoActivity.class);
_intent.putExtra(key, value);
// 第二个参数是请求码,只要是一个唯一值
startActivityForResult(_intent, 1234);
}
});
2、在第二个页面中对要返回的数据进行打包,并以方法setResult( )返回第一个页面;
//必须返回发送请求码的Activity
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.putExtra(“key2”,“dsafas”);
setResult(1234,intent);
cccc.this.finish();
}
});
3、在第一个页面中复写onActivityResult( )方法,用于获取和处理第二页面返回的数据,更新页面。
// 由于我们rtActivityForResult()方法来启动Twtivity的
// 在TwoActivity被销毁之后上一个活动的onActivityResult()方法
// resultCode判断返回码 requestCode请求码
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (resultCode) {
case 1234:
String returnedData = intent.getStringExtra(key1);
Toast.makeText(MainActivity.this,returnedData, Toast.LENGTH_SHORT).show();
break;
default:
}
}onActivityResult()方法带有三个参数,第一个参数requestCode,即我们在启动活动时传入的请求码。第二个参数resultCode,即我们在返回数据时传入结果码。第三个参数data,即携带着返回数据的Intent。由于在一个活动中有可能调用startActivityForResult()方法去启动很多不同的活动,每一个活动返回的数据都会回调到onActivityResult()这个方法中,因此我们首先要做的就是通过检查requestCode的值来判断数据来源。确定数据是从TwoActivity返回的之后,我们再通过resultCode的值来判断处理结果是否成功。最后从data中取值并打印出来,这样就完成了向上一个活动返回数据的工作。
public class TwoActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.second_layout);
Button button2 = (Button) findViewById(R.id.button_2);
// 接收从MainaActivity传递的数据
Intent _intent = getIntent();
if (_intent != null) {
String _value = _intent.getStringExtra(key);
Toast.makeText(TwoActivity.this, _value, Toast.LENGTH_SHORT).show();
}
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra(key1,value two activity);
// 专门用于向上一个活动返回数据
// 第一个参数用于向上一个活动返回结果码,一般只使用RESULT_OK或RESULT_CANCELED这两个值
// 第二个参数则是把带有数据的Intent传递回去
setResult(RESULT_OK, intent);
// 调用了finish()方法来销毁当前活动
finish();
}
});
}
}

三、启动活动的最佳写法
在真正的项目开发中经常会有对接的问题出现。比如TwoActivity并不是由你开发的,但现在你负责的部分需要有启动TwoActivity这个功能,而你却不清楚启动这个活动需要传递哪些数据。这时无非就有两种办法,一个是你自己去阅读TwoActivity中的代码,二是询问负责编写TwoActivity的同事。你会不会觉得很麻烦呢?其实只需要换一种写法,就可以轻松解决掉上面的窘境。
/ 在MainActivity中定义如下代码 */
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
/最佳数据传值方法:调用在下个activity自定义的方法/
TwoActivity.actionStart(MainActivity.this, data1, data2);
}
});
1234567891011
public class TwoActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.second_layout);
}
/最佳数据传值方法/
public static void actionStart(Context context, String data1, String data2) {
Intent intent = new Intent(context, TwoActivity.class);
intent.putExtra(param1, data1);
intent.putExtra(param2, data2);
context.startActivity(intent);
}
}

Activity的生命周期和启动模式 3月12日
一、生命周期
1. Activity的各种生命周期
        系统中的Activity由Activity堆栈管理,当启动一个新的Activity的时候,这个Activity被放置在栈顶,并处于正在运行状态。前一个Activity在堆栈中位于新的Activity下面,并且在新的Activity退出前不会出现在前台。
下面用一张图展示Activity完整生命周期

onCreate 在Activity第一次被创建时调用onCreate方法。我们通常在onCreate方法中加载布局,初始化控件。
onStart 在Activity变为可视的时候,调用onStart方法。
onResume 当Activity处于栈顶,并处于正在运行状态,可以与用户进行交互的时候,调用onResume方法。
onPause 当Activity已经失去焦点,且依旧是可视状态时调用onPause方法,此时Activity无法与用户进行交互。
onStop 当Activity从可视变为不可视的时候,调用onStop方法。
onDestory onDestory方法在Activity被销毁前调用。
onRestart onRestart方法在Activity被重新启动时调用,在Activity第一次被创建的时候不会调用。
        完整生命周期: 完整生命周期在Activity第一次创建调用onCreate方法到销毁前调用onDestroy方法之间。 可视生命周期: 可视生命周期在Activity调用onStart方法变为可视到调用onStop方法变为不可视之间。 前台生命周期: 前台生命周期在Activity调用onResume方法变得可与用户交互到调用onPause方法变得不可与用户交互之间。
2. onSaveInstanceState() 与onRestoreInstanceState()
        系统在“未经你许可”销毁Activity时调用onSaveInstanceState方法,用于保存Activity状态信息。onRestoreInstanceState方法在Activity被系统销毁之后恢复Activity时被调用,用于恢复Activity状态信息。可重写这两个方法在系统“未经你许可”销毁Activity时保存和恢复你的数据。 所谓“未经你许可”指的是非人为销毁Activity,例如按下回退键退出页面属于人为,系统因内存不足回收销毁Activity属于非人为。
什么时候调用onSaveInstanceState方法 (1)、当用户按下HOME键时。 (2)、切换到其他进程时。 (3)、锁屏时。 (4)、启动新的Activity时。 (5)、屏幕方向切换时
什么时候调用onRestoreInstanceState方法 在Activity被系统销毁,又回到该Activity的时候。如用户按下HOME键又马上返回该Activity,这个时候该Activity一般不会因为内存不足而被系统回收,故不调用onRestoreInstanceState方法。所以onSaveInstanceState与onRestoreInstanceState不一定会成对被调用。
3. Activity生命周期的变化
        分别新建3个Activity,MainActivity、TestActivity、TransparentActivity,并在每个Activity中重写onCreate,onStart,onResume,onPause,onStop,onDestroy,onRestart,onSaveInstanceState,onRestoreInstanceState这9个方法。
例:启动Activity,首先创建Activity,然后页面变得可见,最后页面准备好与用户交互,所以生命周期的调用顺序应该是 onCreate() -> onStart() -> onResume()

               二、启动模式               3月13日

Activity储存在Activity栈中,每次创建Activity都会在Activity栈中添加,Activity被销毁时也会从Activity栈中退出。大量的创建、销毁Activity会对系统造成很大开销,为了节省开销,我们可能会复用一些Activity,Activity的启动模式就是为了方便复用Activity而设计的。下面来看一下Activity的4种启动模式:
1. 标准模式 standard
standard是Activity的默认启动模式,如果没有指定启动模式的话,这个Activity就是标准模式。
2. 栈顶复用模式 singleTop
栈顶复用模式指的是,假如Activity处于栈顶,再次启动这个Activity的时候,复用该Activity。
3. 栈内复用模式 singleTask
栈内复用模式跟栈顶复用模式相似,只要在同一个栈内启动模式为栈内复用模式的Activity,再次启动的时候就可以复用。

4.单实例模式 singleInstance
被设置启动模式为单实例模式的Activity独自享有一个Activity栈。
联系代码:

           安卓常用UI布局及控件      3月16日

一、布局的介绍:
    1、在4.0以前版本中一共有五种布局,都是ViewGroup的子类。分别是AbsoluteLayout、RelativeLayout、LinearLayout、FrameLayout、TableLayout。而TableLayout是LinearLayout的子类。(中文分别是:绝对布局、相对布局、线性布局、帧布局、表格布局)。
二、View类的常用xml属性:
(一)、类结构:
        java.lang.Object
           ↳  android.view.View
(二)、View及其子元素常用属性:(各种布局及控件的共同属性)
        android:id
        android:background 
        android:onClick             为该控件的单击事件绑定监听器
        android:padding            设置控件四周的填充区域
        android:visibility            设置该控件是否可见(invisible/visible/gone)
        android:alpha                设置该组件透明度(0-1之间的数值)
        android:layout_height             子组件的布局高度
        android:layout_width               子组件的布局宽度
        android:layout_margin            设置子组件的外边距
三、LinearLayout:
(一)、概念:线性布局控制其中的控件或组件横向或纵向排列。在线性布局布局中,每一行或每一列只能放单独一个控件。线性布局不会换行。当控件排列到窗体边缘,后面的控件就被隐藏,而不会显示出来。
线性布局的默认方向是水平方向(Horizontal),还有一个选项是vertical。
(二)、LinearLayout的常用属性:
1.android:orientation     定义布局内控件或组件的排列方式
        可选项:vertical 、 horizontal
2.android:layout_width    定义控件的宽度
3.android:layout_height    定义控件的高度
4.android:id   设置控件的id。这样就可以在R.java中自动生成相应的值,在程序中通过findViewById就可以调用。
        设置id的格式为:android:id = “@+id/id的名字”
5.android:background     设置控件的背景颜色或背景图片
        例如:android:background="#ffffff"
                   android:background="@drawable/图片名称"
6.android:layout_weight    设置控件的权重。即各控件在水平或者垂直方向上平均分配。
7.android:gravity   该属性用来控制该View的内容物的位置。
        如果该属性是定义在布局节点中,则该布局中所有控件的位置都受到这个属性的控制。
        如果该属性出现在Button、TextView、EditText等控件中,则用来控制这些控件上的文字的位置。
       可选项有:top、bottom、left、right、center_vertical、fill_vertical 、 center、fill等等。
     【备注:】本属性与android:layout_gravity不同。
8.android:layout_gravity   该属性用于设置控件相对于容器的对齐方式。
      可选项有:top、bottom、left、right、center_vertical、center_horizontal 、fill_vertical 、 center、fill等等。
      这些可选项中不是适用于每一种布局。在垂直线性布局中,android:gravity为bottom不起作用;而水平线性布局中,     android:gravity为right不起作用。
    【备注:】而本属性是android:layout_gravity属性,与 android:gravity 属性不同。
(三)、LinearLayout的特有属性:【重新归纳:去除公共属性后的特有属性】
         1、android:orientation    布局管理器内组件的排列方式
         2、android:gravity    设置布局管理器内组件的对齐方式
         3、android:weightSum
(四)、 LinearLayout 子元素的特有属性:
         1、android:layout_weight    子元素在 LinearLayout 中所占的权重
         2、android:layout_gravity     子元素在 LinearLayout 中的对齐方式

四、RelativeLayout: 3月19日
(一)、概念:指按着控件之间的相对位置来进行布局。
(二)、RelativeLayout特有属性:
1、android:gravity    设置布局容器内子控件的对齐方式    
2、android:ignoreGravity    设置布局管理器内哪个控件不受gravity属性的影响
(三)、RelativeLayout子元素的特有属性:LayoutParams
    A、第一组:指兄弟控件之间的相对位置。该组属性的值是另一个控件的id。
layout_toRightOf      该控件在哪个控件的右侧
layout_toLeftOf        该控件在哪个控件的左侧
layout_above           该控件在哪个控件的上侧
layout_below            该控件在哪个控件的下侧
    B、第二组:指兄弟控件之间的对齐关系。该组属性的值是另一个控件的id。
layout_alignRight      该控件与哪个控件的右对齐
layout_alignLeft        该控件与哪个控件的左对齐
layout_alignTop        该控件与哪个控件的顶对齐
layout_alignBottom   该控件与哪个控件的底对齐
    C、第三组:指控件与父布局之间的对齐关系。该组属性的值是true或者false。
layout_alignParentRight               该控件与父布局控件的右对齐吗?
layout_alignParentLeft                 该控件与父布局控件的左对齐吗?
layout_alignParentTop                 该控件与父布局控件的顶端对齐吗?
layout_alignParentBottom            该控件与父布局控件的底部对齐吗?
layout_centerInParent                  该控件位于父布局控件的中心位置吗?
layout_centerVertical                    该控件位于父布局控件的垂直中心位置吗?
layout_centerHorizontal                该控件位于父布局控件的水平中心位置吗?

五、Android UI控件及UI组件: 3月20日
(一)、控件名称:【标红色的为常用的】
TextView        文本视图
EditText         文本编辑框
Button            按钮
六、基本控件:——TextView:
(一)、TextView类结构:
         java.lang.Object
              ↳ android.view.View
                   ↳ android.widget.TextView
(二)、TextView 常用属性:
             1、andorid:text   设置文本的内容
             2、 android:textColor     设置文本的颜色
             3、 android:textSize       设置文本的字体大小(sp)
             4、andorid:height          设置文本的高度,以像素为单位
             5、 android:width            设置文本的宽度,以像素为单位
             6、 android:inputType     设置文本的类型。例如是普通文本,还是email,password,数字等等。
七、基本控件:——EditText:
(一)、 EditText 类结构:
               java.lang.Object
                   ↳ android.view.View
                          ↳ android.widget.TextView
                                  ↳ android.widget.EditText
 所以 EditText 继承了TextView的所有属性。
(二)、android:inputType的可选项:
                android:inputType=“textPersonName” 
                android:inputType=“textPassword” 
                android:inputType=“numberPassword”      只可以输入数字
                android:inputType=“textEmailAddress” 
                android:inputType=“phone”      只允许输入数字,括号等特殊符号,不可以输入字母。
                android:inputType=“textPostalAddress”   
                android:inputType=“time” 
                android:inputType=“date” 
                android:inputType=“number” 
八、基本控件:——Button:
(一)、Button类结构:
               java.lang.Object
                    ↳ android.view.View
                          ↳ android.widget.TextView
                                 ↳ android.widget.Button
 所以Button继承了TextView的所有属性。
【特别补充:】sp、dp、dip、dpi 、 pt、px等单位的区别?
        dpi    dpi指像素密度。dots per inch  ,即每英寸内像素点的个数。它不是表示长度的单位。
        在android中认为:低(120dpi),中(160dpi),高(240dpi),超高(320dpi)。随着技术的增长,实际dpi已经超出这个定义。
        dip    dimension independent pixels  ,即与设备无关的像素。目前这个单位已经被dp所取代,而不建议使用dip。
        dp     与dip的概念一样。不过dp已经取代了dip。在Android中用来表示非文字大小的尺寸。例如:外边距、内填充等。
px = dp * (dpi / 160)
3.7寸屏幕,分辨率320*480手机上,正好1px = 1dp。
        sp      scale  independent  pixel  ,即与缩放比例无关的像素。在android中常用来表示文字大小。
        px      表示像素。因为同样是200px,但是在不同手机下显示的大小是不同的。
        pt      point磅。1磅=1/74英寸
        xlarge 屏幕至少:960dp x 720dp 
        large 屏幕至少 :640dp x 480dp 
        normal 屏幕至少 :480dp x 320dp 
        small 屏幕至少 :426dp x 320dp
总之:dp是用来定义非文字的尺寸,sp用来定义文字大小。px只用于产生一条一像素的分割线时使用。

                               ListView                       3月23日

1.简单介绍ListView
listview是一个以垂直方式在项目中显示视图的列表。是一种不能实现确定视图中的内容的适配器视图(adapter view)。数据和视图的绑定,需要通过继承ListViewAdapter接口的适配器实现。确保当上下滚动的时候,能够动态刷新视图内容。通常我们都会自定义一个继承自BaseAdapter(已继承ListViewAdapter),ArrayAdapter(继承自BaseAdapter),SimpleAdapter(继承自BaseAdapter)的类,重写getView()方法,实现自己想要的功能。
getView方法详情
View getView (int position, View convertView, ViewGroup parent)
Get a View that displays the data at the specified position in the data set.
You can either create a View manually or inflate it from an XML layout file.
When the View is inflated, the parent View (GridView, ListView…) will apply
default layout parameters unless you use inflate(int, android.view.ViewGroup, boolean) to
specify a root view and to prevent attachment to the root
备注:使用适配器构建布局。
如果布局的内容是属于动态或未预先确定的内容,您可以使用这样一种布局:在运行时通过子类 AdapterView 用视图填充布局。 AdapterView 类的子类使用 Adapter 将数据与其布局绑定。
Adapter 充当数据源与 AdapterView 布局之间的中间人—Adapter(从数组或数据库查询等来源)检索数据,并将每个条目转换为可以添加到 AdapterView 布局中的视图。
使用数据填充适配器视图
    您可以通过将 AdapterView 实例与 Adapter 绑定来填充 AdapterView(如 ListView 或 GridView),此操作会从外部来源检索数据,并创建表示每个数据条目的 View。
Android 提供了几个 Adapter 子类,用于检索不同种类的数据和构建 AdapterView 的视图。 两种最常见的适配器是:ArrayAdapter和SimpleCursorAdapter。
2.ListView使用步骤
1).在布局的XML文件中,添加如下代码:

2)新建list_item的布局文件,确定每一个View的样式
  3).新建一个适配器类。
4).绑定数据到视图。

             RecyclerView的简单使用       3月26日

RecyclerView是什么?
RecyclerView是一种新的视图组件,目标是为任何基于适配器的视图提供相似的渲染方式。它被作为ListView和GridView控件的继承者,在最新的support-V7版本中提供支持。
在开发RecyclerView时充分考虑了扩展性,因此用它可以创建想到的任何种类的的布局。但在使用上也稍微有些不便。这就是Android——要完成一件事情总不是那么容易。
整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。
RecyclerView可以实现以下功能:
ListView的功能
GridView的功能
横向ListView的功能
横向ScrollView的功能
瀑布流效果
便于添加Item增加和移除动画
基本使用
引入官方提供的V7包
main.xml:

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

<android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width=“fill_parent”
        android:layout_height=“fill_parent” />

setLayoutManager需要一个LayoutManager,这个类有三个实现,分别是:
  1.LinearLayoutManager 线性管理器,支持横向、纵向
  2.GridLayoutManager 网格布局管理器
  3.StaggeredGridLayoutManager 瀑布就式布局管理器
上边的代码使用的是GridLayoutManager展示一个两列的网格布局效果;
再来说说adapter,RecyclerView包含了一种新型适配器,它也需要使用ViewHolder,使用时需要重写两个主要方法:一个用来展现视图和它的持有者的onCreateViewHolder(ViewGroup parent, int viewType),一个用来把数据绑定到视图上的onBindViewHolder(ViewHolder holder, int position)。这么做的好处是,onCreateViewHolder只有当我们真正需要创建一个新视图时才被调用,不需要检查它是否已经被回收。
Adapter代码:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.myViewHolder> {
    private Context context;
    private List mDatas;
    public RecyclerAdapter(Context context, List mDatas) {
        super();
        this.context = context;
        this.mDatas = mDatas;
    }
    @Override
    public myViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        myViewHolder holder = new myViewHolder(LayoutInflater.from(context).inflate(R.layout.item_home, parent, false));
        return holder;
    }
    @Override
    public void onBindViewHolder(final myViewHolder holder, int position) {
        holder.tv.setText(mDatas.get(position));
    }
    @Override
    public int getItemCount() {
        return mDatas.size();
    }
    class myViewHolder extends RecyclerView.ViewHolder {
        TextView tv;
        public myViewHolder(View itemView) {
            super(itemView);
            tv = (TextView) itemView.findViewById(R.id.pos);
        }
    }  
}

                 Adapter适配器           3月27日

Adapter:适配器,因为ListView是一个View,不能添加子项,因此在呈现数据的时候就需要某种工具将数据呈现在ListView上,而Adapter就能充当此角色。

LayoutInflater
     它的作用类似于findViewById(),不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;而findViewById()是找xml布局文件下的具体widget控件(如Button、TextView等)。
    具体作用:
   1)、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;
   2)、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素。
获得 LayoutInflater 实例的三种方式
LayoutInflater inflater = getLayoutInflater();//调用Activity的getLayoutInflater()
LayoutInflater inflater = LayoutInflater.from(context);
LayoutInflater inflater = (LayoutInflater)context.getSystemService

ViewHolder
要想使用 ListView 就需要编写一个 Adapter 将数据适配到 ListView上,而为了节省资源提高运行效率,一般自定义类 ViewHolder 来减少 findViewById() 的使用以及避免过多地 inflate view,从而实现目标。
Adapter的定义 
1、继承 BaseAdapter (可在继承的时候指定泛型,扩展使用);
2、重写四个基本方法:
getCount():获取数据的总的数量,返回 int 类型的结果;
getItem(int position) :获取指定位置的数据,返回该数据;
getItemId(int position):获取指定位置数据的id,返回该数据的id,一般以数据所在的位置作为它的id;
getView(int position,View convertView,ViewGroup parent):关键方法,用于确定列表项
3、创建 ViewHolder (包含列表项的控件。)
代码展示
public class MyListAdapter extends BaseAdapter // 类定义
// 自定义数据集与布局加载器
List notes;
LayoutInflater inflater;
/** 构造方法 /
public MyListAdapter(Context context,List notes){
    this.notes = notes;
    inflater = LayoutInflater.from(context);
}
/
* 重写方法 /
@Override
public int getCount(){
    return notes.size();
}
@Override
public Object getItem(int position){
    return notes.get(position);
}
@Override
public long getItemId(int position){
    return position;
}
@Override
public View getView(int position,View convertView,ViewGroup parent){
    ViewHolder viewHolder;
    // 若无可重用的 view 则进行加载
    if(converView == null){
        convertView = inflater.inflate(‘列表项布局文件’,parent,false);
        // 初始化 ViewHolder 方便重用
        viewHolder = new ViewHolder();
        viewHolder.tvTitle = (TextView) convertView.findViewById(‘id1’);
        viewHolder.tvContent = (TextView) convertView.findViewById(‘id2’);
        converView.setTag(viewHolder);
    }else{ // 否则进行重用
        viewHolder = (ViewHolder)convertView.getTag();
    }
    // 获得条目内容对象
    Note note = notes.get(position);
    // 设置内容(Note Bean 需要自定义)
    viewHolder.tvTitle.setText(note.getTitle());
    viewHolder.tvContent.setText(note.getContent());
    return converView;
}
/
* 创建 ViewHolder */
class ViewHolder{
    TextView tvTitle;
    TextView tvContent;
}

               Fragment应用             3月30日

Fragment
还是先来基本介绍。
Fragment –> 片段。
在Android3.0的时候被引入,它的出现主要是给大屏幕设备提供更加灵活的UI支持。通过对Activity布局进行分片,更加方便的对每块进行独立控制。这些片段可以被不同的activity复用。
fragment生命周期
每个fragment拥有自己的生命周期,但是fragment要依赖于activity存在,生命周期受到包括它的activity的生命周期控制。

介绍一下常用的几个生命周期函数:
onAttach(Context) –> 当fragment被绑定到activity上时回调
onCreate(Bundle) –> 当fragment对象创建的时候回调,一般在此方法里做参数接收。
onCreateView(LayoutInflater, ViewGroup, Bundle) –> 创建fragment视图时回调
onDestoryView –> 视图销毁时回调
onDestory –> 销毁fragment时回调
onDetech() –> fragment与activity失去关联时回调
fragment的使用
使用fragment可以当成一个控件,直接放到activity布局文件里;也可以在代码里面动态的添加、更新或者删除。
注意:
使用标签显示Fragment的时候,需要对这个fragment设置一个id或者tag,否则会出现”Error inflating class fragment”错误。
Fragment的子类继承的时候,如果你的minSdkVersion <= 11,需要引入V4包,然后倒入android.support.v4.app.Fragment包。如果是大于11,直接导入android.app.Fragment包即可。
Fragment的事务管理
android里通过FragmentManager类进行管理fragment,一组对fragment的操作(添加、删除、替换等)称为一个事务,通过FragmentTransaction类来提交执行。也可以把事务添加到回退栈中,进行回滚。这有点类似于数据库的事务机制。
注意:
事物操作最后必须调用commit()才能执行。
调用commit()方法之后,也不是立刻执行;如果需要立刻执行,可以使用executePendingTransactions()方法。
一次性add多个fragment,显示的是最后一个。
任务栈回退针对的是事务,而不是fragment。一次事务操作过程中可以有很多个对fragment的操作。
只能在activity处于可保存状态的情况下,进行事务操作。否则引发异常。
比如,在onPause()或者onStop()中提交事务,就会出现以上问题,如果非要在这些生命周期里面进行事务提交,请使用FragmentTransaction类的commitAllowingStateLoss()方法,允许状态丢失。
如果activity继承的是AppCompatActivity,onBackPressed()回调函数里面是利用的V4包的getSupportFragmentManager()进行的栈回退,所以做fragment回退的时候需要注意引用的是不是V4包的Fragment类。
Fragment之间的切换
Fragment的切换就是基本就是利用add()、hide()、show()、replace()这四个方法。
Fragment与Activity之间传值
fragment –> activity 99%的做法都是通过接口回调来做的。定义一个接口,activity中实现此接口方法,在fragment里面调用接口方法
activity –> fragment 通过findFragmentById()后者findFragmentByTag()方法获取fragment实例调用fragment里的public方法即可。
Fragment切换动画
Fragment的切换动画可以使用系统的标准动画,也可以自定义动画。
使用系统的需要用到setTransition(),但是只能设置系统提供的有限的动画效果。
FragmentTransaction.TRANSIT_FRAGMENT_OPEN
FragmentTransaction.TRANSIT_FRAGMENT_CLOSE
FragmentTransaction.TRANSIT_FRAGMENT_FADE
注意:
setCustomAnimations()必须在add()、remove()、replace()调用之前设置,否则不起作用。
比如:有两个fragment A和B,从A切换到B的时候
@AnimRes int enter
表示Fragment B的进入动画
@AnimRes int exit
表示Fragment A的退出动画
@AnimRes int popEnter
表示当从B界面pop回到A时,Fragment A的进入动画
@AnimRes int popExit
表示当从B界面pop回到A是,Fragment B的退出动画
如果使用add的方式显示下一个fragment,则只会触发enter 和 popExit动画,因为这种情况下A并没有被移除,只是触发了与B相关的动画
便于添加Item增加和移除动画
基本使用
引入官方提供的V7包
main.xml:

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

<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width=“fill_parent”
android:layout_height=“fill_parent” />

setLayoutManager需要一个LayoutManager,这个类有三个实现,分别是:
  1.LinearLayoutManager 线性管理器,支持横向、纵向
  2.GridLayoutManager 网格布局管理器
  3.StaggeredGridLayoutManager 瀑布就式布局管理器
上边的代码使用的是GridLayoutManager展示一个两列的网格布局效果;
再来说说adapter,RecyclerView包含了一种新型适配器,它也需要使用ViewHolder,使用时需要重写两个主要方法:一个用来展现视图和它的持有者的onCreateViewHolder(ViewGroup parent, int viewType),一个用来把数据绑定到视图上的onBindViewHolder(ViewHolder holder, int position)。这么做的好处是,onCreateViewHolder只有当我们真正需要创建一个新视图时才被调用,不需要检查它是否已经被回收。
Adapter代码:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.myViewHolder> {
private Context context;
private List mDatas;
public RecyclerAdapter(Context context, List mDatas) {
super();
this.context = context;
this.mDatas = mDatas;
}
@Override
public myViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
myViewHolder holder = new myViewHolder(LayoutInflater.from(context).inflate(R.layout.item_home, parent, false));
return holder;
}
@Override
public void onBindViewHolder(final myViewHolder holder, int position) {
holder.tv.setText(mDatas.get(position));
}
@Override
public int getItemCount() {
return mDatas.size();
}
class myViewHolder extends RecyclerView.ViewHolder {
TextView tv;
public myViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.pos);
}
}
}

              广播的介绍及使用           4月2日

Android中的广播主要可以分为两种类型:标准广播和有序广播。
标准广播
一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时间接收到这条广播,因此他们之间没有任何的先后顺序。
特点:效率高;缺点:无法拦截。
有序广播
一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到这条广播,当该广播接收器执行完OnReceive()方法逻辑后,广播才会继续传递。 
特点:优先级高者会先接收到广播,并且可以拦截该条广播是否继续传递。
注意点
有些广播可以通过动态(java代码)静态(xml文件)方式任一种来注册;
有些广播则必须通过某一种方式来注册,比如开机广播必须通过xml方式来注册,监听手机屏幕解锁开锁则必须通过java代码来注册。
示例
接收系统广播
1,监听手机是否插入耳机广播(动态注册)
注册代码
intentFilter = new IntentFilter();intentFilter.addAction(“android.intent.action.HEADSET_PLUG”);registerReceiver(myBrodcast, intentFilter);Toast.makeText(this,“监听耳机广播已注册”, Toast.LENGTH_SHORT).show();
广播接收器代码
classMyBrodcastextendsBroadcastReceiver{
@Override
publicvoidonReceive(Context context, Intent intent) {if(null!= intent) {               
String action = intent.getAction();
switch(action){
case"android.intent.action.HEADSET_PLUG":if(intent.hasExtra(“state”)) {
if(intent.getIntExtra(“state”,0) ==0) {                               
Log.e(TAG,“headset not connected”);                           
}else if(intent.getIntExtra(“state”,0) ==1) { 
Log.e(TAG,“headset connected”); 
                          }
                        }break; 
              }
            }
        } 
  }
运行插入耳机、拔出耳机Log打印:

2,监听手机锁屏解锁开锁广播(动态+静态)
注册代码
intentFilter = new IntentFilter();intentFilter.addAction(Intent.ACTION_SCREEN_OFF); // 必须代码来注册intentFilter.addAction(Intent.ACTION_SCREEN_ON); // 必须代码注册//                intentFilter.addAction(Intent.ACTION_USER_PRESENT); // 可以静态注册registerReceiver(bootCompleteReceiver, intentFilter);Toast.makeText(this,“锁屏解锁广播已注册”, Toast.LENGTH_SHORT).show();
xml
广播接收器
@OverridepublicvoidonReceive(Context context, Intent intent) {// TODO: This method is called when the BroadcastReceiver is receiving// an Intent broadcast.if(null!=intent) {if(intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {Log.e(TAG,“手机开屏”);            }elseif(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {Log.e(TAG,“手机锁屏”);
            }else if(intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
Log.e(TAG,“手机解锁”);
            }
        } 
  }
运行效果图

3,监听手机开机广播(静态注册)
注册代码

接收器代码
case"android.intent.action.BOOT_COMPLETED":Log.e(TAG,“手机已开机”);                    break;
- 发送自定义广播
上面讲的都是系统广播,系统广播需要注册;而自定义广播则需要人为发送。 
一般情况使用自定义广播来实现某个功能,下面就来看个例子:接收到自定义广播后,启动一个界面。 
注册代码

直接使用前面的广播接收器了,在这里增加一个自定义的 action。 
点击注册代码
Intent intent =newIntent(“com.example.mu16jj.broadcastreceiver”);                sendBroadcast(intent);
接收器代码
case"com.example.mu16jj.broadcastreceiver":                    Log.e(TAG,“我是自定义的”);// 在广播接收器中打开Activity                    Intent inten = new Intent(context, MainActivity.class);inten.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(inten);break;
运行后Log

- 发送有序广播
发送方式由原来的 sendBroadcast(intent) 改变为 sendOrderedBroadcast(intent, null),不同的应用注册同一个广播,那么这两个(或者更多)都是可以接收到这条广播的。
既然是有序广播,那么这个顺序的确定就由有一个属性来确定,例如:
priority 数越大优先级别越高,最大值是2147483647;优先级别也可以调用 IntentFilter 对象的 setPriority() 方法进行设置。
当然也可以拦截,只需要在广播接收器的 onReceive() 方法中调用下面一句代码就可以实现:
abortBroadcast();
使用本地广播
上面的有序广播提到了不同的应用可以相互接受广播,那么就存在一个安全问题,为此,Android 系统为我们提供了本地广播管理器类 LocalBroadcastManager,使用它来负责应用中的广播发送,就相对安全多了,实例化方式:
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
当然了,既然是管理器,那么发送和取消就自然由它负责。

动态注册 4月3日
必须程序启动后才能接受广播
动态注册的广播接收器都要取消注册
//实例化IntentFilter和MyReceiver对象
IntentFilter intentFilter = new IntentFilter();
MyReceiver myReceiver = new MyReceiver();
//为IntentFilter添加action,广播接收器才能监听到发出以下值的广播
intentFilter.addAction(“android.intent.action.ACTION_POWER_CONNECTED”);
//注册,传入广播接收器对象和IntentFilter对象
registerReceiver(myReceiver,intentFilter);
//在onDestroy里解除注册
@Override
protected void onDestroy(){
super.onDestroy();
unregisterReceiver(myReceiver);
}
静态注册
下添加新标签
Android Studio快捷创建广播接收器,右键包名->New->Other->Broadcast Receiver

<receiver android:name=".MyReceiver" //广播接收器名
android:enabled=“true” //表示是否启用此广播接收器
android:exported=“true”> //表示是否允许接收本程序以外的广播

//添加相应广播值的action

接收广播
创建广播接收器,定义一个类继承自BroadcastReceiver,并重写父类onReceive()方法,当接收到广播时,就会执行onReceive()方法
广播接收器中不允许开启线程,因为广播接收器生命周期非常短,容易对开启的线程失去控制
不要在onReceive()方法中添加过多逻辑或耗时操作
public class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//实现逻辑 } }
发送自定义广播 4月6日
1.发送标准广播
Intent intent=new Intent(“com.example.MY_BROADCAST”);
sendBroadcast(intent);
构建一个Intent对象,将要发送的广播值传入,然后调用sendBroadcast()方法,就可以将此广播发送出去
2.发送有序广播
Intent intent = new Intent(“com.example.MY_BROADCAST”);
//传入Intent对象,第二个参数与权限有关的字符串,可传入null
sendOrderedBroadcast(intent,null);
发送有序广播,广播接收器有接收顺序,优先级高的先接收到,并可以阻断其继续传播,在onReceive()方法中调用abortBroadcast()方法,截断这条广播
在AndroidManifest.xml中设置广播接收器的优先级priority
<receiver

<intent - filter android:priority=“100”>
<action …/>
</intent - filter>

使用本地广播
本地广播只在应用内部传递,使用本地广播主要使用LocalBroadcastManager对广播进行管理,并提供发送广播和注册广播接收器的方法
//调用getInstance()得到LocalBroadcastManager对象
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
//广播接收器对象和IntentFilter对象
MyReceiver myreceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
//添加action
intentFilter.addAction(“com.example.MY_BROADCAST”);
//注册本地广播监听器
localBroadCastManager.registerReceiver(myReceiver,intentFilter);
//解除注册
localBroadcastManager.unregisterReceiver(myReceiver);
发送本地广播
传入intent对象
localBroadcastManager.sendBroadcast(intent);

              Android广播总结             4月9日

1.Android广播机制概述
Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。广播作为Android组件间的通信方式,可以使用的场景如下:
1.同一app内部的同一组件内的消息通信(单个或多个线程之间);
2.同一app内部的不同组件之间的消息通信(单个进程);
3.同一app具有多个进程的不同组件之间的消息通信;
4.不同app之间的组件之间消息通信;
5.Android系统在特定情况下与App之间的消息通信。
从实现原理看上,Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型。因此,从实现的角度来看,Android中的广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。具体实现流程要点粗略概括如下:
1.广播接收者BroadcastReceiver通过Binder机制向AMS(Activity Manager Service)进行注册;
2.广播发送者通过binder机制向AMS发送广播;
3.AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中;
4.消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。
 对于不同的广播类型,以及不同的BroadcastReceiver注册方式,具体实现上会有不同。但总体流程大致如上。
由此看来,广播发送者和广播接收者分别属于观察者模式中的消息发布和订阅两端,AMS属于中间的处理中心。广播发送者和广播接收者的执行是异步的,发出去的广播不会关心有无接收者接收,也不确定接收者到底是何时才能接收到。显然,整体流程与EventBus非常类似。
在上文说列举的广播机制具体可以使用的场景中,现分析实际应用中的适用性:
第一种情形:同一app内部的同一组件内的消息通信(单个或多个线程之间),实际应用中肯定是不会用到广播机制的(虽然可以用),无论是使用扩展变量作用域、基于接口的回调还是Handler-post/Handler-Message等方式,都可以直接处理此类问题,若适用广播机制,显然有些“杀鸡牛刀”的感觉,会显太“重”;
第二种情形:同一app内部的不同组件之间的消息通信(单个进程),对于此类需求,在有些教复杂的情况下单纯的依靠基于接口的回调等方式不好处理,此时可以直接使用EventBus等,相对而言,EventBus由于是针对统一进程,用于处理此类需求非常适合,且轻松解耦。可以参见文件《Android各组件/控件间通信利器之EventBus》。
第三、四、五情形:由于涉及不同进程间的消息通信,此时根据实际业务使用广播机制会显得非常适宜。下面主要针对Android广播中的具体知识点进行总结。
 
2.BroadcastReceiver
自定义BroadcastReceiver
自定义广播接收器需要继承基类BroadcastReceivre,并实现抽象方法onReceive(context, intent)方法。广播接收器接收到相应广播后,会自动回到onReceive(…)方法。默认情况下,广播接收器也是运行在UI线程,因此,onReceive方法中不能执行太耗时的操作。否则将因此ANR。一般情况下,根据实际业务需求,onReceive方法中都会涉及到与其他组件之间的交互,如发送Notification、启动service等。
下面代码片段是一个简单的广播接收器的自定义:
public class MyBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = “MyBroadcastReceiver”;
public static int m = 1;
@Override
public void onReceive(Context context, Intent intent) {
Log.w(TAG, “intent:” + intent);
String name = intent.getStringExtra(“name”);
Log.w(TAG, “name:” + name + " m=" + m);
m++;
Bundle bundle = intent.getExtras();
}

BroadcastReceiver注册类型
BroadcastReceiver总体上可以分为两种注册类型:静态注册和动态注册。
1).静态注册:
直接在AndroidManifest.xml文件中进行注册。规则如下:
<receiver android:enabled=[“true” | “false”]
android:exported=[“true” | “false”]
android:icon=“drawable resource”
android:label=“string resource”
android:name=“string”
android:permission=“string”
android:process=“string” >
. . .

其中,需要注意的属性
android:exported  ——此broadcastReceiver能否接收其他App的发出的广播,这个属性默认值有点意思,其默认值是由receiver中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。(同样的,activity/service中的此属性默认值一样遵循此规则)同时,需要注意的是,这个值的设定是以application或者application user id为界的,而非进程为界(一个应用中可能含有多个进程);
android:name  —— 此broadcastReceiver类名;
android:permission  ——如果设置,具有相应权限的广播发送方发送的广播才能被此broadcastReceiver所接收;
android:process  ——broadcastReceiver运行所处的进程。默认为app的进程。可以指定独立的进程(Android四大基本组件都可以通过此属性指定自己的独立进程)
常见的注册形式有:

其中,intent-filter由于指定此广播接收器将用于接收特定的广播类型。本示例中给出的是用于接收网络状态改变或开启启动时系统自身所发出的广播。当此App首次启动时,系统会自动实例化MyBroadcastReceiver,并注册到系统中。
之前常说:静态注册的广播接收器即使app已经退出,主要有相应的广播发出,依然可以接收到,但此种描述自Android 3.1开始有可能不再成立,具体分析详见本文后面部分。
 
2).动态注册:
动态注册时,无须在AndroidManifest中注册组件。直接在代码中通过调用Context的registerReceiver函数,可以在程序中动态注册BroadcastReceiver。registerReceiver的定义形式如下:
1 registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
2 registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)
典型的写法示例如下:
1 public class MainActivity extends Activity {
2 public static final String BROADCAST_ACTION = “com.example.corn”;
3 private BroadcastReceiver mBroadcastReceiver;
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.activity_main);
10 mBroadcastReceiver = new MyBroadcastReceiver();
11 IntentFilter intentFilter = new IntentFilter();
12 intentFilter.addAction(BROADCAST_ACTION);
13 registerReceiver(mBroadcastReceiver, intentFilter);
14 }
16 @Override
17 protected void onDestroy() {
18 super.onDestroy();
19 unregisterReceiver(mBroadcastReceiver);
20 }
22 }
注:Android中所有与观察者模式有关的设计中,一旦涉及到register,必定在相应的时机需要unregister。因此,上例在onDestroy()回到中需要unregisterReceiver(mBroadcastReceiver)。
当此Activity实例化时,会动态将MyBroadcastReceiver注册到系统中。当此Activity销毁时,动态注册的MyBroadcastReceiver将不再接收到相应的广播。
3.广播发送及广播类型
经常说”发送广播“和”接收“,表面上看广播作为Android广播机制中的实体,实际上这一实体本身是并不是以所谓的”广播“对象存在的,而是以”意图“(Intent)去表示。定义广播的定义过程,实际就是相应广播”意图“的定义过程,然后通过广播发送者将此”意图“发送出去。被相应的BroadcastReceiver接收后将会回调onReceive()函数。
下段代码片段显示的是一个普通广播的定义过程,并发送出去。其中setAction(…)对应于BroadcastReceiver中的intentFilter中的action。
1 Intent intent = new Intent();
2 intent.setAction(BROADCAST_ACTION);
3 intent.putExtra(“name”, “qqyumidi”);
4 sendBroadcast(intent);
根据广播的发送方式,可以将其分为以下几种类型:
1.Normal Broadcast:普通广播
2.System Broadcast: 系统广播
3.Ordered broadcast:有序广播
4.Sticky Broadcast:粘性广播(在 android 5.0/api 21中deprecated,不再推荐使用,相应的还有粘性有序广播,同样已经deprecated)
5.Local Broadcast:App应用内广播
下面分别总结下各种类型的发送方式及其特点。
1).Normal Broadcast:普通广播
此处将普通广播界定为:开发者自己定义的intent,以context.sendBroadcast_“AsUser”(intent, …)形式。具体可以使用的方法有:
sendBroadcast(intent)/sendBroadcast(intent, receiverPermission)/sendBroadcastAsUser(intent, userHandler)/sendBroadcastAsUser(intent, userHandler,receiverPermission)。
普通广播会被注册了的相应的感兴趣(intent-filter匹配)接收,且顺序是无序的。如果发送广播时有相应的权限要求,BroadCastReceiver如果想要接收此广播,也需要有相应的权限。
2).System Broadcast: 系统广播
Android系统中内置了多个系统广播,只要涉及到手机的基本操作,基本上都会发出相应的系统广播。如:开启启动,网络状态改变,拍照,屏幕关闭与开启,点亮不足等等。每个系统广播都具有特定的intent-filter,其中主要包括具体的action,系统广播发出后,将被相应的BroadcastReceiver接收。系统广播在系统内部当特定事件发生时,有系统自动发出。
3)Ordered broadcast:有序广播
有序广播的有序广播中的“有序”是针对广播接收者而言的,指的是发送出去的广播被BroadcastReceiver按照先后循序接收。有序广播的定义过程与普通广播无异,只是其的主要发送方式变为:sendOrderedBroadcast(intent, receiverPermission, …)。
对于有序广播,其主要特点总结如下:
1>多个具当前已经注册且有效的BroadcastReceiver接收有序广播时,是按照先后顺序接收的,先后顺序判定标准遵循为:将当前系统中所有有效的动态注册和静态注册的BroadcastReceiver按照priority属性值从大到小排序,对于具有相同的priority的动态广播和静态广播,动态广播会排在前面。
2>先接收的BroadcastReceiver可以对此有序广播进行截断,使后面的BroadcastReceiver不再接收到此广播,也可以对广播进行修改,使后面的BroadcastReceiver接收到广播后解析得到错误的参数值。当然,一般情况下,不建议对有序广播进行此类操作,尤其是针对系统中的有序广播。
4)Sticky Broadcast:粘性广播(在 android 5.0/api 21中deprecated,不再推荐使用,相应的还有粘性有序广播,同样已经deprecated)。
既然已经deprecated,此处不再多做总结。
5)Local Broadcast:App应用内广播(此处的App应用以App应用进程为界)
由前文阐述可知,Android中的广播可以跨进程甚至跨App直接通信,且注册是exported对于有intent-filter的情况下默认值是true,由此将可能出现安全隐患如下:
1.其他App可能会针对性的发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收到广播并处理;
2.其他App可以注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。
无论哪种情形,这些安全隐患都确实是存在的。由此,最常见的增加安全性的方案是:
1.对于同一App内部发送和接收广播,将exported属性人为设置成false,使得非本App内部发出的此广播不被接收;
2.在广播发送和接收时,都增加上相应的permission,用于权限验证;
3.发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定在,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。
App应用内广播可以理解成一种局部广播的形式,广播的发送者和接收者都同属于一个App。实际的业务需求中,App应用内广播确实可能需要用到。同时,之所以使用应用内广播时,而不是使用全局广播的形式,更多的考虑到的是Android广播机制中的安全性问题。
相比于全局广播,App应用内广播优势体现在:
1.安全性更高;
2.更加高效。
为此,Android v4兼容包中给出了封装好的LocalBroadcastManager类,用于统一处理App应用内的广播问题,使用方式上与通常的全局广播几乎相同,只是注册/取消注册广播接收器和发送广播时将主调context变成了LocalBroadcastManager的单一实例。
代码片段如下:
1 //registerReceiver(mBroadcastReceiver, intentFilter);
2 //注册应用内广播接收器
3 localBroadcastManager = LocalBroadcastManager.getInstance(this);
4 localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
6 //unregisterReceiver(mBroadcastReceiver);
7 //取消注册应用内广播接收器
8 localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
10 Intent intent = new Intent();
11 intent.setAction(BROADCAST_ACTION);
12 intent.putExtra(“name”, “qqyumidi”);
13 //sendBroadcast(intent);
14 //发送应用内广播
15 localBroadcastManager.sendBroadcast(intent);
 
4.不同注册方式的广播接收器回调onReceive(context, intent)中的context具体类型
1).对于静态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是ReceiverRestrictedContext;
2).对于全局广播的动态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是Activity Context;
3).对于通过LocalBroadcastManager动态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是Application Context。
注:对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册的ContextReceiver才有可能接收到(静态注册或其他方式动态注册的ContextReceiver是接收不到的)。
 
5.不同Android API版本中广播机制相关API重要变迁
1).Android5.0/API level 21开始粘滞广播和有序粘滞广播过期,以后不再建议使用;
2).”静态注册的广播接收器即使app已经退出,主要有相应的广播发出,依然可以接收到,但此种描述自Android 3.1开始有可能不再成立“
Android 3.1开始系统在Intent与广播相关的flag增加了参数,分别是FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES。
FLAG_INCLUDE_STOPPED_PACKAGES:包含已经停止的包(停止:即包所在的进程已经退出)
FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已经停止的包
主要原因如下:
自Android3.1开始,系统本身则增加了对所有app当前是否处于运行状态的跟踪。在发送广播时,不管是什么广播类型,系统默认直接增加了值为FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播。
详情参加Android官方文档:http://developer.android.com/about/versions/android-3.1.html#launchcontrols
由此,对于系统广播,由于是系统内部直接发出,无法更改此intent flag值,因此,3.1开始对于静态注册的接收系统广播的BroadcastReceiver,如果App进程已经退出,将不能接收到广播。
但是对于自定义的广播,可以通过复写此flag为FLAG_INCLUDE_STOPPED_PACKAGES,使得静态注册的BroadcastReceiver,即使所在App进程已经退出,也能能接收到广播,并会启动应用进程,但此时的BroadcastReceiver是重新新建的。
1 Intent intent = new Intent();
2 intent.setAction(BROADCAST_ACTION);
3 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
4 intent.putExtra(“name”, “qqyumidi”);
5 sendBroadcast(intent);
注1:对于动态注册类型的BroadcastReceiver,由于此注册和取消注册实在其他组件(如Activity)中进行,因此,不受此改变影响。
SQLite 4月10日
一.SQLite的介绍
1.SQLite简介
SQLite是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入  式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持 Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如Tcl、PHP、Java、C++、.Net等,还有ODBC接口,同样比起 Mysql、PostgreSQL这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。

2.SQLite的特点:
轻量级
SQLite和C/S模式的数据库软件不同,它是进程内的数据库引擎,因此不存在数据库的客户端和服务器。使用SQLite一般只需要带上它的一个动态  库,就可以享受它的全部功能。而且那个动态库的尺寸也挺小,以版本3.6.11为例,Windows下487KB、Linux下347KB。
不需要"安装"
SQLite的核心引擎本身不依赖第三方的软件,使用它也不需要"安装"。有点类似那种绿色软件。
单一文件  
数据库中所有的信息(比如表、视图等)都包含在一个文件内。这个文件可以自由复制到其它目录或其它机器上。
跨平台/可移植性
除了主流操作系统 windows,linux之后,SQLite还支持其它一些不常用的操作系统。
弱类型的字段
同一列中的数据可以是不同类型
开源
这个相信大家都懂的!!!!!!!!!!!!
3.SQLite数据类型
一般数据采用的固定的静态数据类型,而SQLite采用的是动态数据类型,会根据存入值自动判断。SQLite具有以下五种常用的数据类型:
NULL: 这个值为空值
VARCHAR(n):长度不固定且其最大长度为 n 的字串,n不能超过 4000。
CHAR(n):长度固定为n的字串,n不能超过 254。
INTEGER: 值被标识为整数,依据值的大小可以依次被存储为1,2,3,4,5,6,7,8.
REAL: 所有值都是浮动的数值,被存储为8字节的IEEE浮动标记序号.
TEXT: 值为文本字符串,使用数据库编码存储(TUTF-8, UTF-16BE or UTF-16-LE).
BLOB: 值是BLOB数据块,以输入的数据格式进行存储。如何输入就如何存储,不改  变格式。
DATA :包含了 年份、月份、日期。
TIME: 包含了 小时、分钟、秒。
相信学过数据库的童鞋对这些数据类型都不陌生的!!!
二.SQLiteDatabase的介绍
Android提供了创建和是用SQLite数据库的API。SQLiteDatabase代表一个数据库对象,提供了操作数据库的一些方法。在Android的SDK目录下有sqlite3工具,我们可以利用它创建数据库、创建表和执行一些SQL语句。下面是SQLiteDatabase的常用方法。 
SQLiteDatabase的常用方法 
方法名称
方法表示含义

openOrCreateDatabase(String path,SQLiteDatabase.CursorFactory  factory)
打开或创建数据库

insert(String table,String nullColumnHack,ContentValues  values)
插入一条记录

delete(String table,String whereClause,String[]  whereArgs)
删除一条记录

query(String table,String[] columns,String selection,String[]  selectionArgs,String groupBy,String having,String  orderBy)
查询一条记录

update(String table,ContentValues values,String whereClause,String[]  whereArgs)
修改记录

execSQL(String sql)
执行一条SQL语句

close()
关闭数据库

Google公司命名这些方法的名称都是非常形象的。例如openOrCreateDatabase,我们从字面英文含义就能看出这是个打开或创建数据库的方法。
1、打开或者创建数据库
在Android 中使用SQLiteDatabase的静态方法openOrCreateDatabase(String  path,SQLiteDatabae.CursorFactory  factory)打开或者创建一个数据库。它会自动去检测是否存在这个数据库,如果存在则打开,不存在则创建一个数据库;创建成功则返回一个SQLiteDatabase对象,否则抛出异常FileNotFoundException。
下面是创建名为“stu.db”数据库的代码:
openOrCreateDatabase(String  path,SQLiteDatabae.CursorFactory  factory)
参数1  数据库创建的路径
参数2  一般设置为null就可以了
1

db=SQLiteDatabase.openOrCreateDatabase("/data/data/com.lingdududu.db/databases/stu.db",null);

2、创建表
创建一张表的步骤很简单:
编写创建表的SQL语句
调用SQLiteDatabase的execSQL()方法来执行SQL语句
下面的代码创建了一张用户表,属性列为:id(主键并且自动增加)、sname(学生姓名)、snumber(学号)
1
2
3
4
5
6
private void createTable(SQLiteDatabase db){
//创建表SQL语句
String stu_table=“create table usertable(_id integer primary key autoincrement,sname text,snumber text)”;
//执行SQL语句
db.execSQL(stu_table);
}

3、插入数据
插入数据有两种方法:
①SQLiteDatabase的insert(String table,String nullColumnHack,ContentValues  values)方法,
  参数1  表名称,
  参数2  空列的默认值
  参数3  ContentValues类型的一个封装了列名称和列值的Map;
②编写插入数据的SQL语句,直接调用SQLiteDatabase的execSQL()方法来执行
第一种方法的代码:
1
2
3
4
5
6
7
8
9
10
private void insert(SQLiteDatabase db){
//实例化常量值
ContentValues cValue = new ContentValues();
//添加用户名
cValue.put(“sname”,“xiaoming”);
//添加密码
cValue.put(“snumber”,“01005”);
//调用insert()方法插入数据
db.insert(“stu_table”,null,cValue);
}

第二种方法的代码:
1
2
3
4
5
6
private void insert(SQLiteDatabase db){
//插入数据SQL语句
String stu_sql=“insert into stu_table(sname,snumber) values(‘xiaoming’,‘01005’)”;
//执行SQL语句
db.execSQL(sql);
}

4、删除数据
删除数据也有两种方法:
①调用SQLiteDatabase的delete(String table,String whereClause,String[]  whereArgs)方法
参数1  表名称 
参数2  删除条件
参数3  删除条件值数组
②编写删除SQL语句,调用SQLiteDatabase的execSQL()方法来执行删除。
第一种方法的代码:
1
2
3
4
5
6
7
8
private void delete(SQLiteDatabase db) {
//删除条件
String whereClause = “id=?”;
//删除条件参数
String[] whereArgs = {String.valueOf(2)};
//执行删除
db.delete(“stu_table”,whereClause,whereArgs);
}

第二种方法的代码:
1
2
3
4
5
6
private void delete(SQLiteDatabase db) {  
//删除SQL语句  
String sql = “delete from stu_table where _id = 6”;  
//执行SQL语句  
db.execSQL(sql);  
}

5、修改数据
修改数据有两种方法:
①调用SQLiteDatabase的update(String table,ContentValues values,String  whereClause, String[]  whereArgs)方法
参数1  表名称
参数2  跟行列ContentValues类型的键值对Key-Value
参数3  更新条件(where字句)
参数4  更新条件数组
②编写更新的SQL语句,调用SQLiteDatabase的execSQL执行更新。
第一种方法的代码:
1
2
3
4
5
6
7
8
9
10
11
private void update(SQLiteDatabase db) {  
//实例化内容值 ContentValues values = new ContentValues();  
//在values中添加内容  
values.put(“snumber”,“101003”);  
//修改条件  
String whereClause = “id=?”;  
//修改添加参数  
String[] whereArgs={String.valuesOf(1)};  
//修改  
db.update(“usertable”,values,whereClause,whereArgs);  
}

第二种方法的代码:
1
2
3
4
5
6
private void update(SQLiteDatabase db){  
//修改SQL语句  
String sql = “update stu_table set snumber = 654321 where id = 1”;  
//执行SQL  
db.execSQL(sql);  
}

6、查询数据
在Android中查询数据是通过Cursor类来实现的,当我们使用SQLiteDatabase.query()方法时,会得到一个Cursor对象,Cursor指向的就是每一条数据。它提供了很多有关查询的方法,具体方法如下:
public  Cursor query(String table,String[] columns,String selection,String[]  selectionArgs,String groupBy,String having,String orderBy,String limit);
各个参数的意义说明:
参数table:表名称
参数columns:列名称数
参数selection:条件字句,相当于where
参数selectionArgs:条件字句,参数数组
参数groupBy:分组列
参数having:分组条件
参数orderBy:排序列
参数limit:分页查询限制
参数Cursor:返回值,相当于结果集ResultSet
Cursor是一个游标接口,提供了遍历查询结果的方法,如移动指针方法move(),获得列值方法getString()等.
Cursor游标常用方法
方法名称
方法描述

getCount()
获得总的数据项数

isFirst()
判断是否第一条记录

isLast()
判断是否最后一条记录

moveToFirst()
移动到第一条记录

moveToLast()
移动到最后一条记录

move(int offset)
移动到指定记录

moveToNext()
移动到下一条记录

moveToPrevious()
移动到上一条记录

getColumnIndexOrThrow(String  columnName)
根据列名称获得列索引

getInt(int columnIndex)
获得指定列索引的int类型值

getString(int columnIndex)
获得指定列缩影的String类型值

三. SQLiteOpenHelper
该类是SQLiteDatabase一个辅助类。这个类主要生成一  个数据库,并对数据库的版本进行管理。当在程序当中调用这个类的方法getWritableDatabase()或者 getReadableDatabase()方法的时候,如果当时没有数据,那么Android系统就会自动生成一个数据库。 SQLiteOpenHelper 是一个抽象类,我们通常需要继承它,并且实现里面的3个函数:
1.onCreate(SQLiteDatabase)
在数据库第一次生成的时候会调用这个方法,也就是说,只有在创建数据库的时候才会调用,当然也有一些其它的情况,一般我们在这个方法里边生成数据库表。
2.  onUpgrade(SQLiteDatabase,int,int) 
当数据库需要升级的时候,Android系统会主动的调用这个方法。一般我们在这个方法里边删除数据表,并建立新的数据表,当然是否还需要做其他的操作,完全取决于应用的需求。
3.  onOpen(SQLiteDatabase):
这是当打开数据库时的回调函数,一般在程序中不是很常使用。
写了这么多,改用用实际例子来说明上面的内容了。下面这个操作数据库的实例实现了创建数据库,创建表以及数据库的增删改查的操作。
该实例有两个类:
com.lingdududu.testSQLite 调试类
com.lingdududu.testSQLiteDb  数据库辅助类
使用adb命令查看数据库:
1.在命令行窗口输入adb  shell回车,就进入了Linux命令行,现在就可以使用Linux的命令了。
2.ls回车,显示所有的东西,其中有个data。
3.cd data回车,再ls回车,cd  data回车,ls回车后就会看到很多的com…,那就是系统上的应用程序包名,找到你数据库程序的包名,然后进入。
4.进去后在查看所有,会看到有databases,进入databases,显示所有就会发现你的数据库名字,这里使用的是"stu_db"。
5.sqlite3 stu_db回车就进入了你的数据库了,然后“.schema”就会看到该应用程序的所有表及建表语句。
6.之后就可以使用标准的SQL语句查看刚才生成的数据库及对数据执行增删改查了。
注:ls,cd等命令都是linux的基本命令,不了解的同学可以看看有关这方面的资料。
下面介绍几个在SQLite中常用到的adb命令:
查看
.database 显示数据库信息;
.tables 显示表名称;
.schema 命令可以查看创建数据表时的SQL命令;
.schema table_name 查看创建表table_name时的SQL的命令;
插入记录
insert into table_name values (field1, field2, field3…);
查询
select * from table_name;查看table_name表中所有记录;
select * from table_name where field1=‘xxxxx’; 查询符合指定条件的记录;
删除
drop table_name;     删除表;
drop index_name;     删除索引;

Android活动,控件,碎片,广播,数据库小总结相关推荐

  1. android单选控件spinner与数据库结合综合实例

    本示例说明: 1.实现单选按钮与后台数据绑定,通过Id绑定. 2.实现显示时默认选中项控制. 3.实现修改后保存,根据id保存. 4.数据库处理使用AHibernate1.1,详见: http://b ...

  2. Android 开源控件与常用开发框架开发工具类

    Android的加载动画AVLoadingIndicatorView 项目地址: https://github.com/81813780/AVLoadingIndicatorView 首先,在 bui ...

  3. Android神奇“控件”-----RemoteViews

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 转载请注明 http://blog.csdn.net/wrg_20100512/article/details/53940485 好 ...

  4. Android开源控件收集整理

    一 .基本控件 TextView HTextView 一款支持TextView文字动画效果的Android组件库.GitHub - hanks-zyh/HTextView: Animation eff ...

  5. Android开源控件ViewPager Indicator的使用方法

     1月16日厦门 OSC 源创会火热报名中,奖品多多哦   摘要 Android开源控件ViewPager Indicator的使用介绍 ViewPagerIndicator 目录[-] 1. V ...

  6. xamarin.android 控件,Android 库控件 - Xamarin | Microsoft Docs

    Xamarin Android 库控件Xamarin.Android Gallery control 03/15/2018 本文内容 Gallery是一种布局小组件,用于显示水平滚动列表中的项,并将当 ...

  7. android控件使用大全,Android常见控件使用详解

    本文实例为大家分享了六种Android常见控件的使用方法,供大家参考,具体内容如下 1.TextView 主要用于界面上显示一段文本信息 2.Button 用于和用户交互的一个按钮控件 //为Butt ...

  8. Android学习--02(猜猜我的星座App源码+Android常用控件TextView+EditText+Button+ImangeView+DatePicker+App间通信+跳转页面)

    猜猜我的星座App 1 Android常用控件 1.1 TextView控件 1.1.1 简介 1.1.2属性 1.1.3 扩展属性 1.1.4 TextView的使用方法 1.1.5总结 1.2 E ...

  9. Android 原生控件之三 ProgressBar

    Android 原生控件之三 ProgressBar 相关 来源 开始 不确定的进度 确定的进度 XML属性 1.android:animationResolution 2.android:indet ...

  10. Android学习|控件——Notification通知

    Android学习|控件--Notification通知 一.前提 二.两个对象的的构建 1.创建NotificationManager 2.使用Builder构造器来创建Notification 2 ...

最新文章

  1. 客快物流大数据项目(十七):自定义镜像mycentos
  2. Laravel 中简约而不简单的 Macroable 宏指令
  3. 关系型数据库的超键、候选键、主键
  4. python 多线程读写文件错误_python多线程老是报错。大神帮忙看看哈?
  5. 用 scipy.weave 嵌入 C 语言
  6. mssql sqlserver 优化注意事项:
  7. iMazing与iTunes 两款iOS设备管理器区别 在备份操作上的对比
  8. 强化学习 马尔可夫决策过程(MDP)是什么
  9. 算法:Design Circular Deque(设计一个双端队列)
  10. 利用XML文件的一个写日志的类!!!!!
  11. 2018年信息安全大事件一览
  12. 一条查询SQL的执行流程
  13. HTTP协议的工作原理
  14. fabpot php cs fixer,使用 PHP-CS-Fixer 自动规范化你的 PHP 代码
  15. Ubuntu18.04配置ORB SLAM3
  16. 微信小程序实战十三:狗狗小程序云搭建
  17. PHP常用正则表达式,如验证网址,邮箱等
  18. 专访STEM领域人才资深人工智能图像算法工程师张旦
  19. R语言|forest plot
  20. Excel 上传和下载

热门文章

  1. use tptp to monitor java application performance (1)
  2. android焦点切换,android – 使用FLAG_ACTIVITY_REORDER_TO_FRONT在持续运行的UI活动之间切换会导致“无窗口焦点”错误...
  3. c语言编译预处理指令大全,C语言预处理指令
  4. LCD工控液晶触摸屏贴合如何进行贴合工程?
  5. Xming X Server 配置和使用
  6. 苹果在更新了ios13.4.1后,sim卡更新后,联通4G变得非常非常的慢
  7. Resilient Distributed Datasets (RDD)
  8. python中isnumeric的意思,Python isnumeric()方法
  9. java实现代码在线编译器-从零开发(二)简单SpringBoot网络接口demo
  10. vue-router和location.href的用法区别是什么?