首页 文章 精选 留言 我的

精选列表

搜索[笔记工具],共10000篇文章
优秀的个人博客,低调大师

DLNA&UPnP开发笔记(2)

1. UPnP协议组成 UPnP协议中,定义了两个主要的组件,一个是设备(Device),一个是控制点(Control Point)。这就是为什么很多UPnP协议栈的SDK的接口代码一般都主要由Device和Control Point构成。设备是在网络中可见的对象,而控制点在网络中不可见。 一个UPnP的设备(Device)是不能直接访问和控制另一个UPnP的设备(Device)的,对设备的访问和控制都必须通过控制点(Control Point)来代为完成。而控制点对设备的控制则主要是由设备定义的“服务”(Service)来实现。 设备(Device)需要向网络中广播自己的信息,并提供设备描述和服务(Service)描述,并发送设备事件消息. 控制点(Control Point)则是搜索设备,并使用其提供的服务(Service)访问和控制设备,同时监听设备事件消息。 2. 典型的UPnP AV应用架构 如图所示是一种典型的UPnP AV应用架构,它来自《UPnP-av-AVArchitecture》。在一个典型的UPnP应用中,有三个主体,一个服务器(MediaServer),一个播放器(MediaRender),以及一个控制点(Control Point)。 服务器(MediaServer)主要负责提供多媒体文件的浏览和控制。 播放器(MediaRender)主要负责提供播放和渲染。 控制点(Control Point)则控制整个播放过程。 它们三个在物理上可以是同一个设备,当然,也可以在不同的设备上。 对应到UPnP协议组件的话,“MediaServer”和“MediaRnederer”都属于UPnP的Device。 “ContentDirectory”、“ConnectionManager”、“AVTransport”、“RenderingControl”这些都属于UPnP设备所提供的服务(Service),通过这些服务描述,Control Point就知道该如何访问和控制设备了。 3. UPnP的设备描述和服务描述 UPnP的设备(Device)是通过广播包来通知局域网中的控制点自己的设备信息和服务的,而这些设备信息和服务都必须根据UPnP协议规定的XML文档格式来编写,UPnP提供了标准的模板可以参考,具体的文档地址: http://upnp.org/sdcps-and-certification/standards/sdcps/ 由这些文档我们可以看到,UPnP官网为我们定义了12种设备,在每种设备的文档中详细地定义了设备描述XML如何编写,定义了每种设备需要实现哪些服务,每种服务的XML文档如何编写。 到这里,我们其实可以看到,实现一个上述的UPnP AV应用也并没有那么可怕,一切都是有章可循的,我们需要做的就是熟读协议所定义了一系列文档。 本文转自 Jhuster 51CTO博客,原文链接:http://blog.51cto.com/ticktick/1637727,如需转载请自行联系原作者

优秀的个人博客,低调大师

[Hadoop In Action]学习笔记-Hadoop中的Streaming

Hadoop支持非java预言来编写程序,这就会用到Streaming的通用API。 Hadoop Streaming使用流与程序进行交互。从STDIN输入数据,输出到STDOUT。数据必须为文本,而且每一行被视为一条记录。 用Streaming处理键-值 默认情况下,Streaming使用制表符分离记录中的键与值。当没有制表符时,整个记录被视为键,而值为空白文本。 Streaming API把reducer输出的每一行用制表符分开,并将键值对送入默认的TextOutputFormat中,即在结果被写入文件之前,默认的重新插入一个制表符 本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/838607,如需转载请自行联系原作者

优秀的个人博客,低调大师

openstack学习笔记八 glance安装配置

镜像 安装过系统的虚拟硬盘 管理是用glance来完成。 镜像的状态: active 镜像已经上传完成,并且是可用的 saving 正在被上传,还没有完成 killed 上传出错 queued 并没有真的上传完成,但是被标记有这个镜像 安装glance 在 keystone注册 glance所需要的账户 创建glance服务 指定glance服务的endpoint 安装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@h4~] #yum-yinstallopenstack-glance.noarch [root@h4~] #openstack-db--init--serviceglance--password123456-rootpw123456 [root@h4~(keystone_admin)] #keystoneuser-create--nameglance--pass123456 [root@h4~(keystone_admin)] #keystoneuser-role-add--userglance--tenantservices--roleadmin [root@h4~(keystone_admin)] #keystoneservice-create--nameglance--typeimage--description"glancejingxiang" [root@h4~(keystone_admin)] #keystoneendpoint-create--service-id3d0969b633044029a895da1ca2855464--publicurl'http://192.168.1.204:9292'--internalurl'http://192.168.1.204:9292'--adminurl'http://192.168.1.204:9292' +-------------+----------------------------------+ |Property|Value| +-------------+----------------------------------+ |adminurl|http: //192 .168.1.204:9292| | id |e0f7718b18444f71a43762ca3336ef06| |internalurl|http: //192 .168.1.204:9292| |publicurl|http: //192 .168.1.204:9292| |region|regionOne| |service_id|3d0969b633044029a895da1ca2855464| +-------------+----------------------------------+ 修改配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 [root@h4glance(keystone_admin)] #systemctllist-unit-files|grepglanc openstack-glance-api.servicedisabled接受用户的请求 openstack-glance-registry.servicedisabled和数据库进行交互 openstack-glance-scrubber.servicedisabled和其他接口进行交互 [root@h4glance(keystone_admin)] #ls glance-api.confglance-registry.confmetadefsschema-image.json glance-cache.confglance-scrubber.confpolicy.json [root@h4glance(keystone_admin)] #cd/usr/share/glance/模板 [root@h4glance(keystone_admin)] #ls glance-api-dist.confglance-registry-dist.conf glance-api-dist- paste .iniglance-registry-dist- paste .ini glance-cache-dist.confglance-scrubber-dist.conf [root@h4glance(keystone_admin)] #cpglance-api-dist.conf/etc/glance/glance-api.conf##拷贝模板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 [root@h4glance(keystone_admin)] #vimglance-api.conf [DEFAULT] debug=False verbose=True use_stderr=False log_file= /var/log/glance/api .log filesystem_store_datadir= /var/lib/glance/images/ scrubber_datadir= /var/lib/glance/scrubber image_cache_dir= /var/lib/glance/image-cache/ rabbit_host=192.168.1.204 rabbit_port=5672 rabbit_hosts=$rabbit_host:$rabbit_port rabbit_use_ssl= false rabbit_userid=guest rabbit_password=guest rabbit_login_method=AMQPLAIN [database] connection=mysql: //glance :123456@192.168.1.204 /glance [keystone_authtoken] admin_tenant_name=services admin_user=glance admin_password=123456 auth_host=192.168.1.204 auth_port=35357 auth_protocol=http auth_uri=http: //192 .168.1.204:5000/ [paste_deploy] config_file= /usr/share/glance/glance-api-dist-paste .ini flavor=keystone 1 2 3 [root@h4glance] #chownroot.glanceglance-api.conf [root@h4glance] #systemctlstartopenstack-glance-api.serviceopenstack-glance-registry.serviceopenstack-glance-scrubber.service [root@h4glance] #systemctlenableopenstack-glance-api.serviceopenstack-glance-registry.serviceopenstack-glance-scrubber.service 管理 1 2 3 4 5 6 7 8 9 10 11 [root@h4~(keystone_admin)] #glanceimage-list +----+------+ |ID|Name| +----+------+ +----+------+ [root@h4~(keystone_admin)] #glancehelpimage-create ##########################先上传一个镜像再创建 [root@h4~(keystone_admin)] #glanceimage-create--namehequan--filehequan.img--disk-formatqcow2--visibilitypublice--container-formatbare##创建 [root@h4~(keystone_admin)] #glanceimage-create--namehequan--os-distrohttp://mirrors.163.com/centos/7.2.1511/isos/x86_64/CentOS-7-x86_64-Minimal-1511.iso--disk-formatiso--container-formatbare filesystem_store_datadir= /var/lib/glance/images/ ###镜像保存的位置 #default_store=file 修改镜像存储位置 swift 做后端存储 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 6 #filesystem_store_datadir=/var/lib/glance/images/##先禁用 [glance_store] default_store=swift默认为 file 改为swift stores= file ,http默认不用动 swift_store_auth_version=2默认版本为2 stores=glance.store.swift.Store,glance.store.filesystem.Store此项一定要加上,不然无法上传 swift_store_auth_address=http: //192 .168.1.204:5000 /v2 .0/controller的keystone认证 swift_store_user=service:swift使用swift用户 swift_store_key=hequan密码 swift_store_container=glance将要被创建的容器 swift_store_create_container_on_put=True上传开 swift_store_large_object_size=5120最大5G限制,但与glance结合后限制无效 swift_store_large_object_chunk_size=200最大200个容器 swift_enable_snet=False [root@h4glance(keystone_admin)] #systemctlrestartopenstack-glance-api.serviceopenstack-glance-registry.serviceopenstack-glance-scrubber.service ceph 共享存储 安装epel仓库 1 2 3 4 5 6 7 8 9 10 11 12 rpm-vihhttp: //mirrors .sohu.com /fedora-epel/7/x86_64/e/epel-release-7-2 .noarch.rpm 添加yumceph仓库 vim /etc/yum .repos.d /ceph .repo [ceph] name=Cephnoarchpackages baseurl=http: //mirrors .163.com /ceph/rpm-hammer/el7/x86_64/ enabled=1 gpgcheck=1 type =rpm-md gpgkey=http: //mirrors .163.com /ceph/keys/release .asc 安装ceph-deploy,ceph(ceph所有节点都安装,ceph-deploy只需admin节点安装) yum-yupdate&&yum-y install --releasehammercephceph-deploy 1 生成相关的MOD信息 监控服务器 h5 1 2 3 [root@h5xx] #ceph-deploynewh5 [root@h5xx] #ls ceph.confceph-deploy-ceph.logceph.mon.keyring 2 要根据自己的情况修改配置文件ceph.conf 1 2 osd_pool_default_size=2 ##几个节点组成,默认是3 osd_pool_defaults_min_size=1 ##最小值是1 3 生成key 当客户端要链接到ceph服务器,需要用户名和密码 1 2 3 4 5 [root@h5xx] #ceph-deploymoncreate-initial [root@h5myceph] #ls ceph.bootstrap-mds.keyringceph.client.admin.keyringceph.mon.keyring ceph.bootstrap-osd.keyringceph.conf ceph.bootstrap-rgw.keyringceph.log 4 开始准备配置OSD 1 2 3 4 mkdir path1path2 [root@h5xx] #ceph-deployosdprepareh5:/path1h6:/path2 [root@h5xx] #ceph-deployosdactivateh5:/path1h6:/path2##激活 [ceph_deploy.osd][DEBUG]Hosth5isnowready for osduse. 5 把key复制到各个节点上去 1 2 [root@h5ceph] #ceph-deployadminh5h6 [root@h5ceph] #cephhealth##健康性检查 6 生成元数据 1 2 3 4 [root@h5ceph] #ceph-deploymdscreateh5 [root@h5ceph] #radoslspools [root@h5ceph] #radosmkpoolglance [root@h5ceph] #radosrmpoolglanceglance--yes-i-really-really-mean-it##删除 glance配置成ceph的客户端 安装ceph 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@h4ceph(keystone_admin)] #ls rbdmap [root@h5myceph] #ceph-deployadminh4 [root@h4ceph(keystone_admin)] #ls ceph.client.admin.keyringceph.confrbdmaptmp6BxOoY vimglance-api.conf [glance_store] default_store=rbd stores=rbd rbd_store_pool=glance rbd_store_user=admin rbd_store_ceph_conf= /etc/ceph/ceph .conf rbd_store_chunk_size=8 systemctlrestartopenstack-glance-api.serviceopenstack-glance-registry.serviceopenstack-glance-scrubber.service -rw-------1rootroot637月2116:43ceph.client.admin.keyring setfacl-mu:glance:r--ceph.client.admin.keyring ##设置权限能读 制作镜像 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 yum-ygroupinstall "ServerwithGUI" yum install virt-managerpython-virtinstqemu-kvm-toolsqemu-kvmlibvirt KVM 创建存储卷centos.qcow2 基本安装 配置网卡删除MAC 安装基本组件openssh-clients cloud-init ##云包 [root@h4~] #vim/etc/default/grub GRUB_CMDLINE_LINUX= "net.ifnames=0biosdevname=0console=tty0console=ttyS0,115200n8rhgbquiet" ##指定串口的参数 [root@h4~] #grub2-mkconfig-o/boot/grub2/grub.cfg 封装 [root@h5~] #yumwhatprovides*/virt-sysprep [root@h5~] #yum-yinstalllibguestfs-bash-completion-1.28.1-1.55.el7.centos.noarch [root@h4~] #virt-sysprep-dcentos [root@h4~] #cd/openstack-image/ [root@h4openstack-image] #qemu-imginfocentos.qcow2 qemu-imgconver-c-oqcow2centos.qcow2newcentos.qcow2 ###3压缩命令 本文转自 295631788 51CTO博客,原文链接:http://blog.51cto.com/hequan/1828592,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android开发学习笔记:Spinner和AutoCompleteTextView浅析

