这一周的主要内容是BroadcastReceiver , Service , Webview,Widget. 内容还是比较丰富的,想要扎实掌握,需要更多的练习。
一、BroadcastReceiver
A. 是什么
—-public abstract class
BroadcastReceiver
—- extends Object
Known Direct Subclasses
—-AppWidgetProvider
抽象类,继承Object,其中一个子类就是下边要学的AppWidget.
广播机制,本质上它就是一种组件间的通信方式.
B.为什么要用
全局通信 ,降低耦合度。 不用再持有对方的引用,就可以用broadcastReciever中的intent实现数据交流。 一个地方发送,希望很多地方接收。广播的发送者和接收者事先是不需要知道对方的存在的,这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。
C.怎么用
接收系统广播,自定义广播,静态注册,动态注册
===让程序接收一条开机广播===
1.新建一个类,继承BroadcastReceiver ,重写onReceive方法。该方法内是你收到广播之后进行的操作。
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"开机",Toast.LENGTH_SHORT).show();
}
}
2.在AndroidManifest.xml文件中静态注册,使用这个类名
<!--接收开机广播的权限-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!--接收系统启动后发出的一条值为android.intent.action.BOOT_COMPLETED的广播,所以在此加入相应的action-->
<receiver android:name=".BootCompleteReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
===动态注册广播接收器—–动态注册,接收网络变化广播===
1.新建内部类,继承BroadcastReceiver
2.注册,新建NetworkChangeReceiver对象,新建IntentFilter对象,给IntentFilter添加行为,注册
3.注销 , 动态注册,一定要注销。unRegisterReceiver
public class MainActivity extends AppCompatActivity {
private NetworkChangeReceiver mNetworkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 动态注册广播接收器,需要IntentFilter,需要Action,需要regist,和静态注册的节点相对应
IntentFilter intentFilter=new IntentFilter();
// 这是接收系统广播,值为android.net.conn.CONNECTIVITY_CHANGE的action
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
mNetworkChangeReceiver = new NetworkChangeReceiver();
// 注册,参数1,自定义的广播接收器,参数2,过滤器
registerReceiver(mNetworkChangeReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 动态注册,一定要注销。
unregisterReceiver(mNetworkChangeReceiver);
}
// 定义一个内部类,继承BroadcastReceiver,并重写onReceive方法
// 每当网络状态发送变化时,onReceive方法就会执行
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"网络变化",Toast.LENGTH_SHORT).show()
}
}
}
需要权限
<!--接收网络状态权限-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
总结:
动态注册广播接收器,可以实现灵活的注册与注销,在灵活性方面有很大的优势。但是必须在程序启动之后才能接收到广播,因为他是写在onCreate()方法中。静态注册,可以实现在程序未启动的情况下就能接收到广播。
BroadcastReceiver是一个抽象类,唯一必须重写的抽象方法 onReceive(),在这个方法内不要进行耗时操作,超过10s会被杀死。广播接收器更多的是使用内部类的方式
Service
A. 是什么
public abstract class
Service
java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.app.Service
Service是一个抽象类,父类是ContextWrapper,Context。是一个应用组件,长时间在后台操作,没有用户界面。
B. 为什么要用
Service独特性,他不需要界面,一直在后台运行,即使退出程序。另外就是Service优先级高,系统轻易不会杀死服务。
因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它。
C. 怎么用
两种使用方式,
第一种:
startService() 执行顺序,onCreate(),onStartCommand()
stopServiece 执行顺序,onDestroy()
第二种:
bindService ,主要是为了,与Serviece进行数据交流
详细写下使用bindService()与service进行数据交流执行步骤:
注册:
<service android:name=".TestService">
</service>
1.在activity中适当位置,调用bindService方法
bindService(new Intent(MainActivity.this,TestService.class),mServiceConnection,BIND_AUTO_CREATE);
2.该方法的第二个参数,就需要,新建一个ServiceConnection
private ServiceConnection mServiceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
TestService.LocalBinder localBinder= (TestService.LocalBinder) service;
mTestService = localBinder.getservice();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
3.Service.class同样,上边新建一个实例化对象ServiceConnection,它的onServiceConnection的第二个参数会传进一个IBinder
这个IBinder实际上是Service类中onBind()方法中返回的IBinder. 并从这个IBinder中得到Service
public IBinder onBind(Intent intent) {
Log.i(TAG,"onBind");
return mIBinder;
}
4.那刚开始onBind方法,是return null;的,所以新建全局变量IBinder,来返回。在Service新建一个内部类。
public class LocalBinder extends Binder{
TestService getservice(){
return TestService.this;
}
}
5.新建IBinder,并在onBind()方法中返回
private IBinder mIBinder=new LocalBinder();
6.在Service中设立得到数据的方法。
public int getMusicProgress(){
return 18;
}
7.当activity有了,Service对象后,可以通过service中的方法,进行数据交流
if(mTestService!=null){
int progress=mTestService.getMusicProgress();
}
-8. bindService()方法停止服务,必须解绑,调用unbindService()方法
unbindService(mServiceConnection);
实际上就是activity与Service要进行数据交流。 那两个类之间,最初实际是IBinder是桥梁和管道。所以,通过IBinder得到Service.然后利用其方法开始交流.
Widget
不了解,使用起来真是不灵。
A.是什么
—public class
AppWidgetProvider
—extends BroadcastReceiver
做Widget,需要继承AppWidgetProvider类,它是BroadcastReceiver的子类。
B.为什么用
很独特,可以放在主屏幕,直接操作应用,不用点击进入应用内就可以使用。还可以放在锁屏界面,很酷炫。
C.怎么用
1.写一个类, 继承AppWidgetProvider ,实现onReceive方法
public class MusicWidget extends AppWidgetProvider {
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
2.androidmanifest 注册
<!--桌面小部件 action 检测到widget的更新 android:resourc指定布局-->
<receiver android:name=".TestWdiget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@layout/layout_setting"/>
</receiver>
3。 appwidget 的设置布局 R.layout.setting
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="320dp"
android:minHeight="140dp"
android:previewImage="@drawable/icon"
android:initialLayout="@layout/layout_widget"
android:updatePeriodMillis="20000"
android:widgetCategory="home_screen">
</appwidget-provider>
4。 widget 的具体布局 R.layout.layout_widget. 可以自行设置和普通布局一样。
5.实现 widget点击功能。
public class MusicWidget extends AppWidgetProvider {
public static final String WIDGET_BUTTON_ACTION = "widget_button_action";
// 接收
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
// 接收
if(intent!=null&& TextUtils.equals(intent.getAction(),WIDGET_BUTTON_ACTION)){
// 1. 远程视图 , 参数1,包名。。参数2, 布局文件
RemoteViews remoteViews=new RemoteViews(context.getPackageName(),R.layout.layout_widget);
// 2.接收数据 进行处理
remoteViews.setTextViewText(R.id.widget_music_name,"1");
remoteViews.setImageViewResource(R.id.widget_start,R.drawable.pause);
// 3.更新。 发送和接收都需要更新
AppWidgetManager appWidgetManager=AppWidgetManager.getInstance(context);
// 组件的名字
ComponentName componentName=new ComponentName(context,MusicWidget.class);
appWidgetManager.updateAppWidget(componentName,remoteViews);
}
}
// 发送
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
// 1. 远程视图 , 参数1,包名。。参数2, 布局文件
RemoteViews remoteViews=new RemoteViews(context.getPackageName(),R.layout.layout_widget);
// 2.发送数据
Intent intent=new Intent();
// 发给他本身
intent.setClass(context,MusicWidget.class);
intent.setAction(WIDGET_BUTTON_ACTION);
// 参数1,context 参数2,requestCode 参数3,intent 参数4,flag
PendingIntent pendingIntent=PendingIntent.getBroadcast(context,0,intent,0);
// .设置按钮的点击事件
remoteViews.setOnClickPendingIntent(R.id.widget_start,pendingIntent);
// 3. 更新所有id的事件
// 更新。 发送和接收都需要更新
appWidgetManager.updateAppWidget(appWidgetIds,remoteViews);
}
}
一些常用方法:
onDeleted():当该类型的AppWidget每次被删除时,调用此方法
onDisabled(): 当该类型的窗口小部件(AppWidget)全被删除时,调用此方法
onEnabled(): 当第一次创建该类型的AppWidget时,调用此方法
onReceive(): 广播接受者方法,用来接受广播消息
onUpdate(): 每次创建该类型的AppWidget都会调用此方法 , 通常来说我们需要在该方法里为该AppWidget指定RemoteViews对象。
欢迎留言。