Android应用界面开发_学习笔记_第四周
2016-03-26 20:42
609 查看
Widget
一、是什么
一个桌面插件二、如何使用
从一个小Demo来做起:1、在AndroidManifest中声明 App Widget
2、在xml目录定义 App Widget的初始化xml文件
3、实现Widget具体布局的Layout xml
4、继承APPWidgetProvider类,实现具体的Widget业务逻辑。
实现步骤:
1、新建一个类TestWidet继承AppWidgetProvider;
再在AndroidManifest里注册
<receiver android:name=".TestWidget"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <meta-data android:name="android.appwidget.provider" //指定provider的resource,manifest中存储数据,这里存储了name,name告诉我们这是一个receiver同时还是一个widgetprovider;resource是配置选项,配置选项在xxx.xml文件里。 android:resource="@layout/widget_setting"/> </receiver>
intent-filter中过滤了APPWIDGET_UPDATE事件,这个事件是由系统触发的更新事件,每个widget必须包含这个事件;meta-data标签描述的是widget的配置文件指向,该文件描述了widget的一些基本信息。
2、定义resource(定义配置文件)
在这里定义 layout、最小宽高度、在Widget里的背景、更新时间等。
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns: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/girl" android:initialLayout="@layout/layout_widget" android:updatePeriodMillis="20000" android:widgetCategory="home_screen"> </appwidget-provider>
3、layout_widget布局文件
<?xml version="1.0" encoding="utf-8"?> <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="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="Large Text" android:id="@+id/widget_textView"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="New Button" android:id="@+id/widget_button"/> </LinearLayout>
4、具体的Widget业务逻辑(onReceive方法和onUpdate方法)
package com.example.chenjinhua.myapplication; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.text.TextUtils; import android.util.Log; import android.widget.RemoteViews; /** * Created by chenjinhua on 16/3/26. */ public class TestWidget 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)){ Log.i("WIDGET_BUTTON_ACTION", "be clicked"); /* * 设置组件的变化 * */ //必须重新new一遍RemoteViews,不然RemoteViews不会更新的。 RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.layout_widget); remoteViews.setTextViewText(R.id.widget_textView,"be clicked"); remoteViews.setTextColor(R.id.widget_textView, Color.BLUE); /* * 更新组件 * */ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); //获取组件的名字 ComponentName componentName = new ComponentName(context,TestWidget.class); appWidgetManager.updateAppWidget(componentName,remoteViews); } } /* 当程序初始化时会调用onUpdate方法 * */ @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); //远程视图,把布局文件读出来,读成一个remoteViews的界面 /* * 1、在RemoteViews的构造函数中,通过传入layout文件的id来获取 “layout文件对应的视图(RemoteViews)"; * 2、然后,调用RemoteViews中的方法能对layout中的组件进行设置; * 3、可以调用setOnClickPendingIntent() 来设置Button的点击响应事件 * */ RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.layout_widget); Intent intent = new Intent(); //广播发给TestWidget.class本身,它本身可在onReceive方法里接收。 intent.setClass(context,TestWidget.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); } }
Tips
1、 RemoteViews
顾名思义,它是一个远程视图。App Widget中的视图,都是通过RemoteViews表现的。 在RemoteViews的构造函数中,通过传入layout文件的id来获取 “layout文件对应的视图(RemoteViews)”;然后,调用RemoteViews中的方法能对layout中的组件进行设置(例如,可以调用setTextViewText()来设置TextView组件的文本,可以调用setOnClickPendingIntent() 来设置Button的点击响应事件)。 因此,我们可以将 “RemoteViews 看作是 layout文件中所包含的全部视图的集合”。
2、更新AppWidget界面
(1)、如果是在onUpdate()方法内更新AppWidget界面eg: appWidgetManager.updateAppWidget(appWidgetIds, ActivityView);
(2)、如果是在onUpdate()方法外(一般为Service内)更新AppWidget界面,则需要定义几个变量
eg: public RemoteViews views; //RemoteView对象
public ComponentName thisWidget; //组件名
public AppWidgetManager manager; // AppWidget管理器
thisWidget = new ComponentName(this, PictureAppWidgetProvider.class); manager = AppWidgetManager.getInstance(this); manager.updateAppWidget(thisWidget, views);
其他:
1、与service通信2、Widget控件的交互方法
3、如何做一个桌面播放器Widget
BroadcastReceiver
一、BroadcastReceiver是什么?
1、四大组件之一:广播(通知消息)接收器 –要想到在Manifest中注册2、系统使用了很多广播:通知时间改变(闹钟才会响)、电池电量变低、拍摄了照片、改变了语言;
3、没有用户界面。
只负责向所有在Manifest里的注册者发送广播,需要这个广播的人去接收它。
二、BroadcastReceiver怎么使用?
两种注册方式BroadcastReceiver的两种注册方式
1、静态注册
<receiver android:name=".TestBroadcastReceiver"> <intent-filter> <action android:name="com.example.test.broadcast"/> </intent-filter> </receiver>
2、动态注册
在onStart方法中注册,在onStop方法中反注册
@Override protected void onStart() { super.onStart(); /* 动态注册广播*/ //根据action里的android:name过滤广播。 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(COM_EXAMPLE_TEST_BROADCAST); registerReceiver(mTestBroadcastReceiver, intentFilter); } @Override protected void onStop() { super.onStop(); unregisterReceiver(mTestBroadcastReceiver); }
3、两者的区别:静态注册的广播一直有效,动态注册的广播需要反注册掉,不然注册在内存里,会不断的消耗内存,所以常用动态注册。
如何接收广播onReceive方法
MainActivity类@Override public void onClick(View view) { /* 发送广播 */ Intent intent = new Intent(MainActivity.this,TestBroadcastReceiver.class); //只发给action为COM_EXAMPLE_TEST_BROADCAST intent.setAction(COM_EXAMPLE_TEST_BROADCAST); intent.putExtra("toast", "this is a toast of broadcast"); sendBroadcast(intent); }
TestBroadcastReceiver类
public class TestBroadcastReceiver extends BroadcastReceiver { /* 接收广播、处理数据 */ @Override public void onReceive(Context context, Intent intent) { if (intent != null){ //判断字符串是否相等TextUtils.equals(). if (TextUtils.equals(intent.getAction(),MainActivity.COM_EXAMPLE_TEST_BROADCAST)){ String toastString = intent.getStringExtra("toast"); Toast.makeText(context,toastString,Toast.LENGTH_SHORT).show(); } } } }
如果在onReceive方法中执行耗时操作会怎样?如何解决?
同Activity、Service一样,new Thread进程。
三、几种类型?
1、Normal broadcasts2、Ordered broadcasts
3、二者有什么区别?
正常广播,没有顺序,一下子向所有注册者发送广播;有序广播,广播有自己的顺序,根据顺序发送广播。有点像Service和IntentService。
4、Local broadcasts:LocalBroadcastManager 广播不是在系统中而是在某应用中,这样速度会很快;android系统发广播时所有的应用都能收到,消耗手机性能、广播延时。
四、BroadcastReceiver的生命周期
Register – SendBroadcast – onReceive – unRegister。总结:
1、是什么?
2、怎么用?
3、两种注册方式?
4、几种类型?
5、生命周期
注意事项: 1、适当的用、不要滥用 (消耗性能、广播延时、广播被丢弃等。)
2、可以用LocalBroadcast
该用callback时用callback,要么用LocalBroadcast。
service
service既不是一个单独的进程,又不是一个单独的线程;听歌的服务多用service实现(和activity相比的优势),可以长时间的保存在后台,系统不到万不得已不会杀掉,同时service也不需要界面。
只要service不死,MediaPlayer就一直持有
service的生命周期
启动和停止Service的两种方式
1.Started:context.startService();context.stopService(). 该方法适用于服务和activity之间没有调用交互的情况
2.Bound:context.bindService();context.unbindService() 该方式可以传递参数或者方法调用,通过ServiceConnection的内部类实现来连接Service和Activity。
必须要在Manifest中声明service:如果没声明,编译器不会报错(activity会报错)
<service android:name=".MusicService"/> //.表示根目录,也可以写全为:com.example.jinhua.MusicService
音乐资源文件放在res/raw,
//在oncreare()方法里创建MediaPlayer对象 mediaPlayer = MediaPlayer.create(this,R.raw.libai);
第二种方式: Bind Service 继承自Binder类
首先bindService()方法,把serviceConnection作为参数给传进去,实际上serviceConnection是传给Service,Service会把onBind的Ibinder传回给刚刚传进来的serviceConnection(一个service要想能够被其他组件绑定,那么它的 onBind() 方法必须被实现,且必须返回一个 IBinder 对象,然后其他组件可以通过这个 IBinder 对象与该 service 进行通讯。),在serviceConnection里我们就会收到service其实是Binder,我们又在Binder中构造了service,即return service,所以通过这种方法可以获取service,service里面又可以创建公共方法,可以通过service对象的这些方法获取里面数据,这是就可以互相通信。
IBinder是负责service和外界(如activity)的通信
将IBinder强转为我们本身的Binder;
bindService注意:
1、bindService(或者startService)后,service的onCreate方法只执行一次,执行后service就运行起来了,如果不unbindService的话,service就不会被关闭onDestroy的,即使stopService(或者unbindService)也没有用。
2、
startService()
bindService()
(1)先执行startService的onCreate方法,然后在bindService;为什么要用bindService,是为了让service和一个应用界面、组件进行绑定,一旦绑定了,service和这个应用界面就会同生死共存亡,当界面被销毁掉时,绑定的service就会调用unbindService,然后stopService,然后onDestroy然后被销毁。
(2)如果界面没有被销毁,而又绑定了界面,这时调用stopService,是不会销毁service的。
这就是bind和startService、stopService的区别。
(3)如果没有bind,用的是startService、stopService,若界面销毁了,service还会在后台进行。
IntentService
异步处理服务
IBinder是负责service和外界(如activity)的通信
将IBinder强转为我们本身的Binder;
bindService注意:
1、bindService(或者startService)后,service的onCreate方法只执行一次,执行后service就运行起来了,如果不unbindService的话,service就不会被关闭onDestroy的,即使stopService(或者unbindService)也没有用。
2、
startService()
bindService()
(1)先执行startService的onCreate方法,然后在bindService;为什么要用bindService,是为了让service和一个应用界面、组件进行绑定,一旦绑定了,service和这个应用界面就会同生死共存亡,当界面被销毁掉时,绑定的service就会调用unbindService,然后stopService,然后onDestroy然后被销毁。
(2)如果界面没有被销毁,而又绑定了界面,这时调用stopService,是不会销毁service的。
这就是bind和startService、stopService的区别。
(3)如果没有bind,用的是startService、stopService,若界面销毁了,service还会在后台进行。
IntentService 异步处理服务
异步处理服务:各自干各自的事,A做好了通知一下B就好。
同步处理服务的意思:A执行完了把结果给B,B再执行。
(1)onStartCommand()//开始的时候把intent给你
(2)onHandleIntent()//处理intent数据,这里的intent是由startService或者bindService传的
(3)在什么场景下使用:
什么时候用Service,什么时候用IntentService?当有需要把任务用队列来分配时用IntentService,当不需要时,比如后台播放,就用Service。
总结:
(1)Service的基本概念
(2)如何使用
1、Start
2、Bind
(3)IntentService
(4)Service的生命周期
(5)Bound Service的生命周期
小技巧:
1、Service是一个进程或者线程吗?都不是。
2、能做耗时操作吗?不能,需要new一个Thread来做耗时操作。
3、用它主要来做什么?主要用来在后台长久的运行。
相关文章推荐
- Android开源库
- Android之自定义属性
- android Studio 使用技巧
- android中MVP模式的小案例(一)
- android中惯用的颜色值
- android系统编译kernel时出错:file not recognized: File truncated
- android表情Gson EditText TextView
- Android RecyclerView 使用完全解析
- 查看Android版本的源代码
- android调用第三方api实现用户数授权登录机制详解
- Android SharePreferences的学习笔记
- QtAndroid具体解释(6):集成信鸽推送
- Dagger2在AndroidStudio中的应用以及MVP
- Android SingleTask跨任务栈调用
- 关于Adapter和ViewHolder的另类写法
- Android在程序中使用界面
- android 蓝牙编程重点---如何发送和接收16进制数据
- Android源码下载和编译总结
- Android Studio 配置 gradle 脚本错误:Gradle DSL method not found: 'minus()
- 安卓 jni 开发之 native 方法的动态注册