一.Spinner的简介与创建 1.Spinner的简介 Spinner(下拉列表)是一个每次只能选择所有项中一项的控件,相当于Html中的下拉列表框。它的继承关系如下: java.lang.Object ↳ android.view.View ↳ android.view.ViewGroup ↳ android.widget.AdapterView<T extends android.widget.Adapter> ↳ android.widget.AbsSpinner ↳ android.widget.Spinner Spinner常用的XML属性: 属性名称 描述 android:prompt 该提示在下拉列表对话框显示时显示。(译者注:对话框的标题: 2.创建使用Spinner的步骤如下: ①需要在布局中定时Spinner组件,然后向Spinner添加需要选择的数据 ②设置事件监听器setOnItemSelectedListener( )并实现onItemSelected( ) 3.Spinner添加数据的两种方法: ①在Java代码中载入列表数据 具体的例子如下: MainActivity.java packagecom.android.spinner; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.ArrayAdapter; importandroid.widget.Spinner; importandroid.widget.TextView; publicclassMainActivityextendsActivity{ privatestaticfinalString[]province={"广东","广西","湖南","河南","福建"}; privateTextViewtext; privateSpinnerspinner; privateArrayAdapter<String>adapter; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); text=(TextView)findViewById(R.id.text); spinner=(Spinner)findViewById(R.id.spinner); //将Spinner里面的可选择内容通过ArrayAdapter连接起来 adapter=newArrayAdapter<String>(this,android.R.layout.simple_spinner_item,province); //设置Spinner的样式 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //为对话框设置标题 //也可在XMl文件中通过“android:prompt”设置 spinner.setPrompt("你来自哪个省"); //为Spinner设置适配器 spinner.setAdapter(adapter); //添加Spinner事件监听 spinner.setOnItemSelectedListener(newSpinner.OnItemSelectedListener(){ @Override publicvoidonItemSelected(AdapterView<?>arg0,Viewarg1, intarg2,longarg3){ //TODOAuto-generatedmethodstub text.setText("你所在的城市是:"+province[arg2]); //设置显示当前选择的项 arg0.setVisibility(View.VISIBLE); } @Override publicvoidonNothingSelected(AdapterView<?>arg0){ //TODOAuto-generatedmethodstub } }); } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="10dip" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="@string/planet_prompt" /> <Spinner android:id="@+id/spinner" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> strings.xml <?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="planet_prompt">你来自的省份是:</string> <stringname="app_name">测试Spinner</string> </resources> 效果图: ②在XML文件中定义列表的数据 具体的例子如下: MainActivity.java packagecom.android.spinner; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.AdapterView.OnItemSelectedListener; importandroid.widget.ArrayAdapter; importandroid.widget.Spinner; importandroid.widget.Toast; publicclassMainActivityextendsActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); Spinnerspinner=(Spinner)findViewById(R.id.spinner); ArrayAdapter<CharSequence>adapter=ArrayAdapter.createFromResource( this,R.array.province, android.R.layout.simple_spinner_item); //调用setDropDownViewResource方法,以XML的方式定义下拉菜单要显示的样式 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //为spinner设置适配器 spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(newMyOnItemSelectedListener()); } publicclassMyOnItemSelectedListenerimplementsOnItemSelectedListener{ publicvoidonItemSelected(AdapterView<?>parent,Viewview,intpos,longid){ Toast.makeText(parent.getContext(),"你来自的省份是:"+ parent.getItemAtPosition(pos).toString(),Toast.LENGTH_LONG).show(); } publicvoidonNothingSelected(AdapterView<?>parent){ //TODOAuto-generatedmethodstub } } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="10dip" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="@string/planet_prompt" /> <Spinner android:id="@+id/spinner" android:layout_width="fill_parent" android:layout_height="wrap_content" android:prompt="@string/planet_prompt" /> </LinearLayout> strings.xml <?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="planet_prompt">你来自的省份是</string> <stringname="app_name">测试Spinner</string> <string-arrayname="province"> <item>广东</item> <item>广西</item> <item>湖南</item> <item>河南</item> <item>福建</item> </string-array> </resources> 效果图: 二.AutoCompleteTextView简介 我们平常上网的时候经常会用到Google或百度,在输入框中输入类似”51CTO“,和51CTO相关的信息就会被列出来,供用户选择,非常方便。这种效果在Android中是用AutoCompleteTextView实现的。在AutoCompleteTextView中,主要是设置想显示资源的适配器(Adapter)。 AutoCompleteTextView有三个重要的方法clearListSelection():清除选中的列表项、dismissDropDown():如果存在关闭下拉菜单、getAdapter():获取适配器。 具体的例子如下: MainActivity.java packagecom.android.autocomplete; importandroid.app.Activity; importandroid.os.Bundle; importandroid.widget.ArrayAdapter; importandroid.widget.AutoCompleteTextView; publicclassMainActivityextendsActivity{ privateAutoCompleteTextViewatv; //创建字符串数组 privatestaticfinalString[]strs={"an","and","android","abc","abcdef"}; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); atv=(AutoCompleteTextView)findViewById(R.id.AutoCompleteTextView1); //创建适配器 ArrayAdapter<String>adapter=newArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line,strs); //为AutoCompleteTextView设置适配器 atv.setAdapter(adapter); } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="自动完成文本框" /> <AutoCompleteTextView android:id="@+id/AutoCompleteTextView1" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> 效果图: 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/652801

优秀的个人博客,低调大师

Android开发学习笔记:Notification和NotificationManager浅析

NotificationManager 获取NotificationManager String service = Context.NOTIFICATION_SERVICE; NotificationManager mNotificationManager =(NotificationManager)getSystemService(service); Notification //实例化Notification Notificationnotification=newNotification(); 3.设置Notification的属性 //设置显示图标,该图标会在状态栏显示 inticon=notification.icon=R.drawable.happy; //设置显示提示信息,该信息也在状态栏显示 StringtickerText="测试Notification"; //显示时间 longwhen=System.currentTimeMillis();notification.icon=icon; notification.tickerText=tickerText; notification.when=when; //也可以这样设置 Notificationnotification_2=newNotification(icon,tickerText,when) 调用setLatestEventInfo()方法在视图中设置图标和时间。 //实例化Intent Intentintent=newIntent(MainActivity.this,MainActivity.class); //获得PendingIntent PendingIntentpIntent=PendingIntent.getActivity(MainActivity.this,0,intent,0); //设置事件信息 notification.setLatestEventInfo(MainActivity.this,"Title","Content",pIntent); 4.发出通知 //Notification标示ID privatestaticfinalintID=1; //发出通知 mNotificationManager.notify(ID,n); 下面是具体的例子,在这个例子里定义了一个MainActivity发出广播通知,定义一个MyReceiver类继承Broadcasts接受通知,当接收完通知之后,启动一个SecondActivity,在SecondActivity类中通过Notification和NotificationManager来可视化显示广播通知。具体的步骤如下: MainActivity.java packagecom.android.notification; importandroid.app.Activity; importandroid.content.Intent; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; publicclassMainActivityextendsActivity{ //声明Button privateButtonbtn; //定义BroadcastReceiveraction privatestaticfinalStringMY_ACTION="com.android.notification.MY_ACTION"; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //设置当前布局视图 setContentView(R.layout.main); //实例化Button btn=(Button)findViewById(R.id.Button1); //添加事件监听器 btn.setOnClickListener(listener); } //创建事件监听器 privateOnClickListenerlistener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ //实例化Intent Intentintent=newIntent(); //设置Intentaction属性 intent.setAction(MY_ACTION); //发起广播 sendBroadcast(intent); } }; } MyReceiver.java packagecom.android.notification; importandroid.content.BroadcastReceiver; importandroid.content.Context; importandroid.content.Intent; publicclassMyReceiverextendsBroadcastReceiver{ @Override publicvoidonReceive(Contextcontext,Intentintent){ //实例化Intent Intenti=newIntent(); //在新的任务中启动Activity i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //设置Intent启动的组件名称 i.setClass(context,SecondActivity.class); //启动Activity显示通知 context.startActivity(i); } } SecondActivity.java packagecom.android.notification; importandroid.app.Activity; importandroid.app.Notification; importandroid.app.NotificationManager; importandroid.app.PendingIntent; importandroid.content.Intent; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; publicclassSecondActivityextendsActivity{ //声明按钮 privateButtoncancelBtn; //声明Notification privateNotificationnotification; //声明NotificationManager privateNotificationManagermNotification; //Notification标示ID privatestaticfinalintID=1; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.second); //实例化按钮 cancelBtn=(Button)findViewById(R.id.cancelButton2); //获得NotificationManager实例 Stringservice=NOTIFICATION_SERVICE; mNotification=(NotificationManager)getSystemService(service); //实例化Notification notification=newNotification(); //设置显示图标,该图标会在状态栏显示 inticon=notification.icon=android.R.drawable.stat_notify_chat; //设置显示提示信息,该信息也会在状态栏显示 StringtickerText="TestNotification"; //显示时间 longwhen=System.currentTimeMillis(); notification.icon=icon; notification.tickerText=tickerText; notification.when=when; //实例化Intent Intentintent=newIntent(this,MainActivity.class); //获得PendingIntent PendingIntentpi=PendingIntent.getActivity(this,0,intent,0); //设置事件信息 notification.setLatestEventInfo(this,"消息","HelloAndroid",pi); //发出通知 mNotification.notify(ID,notification); //为按钮添加监听器 cancelBtn.setOnClickListener(cancelListener); } //取消通知监听器 privateOnClickListenercancelListener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ //取消通知 mNotification.cancel(ID); } }; } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:text="发出广播通知" android:id="@+id/Button1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> second.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:text="显示通知界面" android:id="@+id/TextView1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="取消通知" android:id="@+id/cancelButton2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 在AndroidManifest.xml文件中16~21加入对receiver,SecondActivity的声明 <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.android.notification" android:versionCode="1" android:versionName="1.0"> <uses-sdkandroid:minSdkVersion="10"/> <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> <activityandroid:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <receiverandroid:name="MyReceiver"> <intent-filter> <actionandroid:name="com.android.notification.MY_ACTION"/> </intent-filter> </receiver> <activityandroid:name="SecondActivity"/> </application> </manifest> 效果图: Notification丰富的提示方式: 声音提醒 ·使用默认声音 notification.defaults |= Notification.DEFAULT_SOUND; ·使用自定义声音 notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3"); ·注:如果定义了默认声音,那么自定义声音将被覆盖 振动提醒 ·使用默认振动 notification.defaults |= Notification.DEFAULT_VIBRATE; ·使用自定义振动 long[] vibrate = {0,100,200,300};notification.vibrate = vibrate; ·注:如果定义了默认振动,那么自定义振动将被覆盖 灯光闪烁提醒 ·使用默认闪烁 notification.defaults |= Notification.DEFAULT_LIGHTS; ·使用自定义闪烁 notification.ledARGB = 0xff00ff00;// LED灯的颜色,绿灯notification.ledOnMS = 300;// LED灯显示的毫秒数,300毫秒notification.ledOffMS = 1000;// LED灯关闭的毫秒数,1000毫秒notification.flags |= Notification.FLAG_SHOW_LIGHTS; // 必须加上这个标志 更多特性 可以通过 Notification 的相关字段或标志(flags)为提醒设置更多的特性。 ·FLAG_AUTO_CANCEL标志:当提醒被用户点击之后会自动被取消(cancel); ·FLAG_INSISTENT标志:在用户响应之前会一直重复提醒音; ·FLAG_ONGOING_EVENT标志:Add this to theflagsfield to group the notification under the "Ongoing" title in the Notifications window. ·FLAG_NO_CLEAR标志:当在提醒栏中点击“清除提醒”按钮时,该提醒将不会被清除; ·number字段:This value indicates the current number of events represented by the notification. The appropriate number is overlaid on top of the status bar icon. If you intend to use this field, then you must start with "1" when the Notification is first created. (If you change the value from zero to anything greater during an update, the number is not shown.) ·iconLevel字段:This value indicates the current level of aLevelListDrawablethat isused for the notification icon. You can animate the icon in the status bar by changingthis value to correlate with the drawable's defined in a LevelListDrawable. ·contentView字段:To define your own layout for the expanded message, instantiate a RemoteViews object and pass it to thecontentViewfield of your Notification. Pass the PendingIntent to thecontentIntentfield. 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/657502

优秀的个人博客,低调大师

Android开发学习笔记:TextView的属性详解

android:autoLink :设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接。可选值(none/web /email/phone/map/all) android:autoText :如果设置,将自动执行输入值的拼写纠正。此处无效果,在显示输入法并输入的时候起作用。 android:bufferType : 指定getText()方式取得的文本类别。选项editable 类似于StringBuilder :可追加字符,也就是说getText后可调用append方法设置文本内容。spannable :则可在给定的字符区域使用样式,参见这里1、这里2。 android:capitalize :设置英文字母大写类型。此处无效果,需要弹出输入法才能看得到,参见EditView此属性说明。 android:cursorVisible:设定光标为显示/隐藏,默认显示。 android:digits:设置允许输入哪些字符。如“1234567890.+-*/% ()” android:drawableBottom:在text的下方输出一个drawable,如图片。如果指定一个颜色的话会把text的背景设为该颜色,并且同时和background使用时覆盖后者。 android:drawableLeft:在text的左边输出一个drawable,如图片。 android:drawablePadding:设置text与drawable(图片)的间隔,与drawableLeft、 drawableRight、drawableTop、drawableBottom一起使用,可设置为负数,单独使用没有效果。 android:drawableRight:在text的右边输出一个drawable。 android:drawableTop:在text的正上方输出一个drawable。 android:editable:设置是否可编辑。 android:editorExtras:设置文本的额外的输入数据。 android:ellipsize:设置当文字过长时,该控件该如何显示。有如下值设置:”start”—?省略号显示在开头;”end” ——省略号显示在结尾;”middle”—-省略号显示在中间;”marquee” ——以跑马灯的方式显示(动画横向移动) android:freezesText:设置保存文本的内容以及光标的位置。 android:gravity:设置文本位置,如设置成“center”,文本将居中显示。 android:hintText:为空时显示的文字提示信息,可通过textColorHint设置提示信息的颜色。此属性在 EditView中使用,但是这里也可以用。 android:imeOptions:附加功能,设置右下角IME动作与编辑框相关的动作,如actionDone右下角将显示一个“完成”,而不设置默认是一个回车符号。这个在EditView中再详细说明,此处无用。 android:imeActionId:设置IME动作ID。 android:imeActionLabel:设置IME动作标签。 android:includeFontPadding:设置文本是否包含顶部和底部额外空白,默认为true。 android:inputMethod:为文本指定输入法,需要完全限定名(完整的包名)。例如:com.google.android.inputmethod.pinyin,但是这里报错找不到。 android:inputType:设置文本的类型,用于帮助输入法显示合适的键盘类型。在EditView中再详细说明,这里无效果。 android:linksClickable:设置链接是否点击连接,即使设置了autoLink。 android:marqueeRepeatLimit:在ellipsize指定marquee的情况下,设置重复滚动的次数,当设置为 marquee_forever时表示无限次。 android:ems:设置TextView的宽度为N个字符的宽度。这里测试为一个汉字字符宽度 android:maxEms:设置TextView的宽度为最长为N个字符的宽度。与ems同时使用时覆盖ems选项。 android:minEms:设置TextView的宽度为最短为N个字符的宽度。与ems同时使用时覆盖ems选项。 android:maxLength:限制显示的文本长度,超出部分不显示。 android:lines:设置文本的行数,设置两行就显示两行,即使第二行没有数据。 android:maxLines:设置文本的最大显示行数,与width或者layout_width结合使用,超出部分自动换行,超出行数将不显示。 android:minLines:设置文本的最小行数,与lines类似。 android:lineSpacingExtra:设置行间距。 android:lineSpacingMultiplier:设置行间距的倍数。如”1.2” android:numeric:如果被设置,该TextView有一个数字输入法。此处无用,设置后唯一效果是TextView有点击效果,此属性在EdtiView将详细说明。 android:password:以小点”.”显示文本 android:phoneNumber:设置为电话号码的输入方式。 android:privateImeOptions:设置输入法选项,此处无用,在EditText将进一步讨论。 android:scrollHorizontally:设置文本超出TextView的宽度的情况下,是否出现横拉条。 android:selectAllOnFocus:如果文本是可选择的,让他获取焦点而不是将光标移动为文本的开始位置或者末尾位置。 TextView中设置后无效果。 android:shadowColor:指定文本阴影的颜色,需要与shadowRadius一起使用。 android:shadowDx:设置阴影横向坐标开始位置。 android:shadowDy:设置阴影纵向坐标开始位置。 android:shadowRadius:设置阴影的半径。设置为0.1就变成字体的颜色了,一般设置为3.0的效果比较好。 android:singleLine:设置单行显示。如果和layout_width一起使用,当文本不能全部显示时,后面用“…”来表示。如android:text="test_ singleLine " android:singleLine="true" android:layout_width="20dp"将只显示“t…”。如果不设置singleLine或者设置为false,文本将自动换行 android:text:设置显示文本. android:textAppearance:设置文字外观。如 “?android:attr/textAppearanceLargeInverse”这里引用的是系统自带的一个外观,?表示系统是否有这种外观,否则使用默认的外观。可设置的值如下:textAppearanceButton/textAppearanceInverse/textAppearanceLarge/textAppearanceLargeInverse/textAppearanceMedium/textAppearanceMediumInverse/textAppearanceSmall/textAppearanceSmallInverse android:textColor:设置文本颜色 android:textColorHighlight:被选中文字的底色,默认为蓝色 android:textColorHint:设置提示信息文字的颜色,默认为灰色。与hint一起使用。 android:textColorLink:文字链接的颜色. android:textScaleX:设置文字之间间隔,默认为1.0f。 android:textSize:设置文字大小,推荐度量单位”sp”,如”15sp” android:textStyle:设置字形[bold(粗体) 0, italic(斜体) 1, bolditalic(又粗又斜) 2] 可以设置一个或多个,用“|”隔开 android:typeface:设置文本字体,必须是以下常量值之一:normal 0, sans 1, serif 2, monospace(等宽字体) 3] android:height:设置文本区域的高度,支持度量单位:px(像素)/dp/sp/in/mm(毫米) android:maxHeight:设置文本区域的最大高度 android:minHeight:设置文本区域的最小高度 android:width:设置文本区域的宽度,支持度量单位:px(像素)/dp/sp/in/mm(毫米),与layout_width 的区别看这里。 android:maxWidth:设置文本区域的最大宽度 android:minWidth:设置文本区域的最小宽度 附件:Android中的长度单位详解 Android中的长度单位详解(dp、sp、px、in、pt、mm)有很多人不太理解dp、sp 和px 的区别:现在这里介绍一下dp 和sp。dp 也就是dip。这个和sp 基本类似。如果设置表示长度、高度等属性时可以使用dp 或sp。但如果设置字体,需要使用sp。dp 是与密度无关,sp 除了与密度无关外,还与scale 无关。如果屏幕密度为160,这时dp 和sp 和px 是一样的。1dp=1sp=1px,但如果使用px 作单位,如果屏幕大小不变(假设还是3.2 寸),而屏幕密度变成了320。那么原来TextView 的宽度设成160px,在密度为320 的3.2 寸屏幕里看要比在密度为160 的3.2 寸屏幕上看短了一半。但如果设置成160dp 或160sp 的话。系统会自动将width 属性值设置成320px 的。也就是160 * 320 / 160。其中320 / 160 可称为密度比例因子。也就是说,如果使用dp 和sp,系统会根据屏幕密度的变化自动进行转换。 其他单位的含义 px:表示屏幕实际的象素。例如,320*480 的屏幕在横向有320个象素,在纵向有480 个象素。 in:表示英寸,是屏幕的物理尺寸。每英寸等于2.54 厘米。例如,形容手机屏幕大小,经常说,3.2(英)寸、3.5(英)寸、4(英)寸就是指这个单位。这些尺寸是屏幕的对角线长度。如果手机的屏幕是3.2 英寸,表示手机的屏幕(可视区域)对角线长度是3.2*2.54 = 8.128 厘米。读者可以去量一量自己的手机屏幕,看和实际的尺寸是否一致。 mm:表示毫米,是屏幕的物理尺寸。 pt:表示一个点,是屏幕的物理尺寸。大小为1 英寸的1/72。 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/627123

