第四讲 服务、广播与酷特性

[快捷键]

Ctrl+shift+a  查找键

Ctrl+shift+c  将参数转换成变量

Ctrl+alt+L    格式化代码

4.1 service

Service既不是进程也不是线程,最合适的场景是听歌,它比Activity有更高级的优先级。后台长期运行。

4.1.1 Service生命周期

 


onCreate()事件回调函数: Service的生命周期开始,完成Service的初始化工作

onStart()事件回调函数:活动生命周期开始,但没有与之对应的“停止”函数,因此可以近似认为活动生命周期也是以onDestroy()标志结束

onDestroy()事件回调函数: Service的生命周期结束,释放Service所有占用的资源

4.1.2 Service服务启动的两种方式

Start :通过调用Context.startService()启动Service,通过调用Context.stopService()或Service.stopSelf()停止Service

 

Bound:使用Service的组件通过Context.bindService()建立服务链接,通过Context.unbindService()停止服务链接

如果在绑定过程中Service没有启动,Context.bindService()会自动启动Service

4.1.3 启动Service

显示启动:在Intent中指明Service所在的类,并调用startService(Intent)函数启动Service

  1. final Intent serviceIntent = new Intent(this, RandomService.class);
  2. startService(serviceIntent);

隐式启动:在注册Service时,声明Intent-filter的action属性

  1. <service android:name=".RandomService">
  2.    <intent-filter>
  3.             <action android:name="edu.hrbeu.RandomService" />
  4.    </intent-filter>
  5. </service>

隐式启动的代码如下

  1. final Intent serviceIntent = new Intent();
  2. serviceIntent.setAction("edu.hrbeu.RandomService");

4.1.4 案例实现

利用Service实现后台音乐播放

 

【注意】

1、 myMediaPlayer=MediaPlayer.create(this,R.raw.bigbang);用这种方式创建的MediaPlayer可以直接start 。

2、 音频文件存在R.raw.bigbang,注意rae 这个文件夹是我们后创建的,在res文件夹下。

用start的方式

MyService.class

public class MyService extends Service{
    private MediaPlayermyMediaPlayer;
    @Override
   
public void onCreate(){
        super.onCreate();
        myMediaPlayer=MediaPlayer.create(this,R.raw.bigbang);
    }
    @Override
   
public int onStartCommand(Intentintent, int flags, int startId){
        myMediaPlayer.start();
        return super.onStartCommand(intent,flags, startId);
    }
    @Override
   
public void onDestroy(){
        super.onDestroy();
        myMediaPlayer.stop();
    }
    @Nullable
    @Override
   
public IBinderonBind(Intent intent) {
        return null;
    }
}

 

启动及停止服务

View.OnClickListener mListener=new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.start:
                startService(new Intent(MainActivity.this,MyService.class));
                break;
            case R.id.stop:
                stopService(new Intent(MainActivity.this,MyService.class));
                break;
        }

    }
};

用Bound的方式

MyService.class

public class MyService extends Service {
    private MediaPlayer myMediaPlayer;
    private IBinder mIBinder=new LocalBinder();
    @Override
    public void onCreate() {
        super.onCreate();
        myMediaPlayer=MediaPlayer.create(this,R.raw.bigbang);
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        myMediaPlayer.start();
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        myMediaPlayer.stop();
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mIBinder;
    }
    public class LocalBinder extends Binder {
        MyService getservice(){
         return MyService.this;
        };
    }
}

 

 

启动及停止服务

private ServiceConnection mServiceConnection=new ServiceConnection(){

    //服务连接时
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {

        MyService.LocalBinder localBinder= (MyService.LocalBinder) service;
        MyService myService=localBinder.getservice();
    }
   //服务断开连接时
    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};
View.OnClickListener mListener=new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.start:
               startService(new Intent(MainActivity.this,MyService.class));
                bindService(new Intent(MainActivity.this,MyService.class),mServiceConnection,BIND_AUTO_CREATE);
                break;
            case R.id.stop:
                unbindService(mServiceConnection);
                stopService(new Intent(MainActivity.this,MyService.class));

                break;
        }

    }
};
 

