首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

Android开发过程中的视图组详解

Android在屏幕中控件的组织上,可以将各个视图(控件)组成一个视图组(ViewGroup),视图组是一个包含了其他视图的视图。 ▲图书封面 1.视图组(ViewGroup抽象类) android.view包中ViewGroup类继承了View,因此它本身也具有View的特性。ViewGroup主要的功能在于它可以包含其他控件,作为其他控件的容器。 ViewGroup实现了android.view包中的ViewParent接口,这个类表示一个可以作为其他的View的容器的职责。 ViewGroup也实现了android.view包中的ViewManager接口,因此包含ViewManager中的以下几个方法: public abstract void addView(View view, ViewGroup.LayoutParams params) public abstract void removeView(View view) public abstract void updateViewLayout(View view, ViewGroup.LayoutParams params) addView()以View作为参数,用于将这个View增加为当前视图组的“孩子”;removeView()用于将一个View从视图组中移除;updateViewLayout()用于更新某个View的布局。 ViewGroup.OnHierarchyChangeListener是一个接口,用于监听ViewGroup中的View的层次变化。这个接口中包含了两个监听方法: public abstract void onChildViewAdded (View parent, View child) public abstract void onChildViewRemoved (View parent, View child) 实现一个OnHierarchyChangeListener接口后,这两个方法可以监听包括ViewGroup(包括其继承者)之中的增加和删除孩子的情况。通过ViewGroup的setOnHierarchyChangeListener()方法可以将其设置给一个ViewGroup。 ViewGroup是一个抽象类,其中包含了以下的一个抽象方法: protected abstract void onLayout (boolean changed, int l, int t, int r, int b) ViewGroup中的onLayout()方法将在ViewGroup为它的孩子们分配尺寸和位置的时候被调用,在这个类的实现中,需要调用每一个控件的布局方法为其布局。 提示:onLayout()在View中是一个public的方法,在ViewGroup为protected类型,并且为abstract,由于这个方法在ViewGroup中没有实现,因此ViewGroup本身不可以直接使用。 2.Android的屏幕元素体系 Android UI程序的屏幕体系结构的组织遵循以下原则: 一个屏幕可以包含一个视图; 视图组本身也是一个视图; 视图组可以包含若干个视图。 Android视图和视图组的关系如图3-12所示。 图3-12中左右两图表示的一个屏幕中View组织的结构,左图是各个视图组和控件在一个屏幕之中的示意图;右图为视图组的层次结构图(View Hierarchy),这也是Android中一种常用的表示屏幕中布局的方式。 如图3-12所示,外部最大的框表示整个屏幕,其中包含一个视图组ViewGroup0,ViewGroup0包含三个子视图,即View1、ViewGroup1、ViewGroup2。ViewGroup1本身也是视图组,包含了View2和View3;ViewGroup2本身也是视图组,包含了View4、ViewGroup3和ViewGroup4;ViewGroup4本身也是视图组,包含了View5和View6。 ▲图3-12 视图和视图组的关系(上:屏幕示意图;下:View的层次结构图) 根据以上的原则,当屏幕需要包含多个视图时,必须组织在一个视图组中。由于视图组本身也是一个视图,因此视图组还可以包含视图组。 一个主要的限制是:在没有视图组的情况下,两个以上的视图(也包括视图组)是不能够并列的。例如,在布局文件中,类似下面的写法是不可以的。 <?xml version="1.0" encoding="utf-8"?> <Button android:id="@+id/button"/> <EditText android:id="@+id/edit"/> 3.ViewGroup的继承结构 ViewGroup是所有视图组的基类,它本身是一个不能直接使用的抽象类。在程序中使用的主要是ViewGroup的继承者。 ViewGroup的继承者大部分在android.widget包中,其直接继承者包括:AdapterView、AbsoluteLayout、FrameLayout、LinearLayout、RelativeLayout。这些继承者各自又具有一些继承者。 ViewGroup继承者的体系结构如图3-13所示。 图3-13中所示的ViewGroup继承者都是可以作为容器使用的。这些继承者可以为它们的孩子们提供不同的布局方法,用以确定孩子们相互之间的位置和尺寸关系。 这些继承者又具有一些继承者,有些继承者是不作为容器使用的,仅仅是像一个普通控件一样使用。 ▲图3-13 视图组的继承结构 4.布局参数类 在Android中每个控件在布局文件中能使用的XML属性其实有三类: 其自己的XML属性; 其祖先类的XML属性; 其容器的布局参数。 其中,布局参数是包含这个控件的容器(一个ViewGroup的继承者)所提供的参数。在Android中,每一个ViewGroup的继承者都有一个相对应的名称为{XXX}.LayoutParams的静态子类,表示这个ViewGroup的孩子们中可以使用的布局参数。 这些布局参数类的基类为ViewGroup.LayoutParams,这是一个ViewGroup的静态子类,表示ViewGroup的子对象中可以使用参数。 ViewGroup.LayoutParams包含有两个重要的XML属性:android:layout_width和android:layout_height,它们表示布局对象的宽和高。除了使用实际的尺寸数值外,还有如下两个常用的选项。 “match_parent”或者“fill_parent”:表示能匹配父视图的最大尺寸; “wrap_content”:表示仅包裹孩子的最小尺寸。 ViewGroup.MarginLayoutParams是ViewGroup.LayoutParams的一个继承者,主要用于定义和边缘的空白,它具有android:layout_marginTop,android:layout_marginLeft,android:layout_marginBottom,android:layout_marginRight几个XML属性,表示四个方向的边缘空白。 在ViewGroup的继承者中,都具有一个名称为.LayoutParams的静态子类,这些子类继承关系和ViewGroup子类的继承关系具有相似性。布局参数LayoutParams使用方式如图3-14所示。 ▲图3-14 视图组布局参数的结构 从图3-14中可见,LinearLayout的布局参数LinearLayout.LayoutParams可以被这个布局的孩子们使用,RelativeLayout的布局参数RelativeLayout.LayoutParams可以被这个布局的孩子们使用。但是这里“孩子”的含义,只包括这个容器直接的孩子。例如,图3-14中LinearLayout的孩子有一个是RelativeLayout,RelativeLayout的孩子中能使用的参数就不包括线性布局的参数LinearLayout.LayoutParams。 提示:由于LayoutParams也具有继承关系,因此LinearLayout的孩子们除了可以使用LinearLayout.LayoutParams自己的XML属性,还可以使用其祖先类ViewGroup.LayoutParams的XML属性。 本文转自 wws5201985 51CTO博客,原文链接:http://blog.51cto.com/wws5201985/787672,如需转载请自行联系原作者

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