优秀的个人博客,低调大师

Android开发学习笔记:手机震动控制浅析

Android系统中Vibrator对象负责对手机震动的处理,具体的实现方法: 1.获取振动器Vibrator的实例: Vibratorvibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE); getSystemService(VIBRATOR_SERVICE):获得一个震动的服务 2.调用vibrate方法来产生震动: 只向vibrate()传递一个参数,这个参数用来指定振动的毫秒数 //震动5秒 vibrator.vibrate(5000); 向vibrate()方法传递多个参数 //等待1秒,震动2秒,等待1秒,震动3秒 long[]pattern={1000,2000,1000,3000}; //-1表示不重复,如果不是-1,比如改成1,表示从前面这个long数组的下标为1的元素开始重复. vibrator.vibrate(pattern,-1); 3.取消震动 vibrator.cancel(); 4.在AndroidManifest.xml文件添加权限 <uses-permissionandroid:name="android.permission.VIBRATE"/> 下面的实例包含了产生震动的两个方法 VibratorDemoActivity.java packagecom.lingdududu.test; importandroid.app.Activity; importandroid.os.Bundle; importandroid.os.Vibrator; importandroid.view.MotionEvent; /* *@authorlingdududu *当程序开始运行结束时,手机等待1秒就开始震动2秒,再等待1秒,开始震动3秒 *当我们点击手机屏幕,触发onTouchEvent事件,手机就开始震动1秒 */ publicclassVibratorDemoActivityextendsActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); Vibratorvibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE); long[]pattern={1000,2000,1000,3000};//OFF/ON/OFF/ON...... vibrator.vibrate(pattern,-1); } @Override publicbooleanonTouchEvent(MotionEventevent){ if(event.getAction()==MotionEvent.ACTION_MOVE){ Vibratorvibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE); vibrator.vibrate(1000); } returnsuper.onTouchEvent(event); } } 注:记得在AndroidManifest.xml文件添加权限,还有程序要在真机上运行才能有震动的效果,模拟器上不支持震动的。 PS:我正在参加IT博客大赛,欢迎大家来投我一票的 http://blog.51cto.com/contest2011/3061169 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/724042