4.1.5 IntentService

4.1.6小结

1.Service是进程或线程吗?

不是

2.能做耗时操作吗?

不能,如果要做,必须如下

Thread mThred=new Thread(new Runnable() {
    @Override
    public void run() {
        
    }
});
mThred.start();     

3.用它主要来做什么?

在后台长久运行

 

4.2 BroadcaseReceiver

BroadcastReceiver也就是“广播接收者”的意思,它是用来接收来自系统和应用中的广播,他没有用户界面。 属于android四大组件之一,需要在项目清单中注册。

系统使用了很多广播

通知时间改变

电池电量变低

拍摄了新照片

改变了语言等

创建步骤

1)创建一个类myTestBroadcastReceiver用于继承BroadcastReceiver

public class myTestBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //发送广播
        if(intent!=null){
          if(TextUtils.equals(intent.getAction(),"demo.service.fxc.myservice.ab"));
            String toast=intent.getStringExtra("toast");
            Toast.makeText(context,toast,Toast.LENGTH_LONG).show();
        }
    }
}

 

2)注册

静态注册:在清单文件中注册

<receiver android:name=".myTestBroadcastReceiver">
    <intent-filter>
        <action android:name="demo.service.fxc.myservice.abc"/>
        </intent-filter>
</receiver>

 

动态注册:在代码中注册

 

//动态注册,首先需要过滤  IntentFilter 然后注册
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("demo.service.fxc.myservice.abc");
registerReceiver(mMyTestBroadcastReceiver,intentFilter);
 
两者的区别在于:动态注册建议在onStart注册,在onDestroy注销;

 

@Override
protected void onStart() {
    super.onStart();
    //动态注册,首先需要过滤  IntentFilter 然后注册
    IntentFilter intentFilter=new IntentFilter();
    intentFilter.addAction("demo.service.fxc.myservice.abc");
    registerReceiver(mMyTestBroadcastReceiver,intentFilter);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(mMyTestBroadcastReceiver);
}

 

3)通过sendBroadcast(intent) 广播

//发送广播
 Intent intent=new Intent();
 intent.setAction("demo.service.fxc.myservice.abc");
 intent.putExtra("Toast","歌曲要播放了");
 sendBroadcast(intent);

 

 

【注意】不能做耗时操作,//发送广播  >10s 则要  new  work thread

建议适当的用,不要滥用。

4.3 Webview

WebView(网络视图)能加载显示网页,可以将其视为一个浏览器。它使用了WebKit渲染引擎加载显示网页,实现WebView有以下两种不同的方法:

方法一:

1.首先在项目管理文件中声明权限,否则出现Web page not available错误。

<uses-permission android:name="android.permission.INTERNET"/>

2.在布局文件中声明WebView

3.在Activity中实例化WebView

4.调用WebView的loadUrl( )方法,设置WevView要显示的网页

(1)可以加载线上url

view.loadUrl("http://www.zhihu.com/");

 

(2)可以加载本地html(在res 文件夹中新建asset文件夹,将资源文件拷贝)

view.loadUrl("file:///android_asset/test.html");

(3)可以和js交互

mWebView.getSettings().setJavaScriptEnabled(true);

5.为了让WebView能够响应超链接功能,调用setWebViewClient( )方法,设置  WebView视图

6.用WebView点链接看了很多页以后为了让WebView支持回退功能,需要覆盖覆盖Activity类的onKeyDown()方法,如果不做任何处理,点击系统回退键,整个浏览器会调用finish()而结束自身,而不是回退到上一页面.

@Override
public void onBackPressed() {
    if(mWebView!=null&mWebView.canGoBack())
        mWebView.goBack();
    else 
        super.onBackPressed();
}

7.导航和历史记录

