http://bbs.csdn.net/forums/Android CSDN 安卓论坛
http://www.3g-edu.org/courses/content.htm 安卓学习路线
http://blog.csdn.net/freemindhack/article/details/27109477
http://blog.csdn.net/freemindhack/article/details/27404417 安卓学习步骤
http://blog.csdn.net/happiness365/article/details/50451350 安卓大牛博客
http://www.cnblogs.com/zoupeiyang/p/4034517.html 安卓开发环境搭建
http://jobs.zhaopin.com/357186919250355.htm 安卓工作
http://jingyan.baidu.com/article/cb5d6105f1c1a9005c2fe084.html 安装2.2.2
http://blog.csdn.net/u011303443/article/details/51524439 http://blog.csdn.net/b2259909/article/details/50786597
http://blog.csdn.net/eebbhhn/article/details/52776648 http://www.tuicool.com/articles/AVjAva 安装注意事项
http://www.cnblogs.com/Kennytian/p/4449878.html 解决 Android Studio 乱码问题 http://blog.csdn.net/u010302764/article/details/42889731 http://jingyan.baidu.com/article/91f5db1b34d1871c7f05e3df.html
http://www.cnblogs.com/dongdong230/p/4184097.html studio创建项目
http://blog.csdn.net/eyu8874521/article/details/9125987 android webservice http://kb.cnblogs.com/page/98804/
http://blog.csdn.net/rankun1/article/details/52556162
http://blog.csdn.net/zml_2015/article/details/50626260/
http://blog.sina.com.cn/s/blog_b0f182290102v9ck.html http://www.cnblogs.com/hubcarl/p/4030884.html
===========================================
自己学习的知识总结:
创建 HelloWorld项目:
Application name : HelloWorld ,如果安装到手机上,在手机上显示此名称
域名:example.com
package name : 根据这个包名 区分不同的应用程序。
project location:项目代码存放的路径
创建空活动:Empty Activity 名字叫做 HelloWorldActivity
Layout Name:表示布局的名字:hello_world_layout
启动模拟器运行程序:create virtual device
app就是当前的主项目
分析你的上面第一个Android程序:
基于 Android模式的项目结构: 注意:可以切换到project模式结构
app:项目中的代码、资源等都放在这个目录下面,
build:不需要关心,
gradle:
.gitignore: 版本控制
其他内容略。
关注app目录:
libs:存放你用到的第三方jar包。
AndroidTest:编写test测试用例的,可以对项目进行自动化测试。
Java:存放Java代码的目录。
res: 该目录是存放 图片 布局 字符串等资源的。
AndroidManifest.xml:是整个Android项目的配置文件,程序中的4大组件都需要在这个文件里注册,
test: 用来编写测试用例的。
其他文件略.
分析HelloWorld项目是如何运行起来的:
首先打开:AndroidManifest.xml ,
<activity android:name=".HelloWorldActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
这段代码表示:对HelloWorldActivity活动进行注册,才可使用,intent-filter里面的2行代码
表示HelloWorldActivity活动是项目的主活动。在手机中点击应用图标,首先启动的就是这个活动。
活动是Android应用程序的门面,你在应用中看到的东东,都是放在活动中的。
查看HelloWorldActivity活动的代码:
public class HelloWorldActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.hello_world_layout ) ;
}
}
onCreate()方法是一个活动创建后必定要执行的方法。
Android程序讲究 逻辑和视图的分离。不在活动中编写界面,而是在布局文件中编写界面,然后再活动中引入进来(引入布局,需要调用setContentView()方法, )。布局文件都在res/layout 目录下,我们打开刚创建的布局文件 hello_world_layout.xml,看其中的代码:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hello world ! "
/>
</RelativeLayout>
TextView是文本控件,android:text="hello world ! " 是显示文字的。
res资源目录:
drawable开头的文件夹是用来存放图片的,
mipmap是用来存放应用图标的,
values开头的目录是用来存放 字符串、样式、颜色的,
layout目录是用来存放 布局文件 的。
定义了资源,接下来就可以使用资源了,打开res/values/strings.xml文件,内容如下:
<resources>
<string name="app_name"> HelloWorld </string>
</resources>
以上代码定义了一个应用程序名称的字符串,我们可以利用以下2种方式引用它:
在代码中引用:R.string.hello_world
在xml中引用:@/string/hello_world
( string 是可以被替换的)
例如:
打开:AndroidManifest.xml ,
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher" //指定了应用程序的图标
android:label="@string/app_name"
>
</application>
build.gradle 文件:
掌握日志工具使用:Log
它提供了5种级别的打印日志:Log.v() Log.d()
public class HelloWorldActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.hello_world_layout ) ;
Log.d( "HelloWorldActivity" , "onCreate execute " ) ;
}
}
--------------------------------------------------------------------------
探究 活动:
活动Activity是一种可以包含用户界面的组件,主要 用于和用户进行交互。
(一个活动最好对应一个布局)
活动的基本用法:
新建一个Activity项目,例如:ActivityTest ,选择 Add no Activity ,(手动创建活动)
在 app/src/main/java/默认域名/ 为空了,右击新建空活动,名称FirstActivity,并且不要
勾选 generate layout file 和 launcher Activity(变成主活动了) 这2项,勾选backwards
compatibility启用向下兼容,点击finish。
右击 app/src/main/res 新建目录 layout,右击新建布局文件 first_layout ,其他默认。
<LinearLayout>
......................
...........................
//进入布局元素,添加按钮 和属性,
<Button
android:id ="@+id/button_1" //定义算术的标识符,+去掉表示引用
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 1 "
</LinearLayout>
可以浏览布局了。R文件自动生成资源的id。
在FirstActivity活动中引入布局:
public class FirstActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.first_layout ) ; //加载了新的布局
}
}
所有的活动在 AndroidManifest.xml 中注册才能生效,做法:
在 <application>标签内,添加 <activity>标签进行注册,代码是:
<activity Android:name=".FirstActivity"> </activity>
把这个活动变成主活动:
<activity android:name=".FirstActivity"
android:label="this is FirstActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
在活动中 使用 Toast ,在程序中使用它将一些短小的信息通知给用户,而信息会在很短的时间
内消失,不占用屏幕。
利用按钮弹出一个 定义的Toast 的 触发点,
public class FirstActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.first_layout ) ; //加载了新的布局
Button button1 = ( Button ) findViewById( R.id.button_1 );
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Toast.makeText( FirstActivity.this , "you click Button 1",
Toast.LENGTH_SHORT).show();
}
} ) ;
}
在活动中使用 Menu :
在 res 目录下新建 menu 文件夹,在在其中建立一个 main的菜单文件(类型是 menu resource
file ),在main.xml中添加如下代码:
<menu xmlns:android:="" >
<item
android:id = "@+id/add_item"
android:title = "Add" />
<item
android:id = "@+id/remove_item"
android:title = "Remove" />
</>
public class FirstActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.first_layout ) ; //加载了新的布局
Button button1 = ( Button ) findViewById( R.id.button_1 );
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Toast.makeText( FirstActivity.this , "you click Button 1",
Toast.LENGTH_SHORT).show();
}
} ) ;
// 重写方法:
public boolean onCreateOptionsMenu( Menu menu ) {
getMenuInflater().inflate( R.menu.main , menu );
return true; //显示菜单了
}
// 重写方法 添加菜单响应事件:
public boolean onOptionsItemSelected( MenuItem item ) {
switch ( item.getItemId( ) ) { //判断我们点击的是哪个菜单项
case R.id.add_item:
Toast.makeText( this, "you clicked Add"
,Toast.LENGTH_SHORT).show() ; break;
case R.id.remove_item:
Toast.makeText( this, "you clicked Remove"
,Toast.LENGTH_SHORT).show() ; break;
default:
}
return true; //菜单响应了
}
}
如何销毁一个活动:
修改按钮监听器中的代码:
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
finish();//等价于按下 back键,实现销毁活动。
}
} ) ;
使用 Intent 在活动之间 穿梭:
在 ActivityTest 项目中再创建一个活动:SecondActivity , 并勾选 generate layout file , 布局文
件为 second_layout , 但是不要勾选 launcher activity 选项,
开始编辑 second_layout.xml :
<LinearLayout>
......................
...........................
//进入布局元素,添加按钮 和属性,
<Button
android:id ="@+id/button_2" //定义算术的标识符,+去掉表示引用
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 2 "
</LinearLayout>
在SecondActivity活动中引入布局:
public class SecondActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.second_layout ) ; //加载了新的布局
}
}
所有的活动在 AndroidManifest.xml 中注册才能生效,做法:
在 <application>标签内,添加 <activity>标签进行注册,代码是:
<activity Android:name=".FirstActivity"> </activity>
把这个活动变成主活动:
<activity android:name=".FirstActivity"
android:label="this is FirstActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"></activity> //系统自动生成了
如何启动这个 第二个活动:由 Intent启动活动。
显示的Intent:
修改 FirstActivity 中按钮的点击事件:
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Intent intent = new Intent(FirstActivity.this , SecondActivity.class )
//活动之间的跳转。
startActivity( intent );
}
} ) ;
隐式的Intent:由系统启动合适的活动。
在 AndroidManifest.xml 中修改代码:
<activity android:name=".FirstActivity"
android:label="this is FirstActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"> //系统自动生成了
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
在第一个活动中启动第二个活动:
修改 FirstActivity 中按钮的点击事件:
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Intent intent = new Intent("com.example.activitytest.ACTION_START" )
//活动之间的跳转。
startActivity( intent );
}
} ) ;
每个Intent只能指定一个活动,但却可以指定多个category,默认只有一个,可以增加新的
。
修改 FirstActivity 中按钮的点击事件:
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Intent intent = new Intent("com.example.activitytest.ACTION_START" )
intent.addCategory( "com.example.activitytest.MY_CATEGORY" );
startActivity( intent );
}
} ) ;
一旦你运行程序,程序就崩溃了,分析错误日志。
此时在第二个活动中继续添加代码:
<activity android:name=".SecondActivity"> //系统自动生成了
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.activitytest.MY_CATEGORY" />
</intent-filter>
</activity>
OK,程序可以正常运行了。
更多的 隐式的Intent 用法。暂时略去。
向下一个活动传递数据:
例如:第一个活动中有字符串 给第二个活动:
修改 FirstActivity 中按钮的点击事件:
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
String data = "Hello SecondActivity.";
Intent intent = new Intent("FirstActivity.this , SecondActivity.class" )
intent.putExtra( "extra_data" , data ); //准备好要传送的data
startActivity( intent );
}
} ) ;
第二个活动取出数据:
public class SecondActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.second_layout ) ; //加载了新的布局
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity", data );
}
}
返回数据给上一个活动:
当我们希望销毁活动 返回一个结果给上一个活动,可以调用startActivityForResult()
修改 FirstActivity 中按钮的点击事件:
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Intent intent = new Intent("FirstActivity.this , SecondActivity.class" )
startActivityForResult( intent , 1 ); //也是启动第二个活动,逻辑值1
}
} ) ;
在第二个活动中添加按钮注册事件:
public class SecondActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.second_layout ) ; //加载了新的布局
Button button2 = ( Button ) findViewById( R.id.button_2 );
button2.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Intent intent = new Intent();
intent.putExtra( "data_return" , "hello FirstActivity" );
setResult( RESULT_OK, intent ); //向上一个活动返回数据
finish();
}
} ) ;
}
}
此时,系统会回调第一个活动的 方法,下面进行重写:
修改 FirstActivity
protected void onActivityResult( int requestCode , int resultCode , Intent data ){
switch( requestCode ){
case 1:
if(resultCode == RESULT_OK )
{ String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity", returnedData);
}
break;
default:
}
}
在SecondActivity中不通过单击按钮,而是通过按下back键回到FirstActivity ,处理的方式是
:
在SecondActivity中重写方法:
public void onBackPressed(){
Intent intent = new Intent();
intent.putExtra( "data_return" , "hello FirstActivity" );
setResult( RESULT_OK, intent ); //向上一个活动返回数据
finish();
}
活动的生命周期:
活动的结构:就是栈——返回栈(组成了任务来管理活动的)
活动状态:
运行状态: 位于栈顶的活动,
暂停状态:不在栈顶的活动,依然可见,完全存活着。
停止状态:不在栈顶,且完全不可见的 活动。
销毁状态:一个活动从返回栈中移除后,系统回收这种状态,保证手机的内存充足。
活动的生存期:定义了7个方法覆盖了活动的生命周期。
onCreate():活动被第一次创建的时候调用。
onStart():活动从不可见到可见时被调用。
onResume():活动位于栈顶,运行状态,在活动准备好和用户交互的时候被调用。
onPause(): 系统准备去启动 或者 回复另一个活动的时候被调用。
onStop(): 在活动完全不可见的时候被调用。
onDestroy(): 在活动被销毁之前调用。
onRestart():活动被重新启动。
开始体验 活动的生命周期:
新建项目:ActivityLifeCycleTest , 允许自动创建和布局,勾选launcher activity 设置为主活
动,再创建2个子活动:NormalActivity normal_layout , DialogActivity dialog_layout。
第66页。
开始编辑 normal_layout.xml文件:
<LinearLayout>
......................
...........................
//进入布局元素,添加按钮 和属性,
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="this is a normal activity " />
</LinearLayout>
开始编辑 dialog_layout.xml文件:
<LinearLayout>
......................
...........................
//进入布局元素,添加按钮 和属性,
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="this is a dialog activity " />
</LinearLayout>
在 AndroidManifest.xml 中修改代码<activity>:
<activity android:name=".NormalActivity" >
</activity>
<activity android:name=". DialogActivity"
android:theme = "@android:style/Theme.Dialog" > //给当前活动指定主题
</activity>
接下来 修改 activity_main.xml ,重新定制主活动的布局,代码如下:
<LinearLayout>
......................
...........................
//进入布局元素,添加按钮 和属性,
<Button
android:id ="@+id/start_normal_activity" //定义算术的标识符,+去掉表示引用
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start NormalActivity " />
<Button
android:id ="@+id/start_dialog_activity" //定义算术的标识符,+去掉表示引用
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start DialogActivity " />
</LinearLayout>
接着修改 MainActivity 中的代码:
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainActivity";
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.activity_main ) ; //加载了新的布局
Button startNormalActivity = ( Button ) findViewById( R.id.start_normal_activity );
Button startDialogActivity = ( Button ) findViewById( R.id.start_dialog_activity );
startNormalActivity.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Intent intent = new Intent(MainActivity.this , NormalActivity.class )
startActivity( intent ); //
}
} ) ;
startDialogActivity.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Intent intent = new Intent(MainActivity.this , DialogActivity.class )
startActivity( intent ); //
}
} ) ;
protected void onStart() {
super.onStart();
Log.d( TAG , "onStart"); //显示菜单了
}
protected void onResume() {
super.onResume();
Log.d( TAG , "onResume"); //显示菜单了
}
protected void onPause() {
super.onPause();
Log.d( TAG , "onPause"); //显示菜单了
}
protected void onStop() {
super.onStop();
Log.d( TAG , "onStop"); //显示菜单了
}
protected void onDestroy() {
super.onDestroy();
Log.d( TAG , "onDestroy"); //显示菜单了
}
protected void onRestart() {
super.onRestart();
Log.d( TAG , "onRestart"); //显示菜单了
}
}
-------------------------------------------------------复制到此;
活动被回收了怎么办?72
假设 MainActivity 中有文本框里面有信息数据,此时启动了 NormalActivity ,MainActivity活
动进入停止状态,很可能被收回了,当你再次返回到 MainActivity 活动,MainActivity会被再
次创建, 而 之前的临时数据没有了。解决的办法是:
MainActivity修改以下代码:
protected void onSaveInstanceState (Bundle outState){
// 活动被收回前 ,该方法被调用,保存临时数据
super.onSaveInstanceState ( outState);
String tempData = "something you just typed";
outState.putString("data_key", tempData );
}
MainActivity修改以下代码:
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
Log.d( TAG , "onCreate");
setContentView( R.layout.activity_main ) ; //加载了新的布局
if( savedInstanceState != null )
{
String tempData = savedInstanceState.getString("data_key");
Log.d( TAG , tempData ); //可以重新赋值,恢复数据
}
活动的启动模式: 73
共四种:standard(默认的):启动活动就入栈,可以重复启动,重复入栈。back返回N此。
singleTop :如果当前活动已经在栈顶了,就不再创建该活动的新实例了。可以直接使用
singleTask
singleInstance
可以在 AndroidManifest.xml 中 通过 <activity>标签指定 android:launchMode 启动模式。
在 ActivityTest项目中修改代码:修改 FirstActivity 中
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
Log.d( "FirstActivity" , this.toString() );
setContentView( R.layout.first_layout ) ; //加载了新的布局
Button button1 = ( Button ) findViewById( R.id.button_1 );
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Intent intent = new Intent(FirstActivity.this , FirstActivity.class );
startActivity( intent );
}
} ) ;
其他模式知识略写了。
知晓当前是在哪个活动:
在 ActivityTest项目中修改代码:右击com.example.activitytest , 建立 BaseActivity类,(此类没
有注册哦) ,和普通的活动一样:代码如下:
public class BaseActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
Log.d( "BaseActivity" , getClass().getSimpleName() );
}
}
把 BaseActivity 变成父类,让 FirstActivity 等活动都继承 BaseActivity ,分别执行活动。
随时随地退出程序:设计集合类对所有活动进行管理。
代码: public class ActivityCollector {
public static List<Activity> activities = new ArrayList<>();
public static void addActivity( Activity activity ) {
activities.add(activity);
}
public static void removeActivity( Activity activity ) {
activities.remove(activity);
}
public static void finishAll( ) { //销毁所有的活动
for( Activity activity : activities )
{ if( !activity.isFinishing() )
activity.finish() ;
}
}
}
继续修改 BaseActivity 的代码:
public class BaseActivity extends AppCompatActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
Log.d( "BaseActivity" , getClass().getSimpleName() );
ActivityCollector.addActivity( this );
}
protected void onDestory( ) {
super.onDestory( );
ActivityCollector.removeActivity( this );
}
}
修改 ThirdActivity 的代码:
public class ThirdActivity extends BaseActivity {
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
Log.d( "ThirdActivity" , "task id is " + getTaskId() );
setContentView( R.layout.third_layout ) ; //加载了新的布局
Button button3 = ( Button ) findViewById( R.id.button_3 );
button3.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
ActivityCollector.finishAll( );//程序的任何地方执行此方法退出程序
}
} ) ;
}
下面这种写法很牛逼。
启动活动的最佳写法:当前活动向 另一个活动 传递 参数 并启动 ,改进写法:
public class SecondActivity extends BaseActivity {
public static void actionStart( Context context , String data1 , String data2 ){
Intent intent = new Intent( context , SecondActivity.class );
intent.putExtra( "param1" , data1 );
intent.putExtra( "param2" , data2 );
context.startActivity( intent );
}
}
启动 SecondActivity :
button1.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
SecondActivity.actionStart( FirstActivity.this , "data1","data2");
}
} ) ;
-------------------------------------------------------复制到此;
第五章:
广播机制:
Android每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收到自己关心
的广播内容(可以来自于系统或者 其他程序)
广播接收器: Broadcast Receiver
广播的类型:
标准广播: 在标准广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息
。
有序广播:同步执行的广播,同一时刻,只有一个广播接收器接收广播。
应用程序通过监听这些广播来得到系统的状态信息。使用 广播接收器: Broadcast Receiver
注册后可以接受广播: 动态注册(在代码中) 和 静态注册(AndroidManifest.xml )
创建一个 :广播接收器 ,以动态注册的方式 监听网络变化的实现代码:
新建项目BroadcastTest,然后修改MainActivity中的代码:
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter ;
private NetworkChangeReceiver networkChangeReceiver;
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.activity_main ) ; //加载了新的布局
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//监听哪种类型的广播
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver( networkChangeReceiver, intentFilter); //注册监听广播
}
protected void onDestroy(){
super.onDestroy();
unregisterReceiver( networkChangeReceiver );//必须取消注册哦
}
class NetworkChangeReceiver extends BroadcastReceiver {
public void onReceiver( Context context ,Intent intent ){// 网络变化就会执行本方法
Toast.makeText(context , "network changes", Toast.LENGTH_SHORT).show() ;
}
}
注意: 敏感操作声明权限:
在 AndroidManifest.xml 中 ,添加代码:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
动态注册的话,需要程序驱动后才能接收到广播。
静态注册的话,程序未启动也可以接受广播。在 AndroidManifest.xml 中 系统自动添加注册代码
利用工具创建广播接收器 : 右击com.example.broadcasttest , new一个 Broadcast Receiver
:名称为 BootCompleteReceiver ,都勾选属性,修改代码:
class BootCompleteReceiver extends BroadcastReceiver {
public void onReceiver( Context context ,Intent intent ){// 网络变化就会执行本方法
Toast.makeText(context , "Boot Complete", Toast.LENGTH_LONG).show() ;
}
}
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
发送自定义广播:
标准广播: 在标准广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息
。
有序广播:同步执行的广播,同一时刻,只有一个广播接收器接收广播。
class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceiver( Context context ,Intent intent ){// 网络变化就会执行本
Toast.makeText(context , "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show() ;
}
}
在 AndroidManifest.xml 中修改广播器代码:
<receiver
android:name=".MyBroadcastReceiver"
android:enable = "true"
android:exported = "true" >
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
</receiver>
添加一个按钮测试:
public void onClick( View v ){
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast( intent );
}
使用本地广播 更安全:广播只会在程序的内部进行传递。广播接收器也只会接收来自本应用程
序发出来的广播。
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter ;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
// private NetworkChangeReceiver networkChangeReceiver;
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.activity_main ) ; //加载了新的布局
localBroadcastManager = LocalBroadcastManager.getInstance( this );
Button button = ( Button ) findViewById( R.id.button );
button.setOnClickListener( new View.OnClickListener( ) {
public void onClick( View v ){
Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast( intent ); //发送本地广播
}
} ) ;
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");//监听哪种类型的广播
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver( localReceiver , intentFilter); //注册监听广播
}
protected void onDestroy(){
super.onDestroy();
localBroadcastManager.unregisterReceiver( localReceiver );//必须取消注册哦
}
class LocalReceiver extends BroadcastReceiver {
public void onReceiver( Context context ,Intent intent ){// 变化就会执行本方法
Toast.makeText(context , "receivde local broadcast", Toast.LENGTH_SHORT).show() ;
}
}
-------------------------------------------------------复制到此;
第10章 : 服务
更新应用程序中的UI,必须在主线程中执行,在子线程中执行会出错。
验证案例:新建 AndroidThreadTest 项目,修改 activity_main.xml文档:
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="hello world ! "
android:textSize="20sp" />
<Button
android:id ="@+id/change_text" //定义算术的标识符,+去掉表示引用
android:layout_width="wrap_parent"
android:layout_height="wrap_content"
android:text="Change Text"
/>
接着修改 MainActivity 中的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView text;
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState ) ;
setContentView( R.layout.activity_main ) ; //加载了新的布局
text = ( TextView ) findViewById( R.id.text );
Button change_text = ( Button ) findViewById( R.id.change_text );
change_text .setOnClickListener( new View.OnClickListener( ) {
}
public void onClick( View v ){
switch( v.getId()) {
case R.id.change_text:
new Thread( new Runnable()
{ public void run(){ text.setText("Nice to meet you"); }
}
}).start(); break;
default: break;
}
}
}
上述程序崩溃了。
如果 我们要创建子线程,子线程执行完任务后把结果 更新UI控件,该如何实现呢?
可以 引入 异步消息处理机制。
接着修改 MainActivity 中的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final int UPDATE_TEXT =1 ;
private TextView text;
private Handler handler = new Handler() {
public void handleMessage( Message msg ) {
switch( msg.what ) {
case UPDATE_TEXT : text.setText("Nice to meet you"); break;
default: break;
}
}
};
public void onClick( View v ){
switch( v.getId()) {
case R.id.change_text:
new Thread( new Runnable()
{ public void run(){
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message);
}
}
}).start(); break;
default: break;
}
}
}
开始解释:
Message :用于在不同线程之间交换少量的信息数据(叫做消息),
Handler : 主要用于发送(sendMessage() )和处理消息(handleMessage() )的。
MessageQueue : 是消息队列,用于存放来自于 Handler发送来的消息。
每个线程中只有一个这个对象。
Looper: 是每个线程中的MessageQueue的管家,调用Looper的loop()后,就会进入到无线的循
环当中,去取出MessageQueue 中的消息。