优秀的个人博客,低调大师

Android学习笔记(三)基础知识(2)

交互对话框 使用Android SDK中,具有交互功能的对话框是AlertDialog窗口。 package com.example.test8; import android.os.Bundle; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { private Button bt; int n=0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt=(Button)findViewById(R.id.button1); bt.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub n++; String str=Integer.toString(n); bt.setText("点击次数:"+n); new AlertDialog.Builder(MainActivity.this) .setTitle("提示") .setMessage("对话框") .setPositiveButton("确定",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } } ) .show(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } } 拖放相片特效 在Android中,拖动图片的特效可以通过Android.content.Context,Android,widget.BaseAdapter和Android.widget.imageView等来实现。 在下面的列子中,context可以像画布一样,随时可以被处理覆盖。Context是作为Android.content子类。通过widget.BaseAdapter作为容器来存放Gallery所需要的图片。 这里是通过使用Gallery实现的相片拖拽功能,具体代码如下: package com.example.test9; import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Gallery; import android.widget.ImageView; import android.widget.TextView; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { private TextView textview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textview = (TextView)findViewById(R.id.textView1); textview.setText("特效演示"); textview.setTextColor(Color.BLUE); Gallery gallery=(Gallery)findViewById(R.id.gallery1); gallery.setAdapter(new ImageAdapter(this)); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } public class ImageAdapter extends BaseAdapter{ private Context myContext; private int[] myImageID={android.R.drawable.btn_minus, android.R.drawable.btn_radio, android.R.drawable.ic_lock_idle_low_battery, android.R.drawable.ic_menu_camera }; public ImageAdapter(Context c){ this.myContext=c; } public int getCount() { // TODO Auto-generated method stub return this.myImageID.length; } public Object getItem(int position) { // TODO Auto-generated method stub return position; } public long getItemId(int position) { // TODO Auto-generated method stub return position; } public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub ImageView i=new ImageView(this.myContext); i.setImageResource(this.myImageID[position]); i.setScaleType(ImageView.ScaleType.FIT_XY); i.setLayoutParams(new Gallery.LayoutParams(120,120)); return i; } } } 设置about关于信息 创建一个onCreateOptionsMenu(Menu menu)类函数,用于添加Menu菜单项,再利用onOptionItemSelected选择菜单项 package com.example.test10; import android.os.Bundle; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.view.Menu; import android.view.MenuItem; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0,0,0,"关于"); menu.add(0,1,1,"退出"); return super.onCreateOptionsMenu(menu); } public boolean onOptionsItemSelected(MenuItem item){ super.onOptionsItemSelected(item); switch(item.getItemId()){ case 0: openOptionsDialog(); break; case 1: finish(); } return true; } private void openOptionsDialog(){ new AlertDialog.Builder(this) .setTitle("关于") .setMessage("***") .setPositiveButton("OK",new OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }) .show(); } } 程序加载中状态框 程序加载中的提示,此功能是通过Progress Dialog类来运行,此类在Android.app.ProgressDialog类里。但是,我们需要注意使用dismiss()函数来关闭取得焦点的对话框,否则程序将陷入死循环,也不能在线程里更改CONTEXT或parent view的任何状态。 package com.example.test11; import android.os.Bundle; import android.app.Activity; import android.app.ProgressDialog; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { private TextView text; private Button bt; public ProgressDialog myDialog=null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text=(TextView)findViewById(R.id.textView1); bt=(Button)findViewById(R.id.button1); bt.setOnClickListener(myShowProgressBar); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } Button.OnClickListener myShowProgressBar=new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub final CharSequence strDialogTile="请等待"; final CharSequence strDialogBody="程序正在运行"; myDialog=ProgressDialog.show(MainActivity.this,strDialogTile,strDialogBody,true); text.setText(strDialogBody); new Thread(){ public void run(){ try{ text.setText("start"); sleep(3000); text.setText("end"); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally{ myDialog.dismiss(); } } }.start(); } }; } 本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/archive/2013/05/16/3076677.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

docker笔记(转自:陈沙克日志)

yuminstallepel-release yuminstallaxelvimgitcurlwgetlrzszgccpython-develyum*python-pip 设置docker官方repo,安装docker CE版本 yum-config-manager\ --add-repohttps://download.docker.com/linux/centos/docker-ce.repo yuminstall-ydocker-ce docker-v 配置docker mkdir/etc/systemd/system/docker.service.d tee/etc/systemd/system/docker.service.d/docker.conf<<'EOF' [Service] MountFlags=shared EOF 编辑 /usr/lib/systemd/system/docker.service #ExecStart=/usr/bin/dockerd ExecStart=/usr/bin/dockerd--insecure-registry192.168.10.139:4000 启动docker systemctldaemon-reload systemctlrestartdocker systemctlenabledocker dockerinfo registry服务器 dockerrun-d-v/opt/registry:/var/lib/registry-p5000:5000\ --restart=always--nameregistryregistry:2 监控系统 涉及很多软件,很有代表性:Prometheus,grafana,alertmanager,exporters Prometheus https://prometheus.io/docs/prometheus/latest/installation/ dockerrun-p9090:9090-v/tmp/prometheus.yml:/etc/prometheus/prometheus.yml\ prom/prometheus 本文转自yuweibing51CTO博客,原文链接:http://blog.51cto.com/yuweibing/2048204 ,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android开发学习笔记:EditText的属性介绍

EditText继承TextView,所以EditText具有TextView的属性特点,下面主要介绍一些EditText的特有的输入法的属性特点 android:layout_gravity="center_vertical":设置控件显示的位置:默认top,这里居中显示,还有bottom android:hin :Text为空时显示的文字提示信息,可通过textColorHint设置提示信息的颜色。 android:singleLine :设置单行输入,一旦设置为 true ,则文字不会自动换行。 android:gray="top" :多行中指针在第一行第一位置 et.setSelection(et.length()); :调整光标到最后一行 android:autoText :自动拼写帮助。这里单独设置是没有效果的,可能需要其他输入法辅助才行 android:capitalize :设置英文字母大写类型。设置如下值:sentences仅第一个字母大写;words每一个单词首字母大小,用空格区分单词;characters每一个英文字母都大写。 android:digits :设置允许输入哪些字符。如“1234567890.+-*/%\n()” android:singleLine :是否单行或者多行,回车是离开文本框还是文本框增加新行 android:numeric :如果被设置,该TextView接收数字输入。有如下值设置:integer正整数、signed带符号整数、decimal带小数点浮点数。 android:inputType:设置文本的类型 android:password :密码,以小点”.”显示文本 android:phoneNumber :设置为电话号码的输入方式。 android:editable :设置是否可编辑。仍然可以获取光标,但是无法输入。 android:autoLink=”all” :设置文本超链接样式当点击网址时,跳向该网址 android:textColor = "#ff8c00" :字体颜色 android:textStyle="bold" :字体, bold, italic, bolditalic android:textAlign="center" : EditText 没有这个属性,但 TextView 有 android:textColorHighlight="#cccccc" :被选中文字的底色,默认为蓝色 android:textColorHint="#ffff00" :设置提示信息文字的颜色,默认为灰色 android:textScaleX="1.5" :控制字与字之间的间距 android:typeface="monospace" :字型, normal, sans, serif, monospace android:background="@null" :空间背景,这里没有,指透明 android:layout_weight="1" :权重在控制控件显示的大小时蛮有用的。 android:textAppearance="?android:attr/textAppearanceLargeInverse" :文字外观,这里引用的是系统自带的一个外观,?表示系统是否有这种外观,否则使用默认的外观。 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/627350

优秀的个人博客,低调大师

Android笔记:存储相关,getExternalCacheDir, getExternalFilesDir,getExternalSto...

1 2 3 4 5 6 7 8 9 10 11 12 13 FilecacheDir=mContext.getExternalCacheDir(); if ( null !=cacheDir){ mCacheDirPath=cacheDir.getAbsolutePath()+ "/images/" ; } if (TextUtils.isEmpty(mCacheDirPath)){ if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){ mCacheDirPath=Environment.getExternalStorageDirectory().getPath()+ "/Android/data/com.meiyaapp.meiya/cache/images/" ; } else { Toast.makeText(mContext, "SD卡状态错误,请调整后重试哦。" ,Toast.LENGTH_SHORT).show(); } } 本文转自 glblong 51CTO博客,原文链接:http://blog.51cto.com/glblong/1699245,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android开发学习笔记:Service的远程调用

在Andorid平台中,各个组件运行在自己的进程中,他们之间是不能相互访问的,但是在程序之间是不可避免的要传递一些对象,在进程之间相互通信。为了实现进程之间的相互通信,Andorid采用了一种轻量级的实现方式RPC(Remote Procedure Call远程进程调用)来完成进程之间的通信,并且Android通过接口定义语言(Andorid Interface Definition Language ,AIDL)来生成两个进程之间相互访问的代码,例如,你在Activity里的代码需要访问Service中的一个方法,那么就可以通过这种方式来实现了。 AIDL是Android的一种接口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成 AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象。 AIDL RPC机制是通过接口来实现的,类似Windows中的COM或者Corba,但他是轻量级的,客户端和被调用实现之间是通过代理模式实现的,代理类和被代理类实现同一个接口Ibinder接口。 下面是实现Activity访问Service例子的步骤: 一.创建.aidl文件 AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。这些参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。重要的是必须导入导入除了内建类型(例如:int,boolean等)外的任何其他类型,哪怕是这些类型是在与接口相同的包中。具体的要求如下: JAVA基本数据类型不需要导入 String,List,Map和CharSequence不需要导入 使用Eclipse的ADT插件创建一个BookInfo.aidl文件,该文件有4个方法: setName(String name)设置图书的书名,setPrice(int price)设置图书的价格,setPublish(String pname)设置图书的出版社和String display()显示图书的信息. BookInfo.aidl文件 packagecom.android.aidl; //BookInfo接口 interfaceBookInfo{ voidsetName(Stringname); voidsetPrice(intprice); voidssetPublish(Stringpname); //显示图书的信息 Stringdisplay(); } 创建好BookInfo.aidl文件,系统会自动在gen目录下生成Java接口文件BookInfo.java 二.实现AIDL文件生成的JAVA接口 AIDL会生成一个和.aidl文件同名的JAVA接口文件,该接口中有一个静态抽象内部类Stub,该类中声明了AIDL文件中定义的所有方法,其中有一个重要的方法是asInterface(),该方法通过代理模式返回JAVA接口的实现我们可以定义一个实现类,BookImpl,该类继承Stub类,实现我们定义的4个方法 packagecom.android.aidl; importandroid.os.RemoteException; publicclassBookInfoImplextendsBookInfo.Stub{ //声明三个个变量 privateintprice; privateStringname,pname; //显示书名,价格,出版社 publicStringdisplay()throwsRemoteException{ return"书名:"+name+";价格:"+price+";出版社:"+price; } @Override //设置书名 publicvoidsetName(Stringname)throwsRemoteException{ //TODOAuto this.name=name; } @Override //设置价格 publicvoidsetPrice(intprice)throwsRemoteException{ //TODOAuto-generatedmethodstub this.price=price; } @Override //设置出版社 publicvoidsetPublish(Stringpname)throwsRemoteException{ //TODOAuto this.pname=pname; } } 三.向客户端暴露接口 现在已经实现了BookInfo接口,接下来要将该接口暴露给客户端调用。一般通过定义一个Service来实现,在Service的onBind()方法中返回该接口,当我们绑定该接口时调用该方法。 packagecom.android.aidl; importcom.android.aidl.BookInfo.Stub; importandroid.app.Service; importandroid.content.Intent; importandroid.os.IBinder; publicclassRemoteServiceextendsService{ //声明BookInfo接口 privateStubbookifo=newBookInfoImpl(); publicIBinderonBind(Intentintent){ returnbookifo; } } 四.在客户端调用 定义一个Activity来绑定远程Service,获得BookInfo接口,通过RPC机制调用接口中的方法。 packagecom.android.aidl; importandroid.app.Activity; importandroid.app.Service; importandroid.content.ComponentName; importandroid.content.Intent; importandroid.content.ServiceConnection; importandroid.os.Bundle; importandroid.os.IBinder; importandroid.os.RemoteException; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; importandroid.widget.Toast; publicclassMainActivityextendsActivity{ //声明IPerson接口 privateBookInfobookInfo; //声明Button privateButtonbtn; //实例化ServiceConnection privateServiceConnectionconn=newServiceConnection(){ @Override synchronizedpublicvoidonServiceConnected(ComponentNamename,IBinderservice){ //获得IPerson接口 bookInfo=BookInfo.Stub.asInterface(service); if(bookInfo!=null) try{ //RPC方法调用 bookInfo.setName("GoogleAndroidSDK开发范例大全"); bookInfo.setPrice(55); bookInfo.setPublish("人民邮电出版社"); Stringmsg=bookInfo.display(); //显示方法调用返回值 Toast.makeText(MainActivity.this,msg,Toast.LENGTH_LONG) .show(); }catch(RemoteExceptione){ e.printStackTrace(); } } @Override publicvoidonServiceDisconnected(ComponentNamename){ } }; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //设置当前视图布局 setContentView(R.layout.main); //实例化Button btn=(Button)findViewById(R.id.Button1); //为Button添加单击事件监听器 btn.setOnClickListener(newOnClickListener(){ @Override publicvoidonClick(Viewv){ //实例化Intent Intentintent=newIntent(); //设置IntentAction属性 intent.setAction("com.android.aidl.action.MY_REMOTE_SERVICE"); //绑定服务 bindService(intent,conn,Service.BIND_AUTO_CREATE); } }); } } 五.main.xml和AndroidManifest.xml文件 main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:text="远程调用Service" android:id="@+id/Button1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 在AndroidManifest.xml文件16~20声明Service <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.android.aidl" android:versionCode="1" android:versionName="1.0"> <uses-sdkandroid:minSdkVersion="10"/> <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> <activityandroid:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <serviceandroid:name="RemoteService"> <intent-filter> <actionandroid:name="com.android.aidl.action.MY_REMOTE_SERVICE"/> </intent-filter> </service> </application> </manifest> 效果图: 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/653344

优秀的个人博客,低调大师

Android开发学习笔记:对话框浅析

对话框式程序运行中弹出的窗口。Android系统中有四种默认的对话框:警告对话框AlertDialog、进度对话框ProgressDialog、日期选择对话框DatePickerDialog以及时间选择对话框TimePickerDialog。除此之外,我们自定义自已的dialog。 一.警告对话框(AlertDialog) Android系统中最常用的对话框是AlertDialog,它是一个提示窗口,需要用户作出选择的。一般会有几个按钮、标题信息、提示信息等。 在程序中创建AlertDialog的步骤: 1.获得AlertDialog的静态内部类Builder对象,由该类来创建对话框,Builder所提供的方法如下: setTitle():给对话框设置title. setIcon():给对话框设置图标。 setMessage():设置对话框的提示信息 setItems():设置对话框要显示的一个list,一般用于要显示几个命令时 setSingleChoiceItems():设置对话框显示一个单选的List setMultiChoiceItems():用来设置对话框显示一系列的复选框。 setPositiveButton():给对话框添加”Yes”按钮。 setNegativeButton():给对话框添加”No”按钮。 2.调用Builder的create( )方法 3.调用AlertDialog的show( )方法显示对话框 下面是一个提示信息对话框的实例: AlertDialogActivity.java package com.android.dialog.activity; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class AlertDialogActivity extends Activity { private TextView tv; private Button btn; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tv = (TextView)findViewById(R.id.TextView_1); btn = (Button)findViewById(R.id.Button_1); //实例化AlertDialog.Builder对象 final AlertDialog.Builder builder = new AlertDialog.Builder(this); btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { //设置提示信息,确定按钮 builder.setMessage("真的要删除该文件吗?").setPositiveButton("是", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { tv.setText("成功删除"); } //设置取消按钮 }).setNegativeButton("否", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { tv.setText("取消删除"); } }); //创建对话框 AlertDialog ad = builder.create(); //显示对话框 ad.show(); } } ); } } main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/TextView_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试AlertDialog" /> <Button android:id="@+id/Button_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="删除文件" /> </LinearLayout> 效果图: 二.进度对话框(ProgressDialog) 在程序中创建ProgressDialog的步骤: 1.覆盖Activity的onCreateDialog( )方法,并在其中创建对话框 2.调用Activity的showDialog( )方法,显示进度对话框 下面是一个提示进度对话框的实例: ProgressDialogActivity.java packagecom.android.progress.activity; importandroid.app.Activity; importandroid.app.Dialog; importandroid.app.ProgressDialog; importandroid.content.DialogInterface; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; publicclassProgressDialogActivityextendsActivity{ privateButtonbtn; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); btn=(Button)findViewById(R.id.Button_1); btn.setOnClickListener(newOnClickListener(){ publicvoidonClick(Viewv){ //调用Activity的showDialog()方法,显示进度对话框 showDialog(0); } }); } @Override protectedDialogonCreateDialog(intid){ //对进度对话框进行实例化 ProgressDialogdialog=newProgressDialog(this); //设置显示的标题 dialog.setTitle("测试ProgressDialog"); dialog.setIndeterminate(true); dialog.setMessage("程序正在Loading..."); dialog.setCancelable(true); dialog.setButton(Dialog.BUTTON_POSITIVE,"确定", newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ dialog.cancel(); } } ); returndialog; } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/Button_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试ProgressDialog" /> </LinearLayout> 效果图: 三.日期,时间选择对话框(DatePickerDialog、TimePickerDialog) 在程序中创建日期,时间选择对话框的步骤: 1.覆盖Activity的onCreateDialog( )方法,并在其中创建对话框 2.分别在OnDateSetListener的onDateSet( )方法和OnTimeSetListener( )的onTimeSet( )事件方法中更改日期,时间 3.调用Activity的showDialog( )方法,显示进度对话框 MainActivity.java packagecom.android.datatime.activity; importjava.util.Calendar; importandroid.app.Activity; importandroid.app.DatePickerDialog; importandroid.app.Dialog; importandroid.app.TimePickerDialog; importandroid.app.DatePickerDialog.OnDateSetListener; importandroid.app.TimePickerDialog.OnTimeSetListener; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; importandroid.widget.DatePicker; importandroid.widget.TextView; importandroid.widget.TimePicker; publicclassMainActivityextendsActivity{ privateButtonbtn1,btn2; privateTextViewtv_1,tv_2; privateCalendarc;//获得日历实例 privateintm_year,m_month,m_day; privateintm_hour,m_minute; publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); btn1=(Button)findViewById(R.id.Button_1); btn2=(Button)findViewById(R.id.Button_2); c=Calendar.getInstance(); m_year=c.get(Calendar.YEAR); m_month=c.get(Calendar.MONTH); m_day=c.get(Calendar.DAY_OF_MONTH); m_hour=c.get(Calendar.HOUR); m_minute=c.get(Calendar.MINUTE); tv_1=(TextView)findViewById(R.id.TextView_1); tv_1.setText(m_year+":"+(m_month+1)+":"+m_day);//设置TextView里的内容为日期 tv_2=(TextView)findViewById(R.id.TextView_2); tv_2.setText(m_hour+":"+m_minute);//设置TextView里的内容为时间 btn1.setOnClickListener(newOnClickListener(){ publicvoidonClick(Viewv){ showDialog(0);//显示日期对话框 } }); btn2.setOnClickListener(newOnClickListener(){ publicvoidonClick(Viewv){ showDialog(1);//显示时间对话框 } }); } //调用Activity的showDialog()方法显示进对话框 protectedDialogonCreateDialog(intid){ if(id==0) returnnewDatePickerDialog(this,l1,m_year,m_month,m_day); else returnnewTimePickerDialog(this,l2,m_hour,m_minute,false); } //设置日期监听器 privateOnDateSetListenerl1=newOnDateSetListener(){ publicvoidonDateSet(DatePickerview,intyear,intmonthOfYear, intdayOfMonth){ m_year=year; m_month=monthOfYear; m_day=dayOfMonth; tv_1.setText(m_year+":"+(m_month+1)+":"+m_day);//为TextView设置文本内容,重新显示日期 } }; //设置时间监听器 privateOnTimeSetListenerl2=newOnTimeSetListener(){ publicvoidonTimeSet(TimePickerview,inthourOfDay,intminute){ m_hour=hourOfDay; m_minute=minute; tv_2.setText(m_hour+":"+m_minute);//为TextView设置文本内容,重新显示时间 } }; } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:text="" android:id="@+id/TextView_1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:text="" android:id="@+id/TextView_2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="修改日期" android:id="@+id/Button_1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="修改时间" android:id="@+id/Button_2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 效果图: 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/641365

优秀的个人博客,低调大师

Android学习笔记(二)基础知识(1)

更改文字颜色 文字色: TextView.setTextColor(Color.***); 背景色: Resources resources = getBaseContext().getResources(); Drawable HippoDrawable = resources.getDrawable(R.drawable.white); TextView.setBackgroundDrawable(HippoDrawable); 获取手机分辨率 import android.util.DisplayMetrics DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); String x,y; x=dm.widthPixels; y=dm.heightPixels; 页面转换 在Android应用中,是通过setContentView来实现页面的转换处理的,也就是在不同的layout之间进行切换。 setContentView(R.layout.****); 例子: package com.example.test4; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button b1=(Button)findViewById(R.id.button1); b1.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub jumpToMylayout(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } public void jumpToMylayout(){ setContentView(R.layout.mylayout); Button b2 = (Button)findViewById(R.id.button1); b2.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub jumpToLayout(); } }); } public void jumpToLayout(){ setContentView(R.layout.activity_main); Button b1=(Button)findViewById(R.id.button1); b1.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub jumpToMylayout(); } }); } } 调用其他Activity 与上面在不同layout之间转换不同,这里我们需要移交主权到另外一个Activity。 //一个Activity Intent intent=new Intent(); intent.setClass(MainActivity.this,replace.class); startActivity(intent); MainActivity.this.finish(); //另外一个Activity Intent intent=new Intent(); intent.setClass(replace.this, MainActivity.class); startActivity(intent); replace.this.finish(); 不同Activity之间的数据转换 利用Android.os.Bundle对象封装数据的能力,将欲传递的数据或参数,通过Bundle来传递不同Intent之间的数据。 发送: Intent intent=new Intent(); intent.setClass(MainActivity.this,display.class); Bundle bundle = new Bundle(); bundle.putString("num",et1.getText().toString()); bundle.putString("name",et2.getText().toString()); intent.putExtras(bundle); startActivity(intent); 接收: Bundle bundle = this.getIntent().getExtras(); String num = bundle.getString("num"); String name = bundle.getString("name"); 返回数据到前一个Activity 唤起一个Activity: startActivityForResult(intent,0) 重载onActivityResult: protected voidonActivityResult(int requestCode,int resultCode,Intent data){ switch(resultCode){ case RESULT_OK: Bundle bundle=data.getExtras(); //code there break; default: break; } } 返回数据: input.this.setResult(RESULT_OK, intent); 部分代码: //main_activity package com.example.test7; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { TextView tx; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button bt=(Button)findViewById(R.id.button1); tx=(TextView)findViewById(R.id.textView1); bt.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub Intent intent = new Intent(); intent.setClass(MainActivity.this, input.class); startActivityForResult(intent,0); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override protected void onActivityResult(int requestCode,int resultCode,Intent data){ switch(resultCode){ case RESULT_OK: Bundle bundle=data.getExtras(); String str=bundle.getString("str").toString(); tx.setText(str); break; default: break; } } } /** * input.java */ package com.example.test7; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; public class input extends Activity { Intent intent; Bundle bundle; EditText et; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.input); Button bt=(Button)findViewById(R.id.button1); et=(EditText)findViewById(R.id.editText1); intent = this.getIntent(); bundle= new Bundle(); bt.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub bundle.putString("str", et.getText().toString()); intent.putExtras(bundle); input.this.setResult(RESULT_OK, intent); input.this.finish(); } }); } } 本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/archive/2013/05/13/3075259.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