Android开发学习笔记:Activity的生命周期浅析

1.Android系统中Activity作为Activity栈(Stack)被管理的,大家都知道栈的特点是先进后出,所以当前活动的Activity处于栈顶,之前非活动的Activity被压入栈底,等待是否可能被恢复为活动状态。 Android API中所提供的Activity生命周期图: 2.下面的整个Activity生命周期中的所有方法,我们可以根据程序的需要来覆盖相应的方法: publicclassActivityextendsApplicationContext{ //创建的时候调用 protectedvoidonCreate(BundlesavedInstanceState); //启动的时候调用 protectedvoidonStart(); //重新启动的时候调用 protectedvoidonRestart(); //恢复的时候调用 protectedvoidonResume(); //暂停的时候调用 protectedvoidonPause(); //停止的时候调用 protectedvoidonStop(); //销毁的时候调用 protectedvoidonDestroy(); } onCreate(Bundle savedInstanceState):创建activity时调用。设置在该方法中,还以Bundle的形式提供对以前储存的任何状态的访问! onStart():activity变为在屏幕上对用户可见时调用。 onResume():activity开始与用户交互时调用(无论是启动还是重新启动一个活动,该方法总是被调用的) onPause():activity被暂停或收回cpu和其他资源时调用,该方法用于保存活动状态的,也是保护现场,压栈。 onStop():activity被停止并转为不可见阶段及后续的生命周期事件时调用。 onRestart():重新启动activity时调用。该活动仍在栈中,而不是启动新的活动 onDestroy():activity被完全从系统内存中移除时调用 3.下面通过实例来测试Activity的生命周期中各个方法的调用情况,将Activity的所有方法都覆盖,主要用Log打印输出信息,并通过日志(LogCat)方式来观察运行结果。Log.v(String tag, String msg); //Verbose Log.d(String tag, String msg); //Debug Log.i(String tag, String msg); //Info Log.w(String tag, String msg); //Warning Log.e(String tag, String msg); //Error tag类似标签,可以是任意字符串,通常可以使用类名+方法名, 主要是用来在查看日志时提供一个筛选条件。 下面的实例是测试Activity的生命周期中各个方法的调用情况: MainActivity.java packagecom.android.TestAvtivity.activity; importandroid.app.Activity; importandroid.os.Bundle; importandroid.util.Log; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; publicclassMainActivityextendsActivity{ privateButtonbtn; privatestaticfinalStringTAG="MainActivity"; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //输出日志 Log.i(TAG,"MainActivityonCreate--->"); btn=(Button)findViewById(R.id.Button1); btn.setOnClickListener(newOnClickListener(){ @Override publicvoidonClick(Viewv){ //结束当前的Activity MainActivity.this.finish(); } }); } @Override //启动 protectedvoidonStart(){ super.onStart(); //输出日志信息 Log.i(TAG,"MainActivityonStart--->"); } @Override //重启 protectedvoidonRestart(){ super.onRestart(); //输出日志信息 Log.i(TAG,"MainActivityonRestart--->"); } @Override //恢复 protectedvoidonResume(){ super.onResume(); //输出日志信息 Log.i(TAG,"MainActivityonResume--->"); } @Override //暂停 protectedvoidonPause(){ super.onPause(); //输出日志信息 Log.i(TAG,"MainActivityonPause--->"); } @Override //停止 protectedvoidonStop(){ super.onStop(); //输出日志信息 Log.i(TAG,"MainActivityonStop--->"); } @Override //销毁 protectedvoidonDestroy(){ super.onDestroy(); //输出日志信息 Log.i(TAG,"MainActivityonDestroy--->"); } } 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:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试Activit生命周期" /> <Button android:id="@+id/Button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="关闭Activity" /> </LinearLayout> 效果图: ①当启动程序时,日志的输出结果如下图所示,程序执行了onCreate()->onStart()->onResume三个方法。输出如下: MainActivity onCreate---> MainActivity onStart---> MainActivity onResume---> 注意:这里我是在选择了绿色的“+”,这时出现了下图的界面,之后我就在Filter Name上写入Test,by Log Tag上写入MainActivity,按OK保存,这时就能在LogCat上面筛选我们想要看到的信息了。 ②当按(返回键)或者按钮时,日志的输出结果如下图所示,程序先后调用了onPause( )->onStop( )->onDestory( )三个方法。 ③当按(Home键)时,日志的输出结果如下图所示,程序先后调用了onPause( )->onStop( )这两个方法,这时候应用程序并没有销毁。 ④当再次启动程序时,日志的输出结果如下图所示,程序先后调用了onRestart( )->onStart( )->onResume( )三个方法。 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/636913

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

WinForm自动化测试工具开发札记(4)

架构复用 这两天使用Win32 API参考对软件能用到的功能进行了一些小的尝试. 基本上没有什么太大的困难,只要努力,都能克服. 如果让这些功能散落在程序中,那么这个程序肯定写不出来.下面一段时间就开始设计类库了.使用接口/Abs类/类,把这些功能组织起来.昨天晚上在纸上大概画了画,画着画着才发现--咦,这不是跟.NET Framework的组织架构一样吗?呵呵,中微软的毒太深啦... 不过话又说回来,好的架构就应该复用. 又一个问题:是复用.NET Framework的架构,还是MFC的架构呢? 答案是:两者的"杂交品种". 1. .NET Framework的类种类丰富,适合测试WinForm上的各种控件. 2. 因为是在进行测试,所以.NET Framework的类中的"事件"成员的用处就不大了,去掉.这与MFC是一致的. 3. 正统的OO思想中本来也没有"事件"这个概念,微软自己加进去的.大概是沿袭了VB6的思想. 4. "属性"成员如果能去掉,也会去掉.降低程序的编写难度(其实也降低不了多少,搞不好程序不安全). 5. 正统的OO思想中也没有"属性"这个成员,也是微软自己加进去的.大概...(靠,哪儿来的拖鞋?) 6. 类与类(包括接口)间的继承关系,采用.NET Framework的,因为这个架构比MFC的更清晰. 本文转自 水之真谛 51CTO博客,原文链接:http://blog.51cto.com/liutiemeng/18758,如需转载请自行联系原作者

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

Android开发学习笔记:Service的简介和启动方式

一.Service的简介 1.Service 介绍和作用 Service是Android系统中的四大组件之一,它是一种长生命周期的,没有可视化界面,运行于后台的一种服务程序。比如我们播放音乐的时候,有可能想边听音乐边干些其他事情,当退出播放音乐的应用,如果不用Service,我 们就听不到歌了,所以这时候就得用到Service了。 2. Service生命周期 Service的生命周期并不像Activity那么复杂,它只继承了onCreate(),onStart(),onDestroy()三个方法,当第一次启动Service时,先后调用了onCreate(),onStart()这两个方法,当停止Service时,则执行onDestroy()方法,这里需要注意的是,如果Service已经启动了,当我们再次启动Service时,不会在执行onCreate()方法,而是直接执行onStart()方法。 二.Service的启动方式 Service的有两种启动方式: Context.startService()和Context.bindService(),这两种方式对 Service生命周期的影响是不同的。 1.Context.startService()方式启动 ①Context.startService()方式的生命周期:启动时,startService –> onCreate() –> onStart() 停止时,stopService –> onDestroy() 如果调用者直接退出而没有停止Service,则Service 会一直在后台运行 Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。 ②Context.startService()方式启动 Service的方法: 下面是具体例子: MainActivity.java packagecom.android.service.activity; importandroid.app.Activity; importandroid.content.Intent; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; publicclassMainActivityextendsActivity { privateButtonstartBtn; privateButtonstopBtn; @Override publicvoidonCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); startBtn=(Button)findViewById(R.id.startBtn); stopBtn=(Button)findViewById(R.id.stopBtn); //添加监听器 startBtn.setOnClickListener(listener); stopBtn.setOnClickListener(listener); } //启动监听器 privateOnClickListenerlistener=newOnClickListener() { @Override publicvoidonClick(Viewv) { Intentintent=newIntent(MainActivity.this,ServiceDemo.class); switch(v.getId()) { caseR.id.startBtn: startService(intent); break; caseR.id.stopBtn: stopService(intent); break; default: break; } } }; } ServiceDemo.java packagecom.android.service.activity; importandroid.app.Service; importandroid.content.Intent; importandroid.os.IBinder; importandroid.util.Log; publicclassServiceDemoextendsService { privatestaticfinalStringTAG="Test"; @Override //Service时被调用 publicvoidonCreate() { Log.i(TAG,"ServiceonCreate--->"); super.onCreate(); } @Override //当调用者使用startService()方法启动Service时,该方法被调用 publicvoidonStart(Intentintent,intstartId) { Log.i(TAG,"ServiceonStart--->"); super.onStart(intent,startId); } @Override //当Service不在使用时调用 publicvoidonDestroy() { Log.i(TAG,"ServiceonDestroy--->"); super.onDestroy(); } @Override //当使用startService()方法启动Service时,方法体内只需写returnnull publicIBinderonBind(Intentintent) { returnnull; } } 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/startBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="启动Service" /> <Button android:id="@+id/stopBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="停止Service" /> </LinearLayout> 在AndroidManifest.xml文件中添加16~21行的声明 <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.android.service.activity" 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=".ServiceDemo"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </service> </application> </manifest> 效果图: 当点击按钮时,先后执行了Service中onCreate()->onStart()这两个方法,LogCat显示如下: 当点击按钮时,Service则执行了onDestroy()方法,LogCat显示如下: 当点击或按钮,进入Settings(设置)->Applications(应用)->Running Services(正在运行的服务)看一下我们新启动了的服务,效果图如下: 2 .Context.bindService() 方式启动: ①Context.bindService()方式的生命周期:绑定时,bindService -> onCreate() –> onBind() 调用者退出了,即解绑定时,Srevice就会unbindService –>onUnbind() –> onDestory() 用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。 ②Context.bindService()方式启动 Service的方法: 绑定Service需要三个参数:bindService(intent, conn, Service.BIND_AUTO_CREATE); 第一个:Intent对象 第二个:ServiceConnection对象,创建该对象要实现它的onServiceConnected()和onServiceDisconnected()来判断连接成功或者是断开连接 第三个:如何创建Service,一般指定绑定的时候自动创建 下面是具体的例子: MainActivity.java packagecom.android.bindservice.activity; importandroid.app.Activity; importandroid.app.Service; importandroid.content.ComponentName; importandroid.content.Intent; importandroid.content.ServiceConnection; importandroid.os.Bundle; importandroid.os.IBinder; importandroid.util.Log; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; publicclassMainActivityextendsActivity{ //声明Button privateButtonstartBtn,stopBtn,bindBtn,unbindBtn; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //设置当前布局视图 setContentView(R.layout.main); //实例化Button startBtn=(Button)findViewById(R.id.startBtn1); stopBtn=(Button)findViewById(R.id.stopBtn2); bindBtn=(Button)findViewById(R.id.bindBtn3); unbindBtn=(Button)findViewById(R.id.unbindBtn4); //添加监听器 startBtn.setOnClickListener(startListener); stopBtn.setOnClickListener(stopListener); bindBtn.setOnClickListener(bindListener); unbindBtn.setOnClickListener(unBindListener); } //启动Service监听器 privateOnClickListenerstartListener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ //创建Intent Intentintent=newIntent(); //设置Class属性 intent.setClass(MainActivity.this,BindService.class); //启动该Service startService(intent); } }; //停止Service监听器 privateOnClickListenerstopListener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ //创建Intent Intentintent=newIntent(); //设置Class属性 intent.setClass(MainActivity.this,BindService.class); //启动该Service stopService(intent); } }; //连接对象 privateServiceConnectionconn=newServiceConnection(){ @Override publicvoidonServiceConnected(ComponentNamename,IBinderservice){ Log.i("Service","连接成功!"); } @Override publicvoidonServiceDisconnected(ComponentNamename){ Log.i("Service","断开连接!"); } }; //綁定Service监听器 privateOnClickListenerbindListener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ //创建Intent Intentintent=newIntent(); //设置Class属性 intent.setClass(MainActivity.this,BindService.class); //绑定Service bindService(intent,conn,Service.BIND_AUTO_CREATE); } }; //解除绑定Service监听器 privateOnClickListenerunBindListener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ //创建Intent Intentintent=newIntent(); //设置Class属性 intent.setClass(MainActivity.this,BindService.class); //解除绑定Service unbindService(conn); } }; } BindService.java packagecom.android.bindservice.activity; importandroid.app.Service; importandroid.content.Intent; importandroid.os.IBinder; importandroid.util.Log; publicclassBindServiceextendsService{ privatestaticfinalStringTAG="Test"; //返回null publicIBinderonBind(Intentintent){ Log.i(TAG,"ServiceonBind--->"); returnnull; } //Service创建时调用 publicvoidonCreate(){ Log.i(TAG,"ServiceonCreate--->"); } //当客户端调用startService()方法启动Service时,该方法被调用 publicvoidonStart(Intentintent,intstartId){ Log.i(TAG,"ServiceonStart--->"); } //当Service不再使用时调用 publicvoidonDestroy(){ Log.i(TAG,"ServiceonDestroy--->"); } //当解除绑定时调用 publicbooleanonUnbind(Intentintent){ Log.i(TAG,"ServiceonUnbind--->"); returnsuper.onUnbind(intent); } } 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/startBtn1" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:text="停止Service" android:id="@+id/stopBtn2" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:text="绑定Service" android:id="@+id/bindBtn3" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:text="解除绑定" android:id="@+id/unbindBtn4" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> 在AndroidManifest.xml文件中添加16~21行的声明 <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.android.bindservice.activity" 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=".BindService"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </service> </application> </manifest> 效果图: 当点击按钮时,先后执行了Service中onCreate()->onStart()这两个方法,LogCat显示如下: 当点击按钮,则Service执行了onUnbind()方法,LogCat显示如下: 当点击按钮,则Service执行了onUnbind()方法,LogCat显示如下: 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/647804

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

hadoop mapreduce开发实践之HDFS压缩文件(-cacheArchive)

1、分发HDFS压缩文件(-cacheArchive) 需求:wordcount(只统计指定的单词【the,and,had...】),但是该文件存储在HDFS上的压缩文件,压缩文件内可能有多个文件,通过-cacheArchive的方式进行分发; -cacheArchive hdfs://host:port/path/to/file.tar.gz#linkname.tar.gz #选项在计算节点上缓存文件,streaming程序通过./linkname.tar.gz的方式访问文件。 思路:reducer程序都不需要修改,mapper需要增加用来读取压缩文件的函数(或模块),运行streaming的时候需要使用-cacheArchive 指定hdfs上的文件; 1.1、 streaming命令格式(-cacheArchive) $HADOOP_HOME/bin/hadoop jar hadoop-streaming.jar \ -jobconf mapred.job.name="streaming_cacheArchive_demo" \ -jobconf mapred.job.priority=3 \ -jobconf mapred.compress.map.output=true \ -jobconf mapred.map.output.compression_codec=org.apache.hadoop.io.compress.GzipCodec \ -jobconf mapred.output.compress=true \ -jobconf mapred.out.compression.codec=org.apache.hadoop.io.compress.GzipCodec \ -input /input/ \ -output /output/ \ -mapper "python mapper.py whc.tar.gz" \ -reducer "python reducer.py" \ -cacheArchive "hdfs://master:9000/cache_file/wordwhite.tar.gz#whc.tar.gz" -file ./mapper.py \ -file ./reducer.py 1.2、mapper程序 #!/usr/bin/env python # -*- coding:utf-8 -*- import os import os.path import sys def getCachefile(filename): filelist = [] if os.path.isdir(filename): for root, dirs, files, in os.walk(filename): for name in files: filepath = root + '/' + name filelist.append(filepath) return filelist def readWordwhite(filename): wordset = set() for cachefile in getCachefile(filename): with open(cachefile, 'r') as fd: for line in fd: word = line.strip() wordset.add(word) return wordset def mapper(filename): wordset = readWordwhite(filename) for line in sys.stdin: line = line.strip() words = line.split() for word in words: if word != "" and (word in wordset): print "%s\t%s" %(word, 1) if __name__ == "__main__": if sys.argv[1]: file_fd = sys.argv[1] mapper(file_fd) 1.3、 reducer程序 #!/usr/bin/env python # -*- coding:utf-8 -*- import sys def reducer(): currentword = None wordsum = 0 for line in sys.stdin: wordlist = line.strip().split('\t') if len(wordlist) < 2: continue word = wordlist[0].strip() wordvalue = wordlist[1].strip() if currentword == None: currentword = word if currentword != word: print "%s\t%s" %(currentword, str(wordsum)) currentword = word wordsum = 0 wordsum += int(wordvalue) print "%s\t%s" %(currentword, str(wordsum)) if __name__ == "__main__": reducer() 1.4、上传wordwhite.tar.gz $ ls -R wordwhite wordwhite: wordwhite01 wordwhite02 wordwhite03 $ cat wordwhite/wordwhite0* have and had the in this or this to $ tar zcf wordwhite.tar.gz wordwhite $ hadoop fs -put wordwhite.tar.gz hdfs://localhost:9000/input/cachefile/ 1.5、 run_streaming程序 #!/bin/bash HADOOP_CMD="/home/hadoop/app/hadoop/hadoop-2.6.0-cdh5.13.0/bin/hadoop" STREAM_JAR_PATH="/home/hadoop/app/hadoop/hadoop-2.6.0-cdh5.13.0/share/hadoop/tools/lib/hadoop-streaming-2.6.0-cdh5.13.0.jar" INPUT_FILE_PATH="/input/The_Man_of_Property" OUTPUT_FILE_PATH="/output/wordcount/WordwhiteCacheArchiveFiletest" $HADOOP_CMD fs -rmr -skipTrash $OUTPUT_FILE_PATH $HADOOP_CMD jar $STREAM_JAR_PATH \ -input $INPUT_FILE_PATH \ -output $OUTPUT_FILE_PATH \ -jobconf "mapred.job.name=wordcount_wordwhite_cacheArchivefile_demo" \ -mapper "python mapper.py WHF.gz" \ -reducer "python reducer.py" \ -cacheArchive "hdfs://localhost:9000/input/cachefile/wordwhite.tar.gz#WHF.gz" \ -file "./mapper.py" \ -file "./reducer.py" 1.6、执行程序 $ chmod +x run_streaming.sh $ ./run_streaming.sh rmr: DEPRECATED: Please use 'rm -r' instead. Deleted /output/wordcount/WordwhiteCacheArchiveFiletest 18/02/01 17:57:00 WARN streaming.StreamJob: -file option is deprecated, please use generic option -files instead. 18/02/01 17:57:00 WARN streaming.StreamJob: -cacheArchive option is deprecated, please use -archives instead. 18/02/01 17:57:00 WARN streaming.StreamJob: -jobconf option is deprecated, please use -D instead. 18/02/01 17:57:00 INFO Configuration.deprecation: mapred.job.name is deprecated. Instead, use mapreduce.job.name packageJobJar: [./mapper.py, ./reducer.py, /tmp/hadoop-unjar211766205758273068/] [] /tmp/streamjob9043244899616176268.jar tmpDir=null 18/02/01 17:57:01 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032 18/02/01 17:57:01 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032 18/02/01 17:57:03 INFO mapred.FileInputFormat: Total input paths to process : 1 18/02/01 17:57:03 INFO mapreduce.JobSubmitter: number of splits:2 18/02/01 17:57:04 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1516345010544_0030 18/02/01 17:57:04 INFO impl.YarnClientImpl: Submitted application application_1516345010544_0030 18/02/01 17:57:04 INFO mapreduce.Job: The url to track the job: http://localhost:8088/proxy/application_1516345010544_0030/ 18/02/01 17:57:04 INFO mapreduce.Job: Running job: job_1516345010544_0030 18/02/01 17:57:11 INFO mapreduce.Job: Job job_1516345010544_0030 running in uber mode : false 18/02/01 17:57:11 INFO mapreduce.Job: map 0% reduce 0% 18/02/01 17:57:20 INFO mapreduce.Job: map 50% reduce 0% 18/02/01 17:57:21 INFO mapreduce.Job: map 100% reduce 0% 18/02/01 17:57:27 INFO mapreduce.Job: map 100% reduce 100% 18/02/01 17:57:28 INFO mapreduce.Job: Job job_1516345010544_0030 completed successfully 18/02/01 17:57:28 INFO mapreduce.Job: Counters: 49 File System Counters FILE: Number of bytes read=113911 FILE: Number of bytes written=664972 FILE: Number of read operations=0 FILE: Number of large read operations=0 FILE: Number of write operations=0 HDFS: Number of bytes read=636501 HDFS: Number of bytes written=68 HDFS: Number of read operations=9 HDFS: Number of large read operations=0 HDFS: Number of write operations=2 Job Counters Launched map tasks=2 Launched reduce tasks=1 Data-local map tasks=2 Total time spent by all maps in occupied slots (ms)=12584 Total time spent by all reduces in occupied slots (ms)=4425 Total time spent by all map tasks (ms)=12584 Total time spent by all reduce tasks (ms)=4425 Total vcore-milliseconds taken by all map tasks=12584 Total vcore-milliseconds taken by all reduce tasks=4425 Total megabyte-milliseconds taken by all map tasks=12886016 Total megabyte-milliseconds taken by all reduce tasks=4531200 Map-Reduce Framework Map input records=2866 Map output records=14734 Map output bytes=84437 Map output materialized bytes=113917 Input split bytes=198 Combine input records=0 Combine output records=0 Reduce input groups=8 Reduce shuffle bytes=113917 Reduce input records=14734 Reduce output records=8 Spilled Records=29468 Shuffled Maps =2 Failed Shuffles=0 Merged Map outputs=2 GC time elapsed (ms)=390 CPU time spent (ms)=3660 Physical memory (bytes) snapshot=713809920 Virtual memory (bytes) snapshot=8331399168 Total committed heap usage (bytes)=594018304 Shuffle Errors BAD_ID=0 CONNECTION=0 IO_ERROR=0 WRONG_LENGTH=0 WRONG_MAP=0 WRONG_REDUCE=0 File Input Format Counters Bytes Read=636303 File Output Format Counters Bytes Written=68 18/02/01 17:57:28 INFO streaming.StreamJob: Output directory: /output/wordcount/WordwhiteCacheArchiveFiletest 1.7、 查看结果 $ hadoop fs -ls /output/wordcount/WordwhiteCacheArchiveFiletest Found 2 items -rw-r--r-- 1 hadoop supergroup 0 2018-02-01 17:57 /output/wordcount/WordwhiteCacheArchiveFiletest/_SUCCESS -rw-r--r-- 1 hadoop supergroup 68 2018-02-01 17:57 /output/wordcount/WordwhiteCacheArchiveFiletest/part-00000 $ hadoop fs -text /output/wordcount/WordwhiteCacheArchiveFiletest/part-00000 and 2573 had 1526 have 350 in 1694 or 253 the 5144 this 412 to 2782 以上就完成了分发HDFS上的压缩文件并指定单词的wordcount. 2、hadoop streaming 语法参考 http://blog.51cto.com/balich/2065419 本文转自 巴利奇 51CTO博客,原文链接:http://blog.51cto.com/balich/2067858

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

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

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册