public void onBackPressed() {
    if(mWebView!=null&mWebView.canGoBack()) {

        WebBackForwardList webBackForwardList=mWebView.copyBackForwardList();
        WebHistoryItem webHistoryItem= webBackForwardList.getItemAtIndex(0);
        String historyUrl= webHistoryItem.getUrl();
        mWebView.goBack();
        mWebView.goForward();
        mWebView.goBackOrForward(+1);
        mWebView.reload();
    }
    else
        super.onBackPressed();
}

4.4Android的酷特性widget(窗口小部件)

App Widget是应用程序窗口小部件(Widget)是微型的应用程序视图,它可以被嵌入到其它应用程序中(比如桌面)并接收周期性的更新。你可以通过一个App Widget Provider来发布一个Widget。

主要相关类介绍:

(1)AppWidgetProvider 继承自 BroadcastReceiver,它能接收 widget 相关的广播,例如 widget 的更新、删除、开启和禁用等。

AppWidgetProvider中的广播处理函数如下:

onUpdate  当 widget 更新时被执行。
onReceive(Context, Intent):  接收到任意广播时触发,并且会在上述的方法之前被调用。

  总结,AppWidgetProvider继承于 BroadcastReceiver。实际上,AppWidge中的onUpdate()、onEnabled()、onDisabled()等方法都是在onReceive()中调用的;是onReceive()对特定事情的响应函数。

 

1.新建一个Android工程命名为:Appwidget

public class appWidget extends AppWidgetProvider{
    public appWidget() {
        super();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        if(intent!=null && TextUtils.equals(intent.getAction(),"widget_button_action")) {
            Toast.makeText(context, "intent_widget_abc", Toast.LENGTH_LONG).show();
            //获取布局及控件,修改属性
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.layout_widget);
            remoteViews.setTextViewText(R.id.widget_textview, "被点击了");
            AppWidgetManager appWidgetManager=AppWidgetManager.getInstance(context);
            ComponentName componentName=new ComponentName(context,appWidget.class);
             //刷新视图
            appWidgetManager.updateAppWidget(componentName,remoteViews);
        }

    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        //更新布局
        RemoteViews remoteViews=new RemoteViews(context.getPackageName(),R.layout.layout_widget);

        Intent intent=new Intent();
        intent.setClass(context,appWidget.class);
        intent.setAction("widget_button_action");
        PendingIntent pendingIntent=PendingIntent.getBroadcast(context,0,intent,0);
        remoteViews.setOnClickPendingIntent(R.id.widget_button,pendingIntent);
        appWidgetManager.updateAppWidget(appWidgetIds,remoteViews);
    }
}

2.准备素材,一个是Widget的图标,一个是Widget的背景

3.建立Widget内容提供者文件,我们在res下新建一个set_widget.xml

代码如下:

 

<appwidget-providerxmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:minWidth="140dp"
             android:minHeight="140dp"
             android:previewImage="@drawable/timg"
             android:updatePeriodMillis="200000"
             android:widgetCategory="home_screen"
              android:initialLayout="@layout/layout_widget">

</appwidget-provider>

其中宽度、长度很清楚,还有android:updatePeriodMillis是自动更新的时间间隔,android:initialLayoutWidget的界面描述文件。

4. 修改layout_widget.xml布局,代码如下:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="nihao!"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="button"/>
</LinearLayout>

6.   修改配置文件AndroidManifest.xml,代码如下

<application
    android:allowBackup="true"
   android:icon="@mipmap/ic_launcher"
   android:label="@string/app_name"
    android:supportsRtl="true"
   android:theme="@style/AppTheme">
    <activityandroid:name=".MainActivity">
        <intent-filter>
            <actionandroid:name="android.intent.action.MAIN"/>

            <categoryandroid:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
    <receiverandroid:name=".appWidget">
        <intent-filter>
            <actionandroid:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-dataandroid:name="android.appwidget.provider"
                  android:resource="@layout/set_widget">
        </meta-data>
    </receiver>

</application>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值