[Android学习笔记一] ContentProvider组件开发详解

Android四大组件中ContentProvider组件相对Activity,BroadcastReceiver, Service而言比较独立,而且多数使用的时候都是在用Android系统提供的关于邮件,媒体,短信,联系人等ContentProvider。通常开发的应用较少提供ContentProvider组件,一般会在同家公司的产品或则内容适配方面会用到ContentProvider组件。 本文主要讲述开发和使用ContentProvider组件的通用方式。其中包含:代码模板,权限设置,ContentResolver 等。 1 . 开发ContentProvider基本思路 1.1.ContentProvider组件需要对外开放的内容 授权字符串(Authoritis),内容类型,数据字段名称, 访问权限说明等 1.2. 编写ContentProvider组件类继承ContentProvider类,实现其中的CRUD操作方法 1.3. AndroidMainifest.xml中配置<provider>元素,指定控制属性,其中包含是否对外部应用可用,读写权限,Authorities字符串等 1.4. 应用本身或者外部应用使用ContentProvider组件 2. 开发一个基于SQLite数据库提供Note表信息的ContentProvider 2.1 开发一个独立的ContentProvider组件代码框架 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 package secondriver.xprovider; import android.content.*; import android.content.pm.ProviderInfo; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.provider.BaseColumns; import android.text.TextUtils; import android.util.Log; import java.text.SimpleDateFormat; import java.util.Date; /** *Author:secondriver *Date:2015/11/4 */ public class XProvider extends ContentProvider{ private static final StringTAG= "XProvider" ; //授权字符串 //授权Uri //Note公开信息 public static final class Note implements BaseColumns{ //Note表名 //Note表的内容Uri //内容类型 //Note表字段 //Uri匹配码 } //Uri匹配器 public static UriMatcheruriMatcher; static { uriMatcher= new UriMatcher(UriMatcher.NO_MATCH); //添加Uri匹配内容 } private XSQLiteHelperhelper; @Override public boolean onCreate(){ //ContentProvider组件创建时做的工作 return true ; } @Override public Cursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder){ return cursor; } @Override public StringgetType(Uriuri){ return null ; } @Override public Uriinsert(Uriuri,ContentValuesvalues){ return null ; } @Override public int delete(Uriuri,Stringselection,String[]selectionArgs){ return effectRows; } @Override public int update(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs){ return effectRows; } public static class XSQLiteHelper extends SQLiteOpenHelper{ public static final StringDATA_BASE_NAME= "xprovider.sqlite" ; public static final int DATA_BASE_VERSION= 1 ; public static volatile XSQLiteHelperxsqLiteHelper; public static XSQLiteHelpergetXsqLiteHelper(Contextcontext){ //实例化XSQLiteHelp对象 return xsqLiteHelper; } public XSQLiteHelper(Contextcontext,Stringname,SQLiteDatabase.CursorFactoryfactory, int version){ super (context,name,factory,version); } @Override public void onCreate(SQLiteDatabasedb){ //数据库初始化 } @Override public void onUpgrade(SQLiteDatabasedb, int oldVersion, int newVersion){ } } } 上面代码提供了一个SQLiteOpenHelper的实现,实际开发中可个会更具具体应用来提供给ContentProvider组件。 中文注释部分可能需要填充具体代码,比如权限可以更具实际情况来定义,表字段根据要提供的内容信息来公开字段名并且需要在文档中说明。 2.1 准备Note表信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 //Note公开信息 public static final class Note implements BaseColumns{ //Note表名 public static final StringTABLE_NAME= "note" ; //Note表的内容Uri public static final UriCONTENT_URI=Uri.withAppendedPath(AUTHORITY_URI, "note" ); //建议使用格式如:type/subtype=>vnd.android.cursor.dir/vnd.<name>.<type>name=packagenametype=tablename public static final StringCONTENT_DIR_TYPE= "vnd.android.cursor.dir/vnd.secondriver.xprovider.note" ; public static final StringCONTENT_ITEM_TYPE= "vnd.android.cursor.item/vnd.secondriver.xprovider.note" ; //ID主键 public static final StringID_COLUMN=_ID; //内容列 public static final StringCONTENT_COLUMN= "CONTENT" ; //创建时间列表 public static final StringCREATED_COLUMN= "CREATED" ; //标识列 public static final StringFLAG_COLUMN= "FLAG" ; //状态列 public static final StringSTATUS_COLUMN= "STATUS" ; //Uri匹配码 private static final int NOTE_ITEM= 0x21 ; private static final int NOTE_DIR= 0x22 ; } 说明:Uri匹配码声明为Note类的常量这样可以方便对照,一个ContentProvider组件中声明多个表公开类,比如User类,这样就比较容易区分操作的是那个表的内容。 2.2 Note类外其它的具体代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 package secondriver.xprovider; import android.content.*; import android.content.pm.ProviderInfo; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.provider.BaseColumns; import android.text.TextUtils; import android.util.Log; import java.text.SimpleDateFormat; import java.util.Date; /** *Author:secondriver *Date:2015/11/4 */ public class XProvider extends ContentProvider{ private static final StringTAG= "XProvider" ; //授权字符串 public static final StringAUTHORITY= "secondriver.xprovider.X_PROVIDER" ; //授权Uri public static final UriAUTHORITY_URI=Uri.parse( "content://" +AUTHORITY); //Uri匹配器 public static UriMatcheruriMatcher; static { uriMatcher= new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "note/#" ,Note.NOTE_ITEM); uriMatcher.addURI(AUTHORITY, "note" ,Note.NOTE_DIR); } private XSQLiteHelperhelper; @Override public boolean onCreate(){ helper=XSQLiteHelper.getXsqLiteHelper(getContext()); return true ; } @Override public Cursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder){ SQLiteQueryBuilderbuilder= new SQLiteQueryBuilder(); switch (uriMatcher.match(uri)){ case Note.NOTE_DIR: break ; case Note.NOTE_ITEM: builder.appendWhere(Note.ID_COLUMN+ "=" +uri.getPathSegments().get( 1 )); break ; default : throw new IllegalArgumentException( "UnsupportedURI:" +uri); } builder.setTables(Note.TABLE_NAME); Cursorcursor=builder.query(helper.getReadableDatabase(),projection,selection,selectionArgs, null , null ,sortOrder); return cursor; } @Override public StringgetType(Uriuri){ switch (uriMatcher.match(uri)){ case Note.NOTE_ITEM: return Note.CONTENT_ITEM_TYPE; case Note.NOTE_DIR: return Note.CONTENT_DIR_TYPE; default : throw new IllegalArgumentException( "UnsupportedURI:" +uri); } } @Override public Uriinsert(Uriuri,ContentValuesvalues){ SQLiteDatabasedb=helper.getWritableDatabase(); switch (uriMatcher.match(uri)){ case Note.NOTE_DIR: long noteId=db.insert(Note.TABLE_NAME, null ,values); if (noteId> 0 ){ //插入成功 UrinewUri=ContentUris.withAppendedId(uri,noteId); getContext().getContentResolver().notifyChange(newUri, null ); return newUri; } else { //插入失败 return null ; } default : throw new IllegalArgumentException( "UnsupportedURI:" +uri); } } @Override public int delete(Uriuri,Stringselection,String[]selectionArgs){ SQLiteDatabasedb=helper.getWritableDatabase(); int effectRows= 0 ; switch (uriMatcher.match(uri)){ case Note.NOTE_DIR: effectRows=db.delete(Note.TABLE_NAME,selection,selectionArgs); break ; case Note.NOTE_ITEM: long id=ContentUris.parseId(uri); StringwhereClause=Note.ID_COLUMN+ "=" +String.valueOf(id); if (!TextUtils.isEmpty(selection)){ whereClause=whereClause+ "AND" +selection; } effectRows=db.delete(Note.TABLE_NAME,whereClause,selectionArgs); break ; default : throw new IllegalArgumentException( "UnsupportedURI:" +uri); } getContext().getContentResolver().notifyChange(uri, null ); return effectRows; } @Override public int update(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs){ SQLiteDatabasedb=helper.getWritableDatabase(); int effectRows= 0 ; switch (uriMatcher.match(uri)){ case Note.NOTE_DIR: effectRows=db.update(Note.TABLE_NAME,values,selection,selectionArgs); break ; case Note.NOTE_ITEM: long nodeId=ContentUris.parseId(uri); StringwhereClause=Note.ID_COLUMN+ "=" +String.valueOf(nodeId); if (!TextUtils.isEmpty(selection)){ whereClause=whereClause+ "AND" +selection; } effectRows=db.update(Note.TABLE_NAME,values,whereClause,selectionArgs); break ; default : throw new IllegalArgumentException( "UnsupportedURI:" +uri); } return effectRows; } public static class XSQLiteHelper extends SQLiteOpenHelper{ public static final StringDATA_BASE_NAME= "xprovider.sqlite" ; public static final int DATA_BASE_VERSION= 1 ; public static volatile XSQLiteHelperxsqLiteHelper; public static XSQLiteHelpergetXsqLiteHelper(Contextcontext){ if ( null ==xsqLiteHelper){ synchronized (XSQLiteHelper. class ){ if ( null ==xsqLiteHelper){ xsqLiteHelper= new XSQLiteHelper(context,DATA_BASE_NAME, null ,DATA_BASE_VERSION); } } } return xsqLiteHelper; } public XSQLiteHelper(Contextcontext,Stringname,SQLiteDatabase.CursorFactoryfactory, int version){ super (context,name,factory,version); } @Override public void onCreate(SQLiteDatabasedb){ db.beginTransaction(); try { db.execSQL( new StringBuilder( "createtableifnotexists" ) .append(Note.TABLE_NAME) .append( "(" ) .append(Note.ID_COLUMN) .append( "integerprimarykeyautoincrement," ) .append(Note.CONTENT_COLUMN) .append( "varchar," ) .append(Note.CREATED_COLUMN) .append( "varchar," ) .append(Note.FLAG_COLUMN) .append( "varchar," ) .append(Note.STATUS_COLUMN) .append( "varchar" ) .append( ")" ) .toString() ); SimpleDateFormatsimpleDateFormat= new SimpleDateFormat( "yyyy-MM-ddHH:mm:ss" ); for ( int i= 0 ;i< 50 ;i++){ ContentValuescv= new ContentValues(); cv.put(Note.CONTENT_COLUMN, "Note内容" +i); cv.put(Note.CREATED_COLUMN,simpleDateFormat.format( new Date())); cv.put(Note.FLAG_COLUMN,i); cv.put(Note.STATUS_COLUMN,i); db.insert(Note.TABLE_NAME, null ,cv); } db.setTransactionSuccessful(); } catch (SQLiteExceptione){ Log.e(TAG,e.getMessage()); } finally { db.endTransaction(); } } @Override public void onUpgrade(SQLiteDatabasedb, int oldVersion, int newVersion){ } } } 3. 在AndroidMainfest.xml清单文件中声明ContentProvider组件 3.1 声明XProvider 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <!-- 按如下顺序验证权限 android:grantUriPermssions:Temporarypermissionflag. android:permission:Singleprovider-wideread/writepermission. android:readPermission:Provider-widereadpermission. android:writePermission:Provider-widewritepermission. --> < provider android:permission = "secondriver.xprovider.permission.X_PROVIDER" android:authorities = "secondriver.xprovider.X_PROVIDER" android:name = ".XProvider" android:exported = "true" > <!-- 子元素: grant-uri-permission:Uri临时访问授权 path-permission:Uri细粒度控制读写权限 --> </ provider > 3.2 定义权限 清单文件中声明XProvider的时候使用到了内容读写权限 “secondriver.xprovider.permission.X_PROVIDER” 因此该权限需要清单文件中定义。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 < permission android:name = "secondriver.xprovider.permission.X_PROVIDER" android:label = "xProvider的读写权限" android:description = "@string/permission_x_provider_desc" android:protectionLevel = "normal" /> <!-- <permission android:name="secondriver.xprovider.permission.READ_X_PROVIDER" android:label="xProvider的读权限" android:description="@string/permission_read_x_provider_desc" android:protectionLevel="normal"/> <permission android:name="secondriver.xprovider.permission.WRITE_X_PROVIDER" android:label="xProvider的写权限" android:description="@string/permission_write_x_provider_desc" android:protectionLevel="normal"/> --> 权限定义时label属性的值通常为”XXX的权限“,description属性的值通常是”允许该应用干什么,授权有XXX的危害“。比如:label =发送持久广播权限 description=允许该应用发送持久广播,此类消息在广播结束后仍会保留。过多使用会占用手机过多内容,从而降低其速度或稳定性。 3.3 权限说明 默认情况下Provider是没有权限控制的,因此一旦exported=true,那么外部其它应用都可以访问到Provider提供的内容,为了更加安全,有效,范围合适的控制需要添加权限控制。 Provider权限分为: 读写的Provider层权限 读写分开的Provider层权限 Path层权限 临时授权 四种权限从上往下优先级越高。 Path层权限:是对于Uri的更具细粒度的权限控制,provider元素的子元素中可以配置grant-ui-permission和path-permission 。 临时授权:provider元素属性grantUriPermissions=true时系统将授予应用临时权限访问完整的Provider,覆盖掉Provider和Path层的权限;grantUriPermissions=false时需要在provider元素的子元素中配置一个或者多个grant-uri-permission元素来为指定的Uri的临时访问授权。 另外应用在使用临时授权访问Provider时Provider应用会在返回的Intent中通过的setFlags方法指定FLAG_GRANT_READ_URI_PERMISSION和FLAG_GRANT_WRITE_URI_PERMISSION标识,携带一个具有临时授权的Uri供外部应用完成本次内容访问操作。 4. 在本应用和其它应用中使用ContentProvider提供的内容 这里提供在其它应用中使用ContentProvider。在使用外部提供的ContentProvider通常需要了解的内容便是文字1.1部分提到。 4.1 下面是通过一个ListView来展示Note中的”CONTENT“和”CREATED“字段信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 package secondriver.oapp; import android.app.Activity; import android.app.LoaderManager; import android.content.CursorLoader; import android.content.Loader; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** *Author:secondriver *Date:2015/11/5 */ public class XResolverActivity extends Activity{ private SimpleAdaptermAdapter; private ListViewmListView; private List<Map<String,String>>mData; private final int xproviderLoad= 0x01 ; private LoaderManagerloaderManager; private LoaderManager.LoaderCallbacks<Cursor>callbacks= new LoaderManager.LoaderCallbacks<Cursor>(){ @Override public Loader<Cursor>onCreateLoader( int id,Bundleargs){ CursorLoadercursorLoader= new CursorLoader(getApplicationContext(), Uri.parse( "content://secondriver.xprovider.X_PROVIDER/note" ), new String[]{ "_id" , "CONTENT" , "CREATED" }, null , null , null ); return cursorLoader; } @Override public void onLoadFinished(Loader<Cursor>loader,Cursordata){ int idIndex=data.getColumnIndexOrThrow( "_id" ); int contentIndex=data.getColumnIndexOrThrow( "CONTENT" ); int createdIndex=data.getColumnIndexOrThrow( "CREATED" ); mData.clear(); while (data.moveToNext()){ HashMap<String,String>m= new HashMap<>(); m.put( "CONTENT" ,data.getString(contentIndex)); m.put( "CREATED" ,data.getString(createdIndex)); m.put( "_id" ,data.getString(idIndex)); mData.add(m); } mAdapter.notifyDataSetChanged(); } @Override public void onLoaderReset(Loader<Cursor>loader){ } }; @Override protected void onCreate(BundlesavedInstanceState){ super .onCreate(savedInstanceState); setContentView(R.layout.activity_xresolver); mListView=(ListView)findViewById(android.R.id.list); mData= new ArrayList<>(); mAdapter= new SimpleAdapter( this ,mData,android.R.layout.simple_list_item_2, new String[]{ "CONTENT" , "CREATED" }, new int []{ android.R.id.text1, android.R.id.text2 }); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener( new AdapterView.OnItemClickListener(){ @Override public void onItemClick(AdapterView<?>parent,Viewview, int position, long id){ HashMapm=(HashMap)mData.get(position); StringnoteId=(String)m.get( "_id" ); StringnoteContent=(String)m.get( "CONTENT" ); getContentResolver().delete(Uri.withAppendedPath(Uri.parse( "content://secondriver.xprovider.X_PROVIDER/note" ),noteId), null , null ); mData.remove(position); mAdapter.notifyDataSetChanged(); Toast.makeText(XResolverActivity. this , "Delete:" +noteContent,Toast.LENGTH_LONG).show(); } }); loaderManager=getLoaderManager(); loaderManager.initLoader(xproviderLoad, new Bundle(),callbacks); } @Override protected void onResume(){ super .onResume(); if ( null !=loaderManager){ loaderManager.restartLoader(xproviderLoad, new Bundle(),callbacks); } } @Override protected void onDestroy(){ super .onDestroy(); if ( null !=loaderManager){ loaderManager.destroyLoader(xproviderLoad); } } } 说明:需要额外注意的是代码中的硬编码字符串内容,这些内容正是XProvider类和Note类公开的信息,这些内容通常在ContentProvider组件的使用文档中公开说明的。如果是在应用内部使用XProvider的话,那么就可以直接使用变量名而避免硬编码。如下代码片段所示: 1 2 3 4 5 6 7 8 9 mAdapter= new SimpleAdapter( this ,mData,android.R.layout.simple_list_item_2, new String[]{ XProvider.Note.CONTENT_COLUMN, XProvider.Note.CREATED_COLUMN }, new int []{ android.R.id.text1, android.R.id.text2 }); 由于XProvider的访问需要读写权限,因此需要在清单文件中声明使用的权限。 1 < uses-permission android:name = "secondriver.xprovider.permission.X_PROVIDER" /> 5. ContentProvider组件小结 在开发ContentProvider时尽可能使其具备以下特点: 提供恰当的内容访问范围;ContentProvider组件独立封装;详细的权限,Uri,提供内容的使用说明。 本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1710151,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册