首页 > 系统 > Android > 正文

Android面试宝典 --第三章组件

2019-11-09 16:46:30
字体:
来源:转载
供稿:网友

Android面试宝典

          –第三章组件

          本文对Android面试宝典的面试题目做一点总结和记录,希望对大家面试或简单复习有帮助。           这里的组件不仅仅是Android中组重要的四大应用组件,还有其他基础组件如TextView,ImageView等等。

一.组件的属性

(一)android:id属性是必须的吗?请解释一下该属性的作用。

答案:id在xml布局文件中并不是必须的。Android:id的作用:1.在相对布局(RelativeLayout)中,需要使用相对位置来显示另一个组件时,作为参照物的组件是必须要设置id的。2.需要在java代码中进行动态设置的组件也是需要设置id属性标签。

(二)请描述一下android:padding和android:layout_margin的区别?

答案:padding用于设置组件内容到组件边缘的距离。Layout_margin用于设置组件到另一个组件(或者到父框体)之间的距离。

(三)请描述一下android:gravity和android:layout_gravity属性的区别?

答案:gravity可以设置组件内容相对于组件的位置,比如可以设置TextView中的文本字体居中显示或居左显示。Layout_gravity可以设置当前组件相对于在父组件内的位置,比如可以设置一个TextView的组件是在FrameLayout布局的左边还有右边。

(四)请说出android:layout_weight属性的功能,并举例说明该属性的用法。

答案:layout_weight属性当前组件在水平或垂直方向所占的空间,该属性一般是在线性布局中使用,表示权重的意思。示例: <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="老一" /> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="老二" /> <Button android:layout_weight="2" android:layout_width="0dp" android:layout_height="wrap_content" android:text="老三" /> </LinearLayout>这里水平方向显示三个按钮,权重分别是1,1,2。

二.文本组件

(一)请说出AndroidSDK支持哪些方式显示富文本信息(不同颜色、大小,并包含图像的文本信息)?简要说明其实现方法。

答案:AndroidSDK支持如下显示富文本信息的方式:1.使用HTML标签语言文本,如<font>可以设置字体大小和颜色,<b>可以设置粗体,首先要使用Html.fromHtml方法将这些标签语言文本转换为CharSequence对象,然后再将该对象作为TextView.setText方法的参数值。2.使用WebView组件显示HTML页面。3.继承View类或View的子类,并重写onDraw方法,在该方法中直接绘制富文本或图像。4.TextView组件中显示图像还可以使用ImageSpan对象,ImageSpan对象用于封装Bitmap对象,并通过SpannableString对象来封装ImageSpan对象,最后将SpannableString对象作为TextView.setText方法的参数值将图像显示在TextView组件上。

(二)如何为TextView组件中显示的文本添加背景色?

答案:Span对象的考察:示例代码: String str="这是设置TextView部分文字背景颜色和前景颜色的demo!"; int bstart=str.indexOf("背景"); int bend=bstart+"背景".length(); int fstart=str.indexOf("前景"); int fend=fstart+"前景".length(); SpannableStringBuilder style=new SpannableStringBuilder(str); style.setSpan(new BackgroundColorSpan(Color.RED),bstart,bend,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); style.setSpan(new ForegroundColorSpan(Color.RED),fstart,fend,Spannable.SPAN_EXCLUSIVE_INCLUSIVE); TextView tvColor=(TextView) findViewById(R.id.tv_color); tvColor.setText(style);

效果: t3 这里第一部分是设置字体背景色,第二部分是字体颜色。

(三)在设计电子词典程序时,当用户输入单词时,应显示以当前输入单词开头的单词列表。AndroidSDK中哪个组件可以实现这个功能,请写出核心实现代码。

解析:本题考察的是AutoCompleteTextView组件的用法以及如何将数据库的数据与该组件放在结合使用答案:使用AutoCompleteTextView组件可以在文本输入框下方显示一个列表,用于显示当前输入字符串开头的单词列表。获取以某些字符开头的单词列表的代码应该放在TextWatcher.afterTextChanged方法中,在该方法中会不断更新单词列表,代码如下:Public void afterTextchanged(Editable s){ //查询以当前输入的字符开头的单词 Cursor cursor=database.rawQuery(“select english as _id from t_Words where english like ?”,new String[]{s.toString+%}) //创建适配器对象,DictionaryAdapter是自定义的继承CursorAdapter的类 DictionaryAdapter dictionaryAdapter=new DictionaryAdapter(this,cursor,true); autoCompleteTextView.setAdapter(dictionaryAdapter);}

三.按钮组件

(一)在按钮上显示图片的方式有哪些?

解析:Button是TextView的子类,所有可以使用SpannableString来显示图片,但是AndroidSDK提供了一个专门显示图像的按钮组件ImageView,并且可以稍微说一下RadioButton也是可以显示图片。最好写出显示图片的核心代码或xml代码。答案:AndroidSDK支持在Button、ImageButton以及RadioButton上显示图像。Button和RadioButton显示图像的方式如下两种:1.使用android:drableXxx(Xxx表示Left、Top、Right和Button)属性将图像显示在文字的周围(上下左右四个方向);2.与TextView组件类似,使用ImageSpan封装Bitmap对象,使用SpannableString.setSpan方法设置ImageSpan对象,最后调用Button.setText方法设置SpannableString对象来显示图像。ImageButton:使用android:src属性指定图像文件的资源,跟ImageView绑定的用法一样。

(二)如何用代码动态改变Button的大小和位置?

答案:由于Button是View的子类,因此,可以使用Button.layout(l,t,r,b);方法动态改变Button的大小和位置。Layout方法有四个参数,分别表示Button距离父框体左边、顶上、右边和下边的距离。比如这里r值和b值增加按钮的右边和下边会发生延伸变长。

(三)如果想让一个显示图像的按钮在不同状态显示不同的图像,应该如何做?

解析:考察drawable资源的使用,选择器selector!答案:使用drawable资源可以很容易地实现按钮图像切换的功能。如果只是简单地切换图像状态(如按下、获得焦点、正常状态),可以使用状态资源,然后通过Button按钮的android:background属性指定该状态资源文件的ID即可。状态资源文件需要在drawable目录中创建一个XML文件,并在<selector>标签中指定各种状态对应的状态图像。资源文件的简单示例:<selector xmlns:android:”http://schemas.android.com/apk/res/android”><!--按钮按下的状态显示的图片 --><item android:state_PRess=”true” android:drawable=”@drawable/press”><!--按钮处于焦点的状态显示的图片 --><item android:state_focused=”true” android:drawable=”@drawable/focused”><!--按钮正常的状态显示的图片 --><item android:drawable=”@drawable/normal”></selector>

四.图像组件

(一)如何实现图像的半透明,请阐述其实现过程,并写出必要的实现代码。

解析:设置图像透明一般可以使用Paint.setAlpha方法,但也可以使用<FrameLayout>标签通过图层的方式实现图像的半透明效果。

答案:可以采用如下两种实现图像半透明的方法。

1.使用Paint.setAlpha方法设置图像的透明度。基本原理是先使用Bitmap对象装载图像,然后在View.onDraw方法中使用Canvas.drawBitmap方法将Bitmap对象绘制到当前的View上。核心代码:InputStream is=getResources().openRawResource(R.drawable.image);//装载图像Bitmap bitmap=BitmapFactory.decodeStream(is);//重写onDraw方法Protected void onDraw(Canvas canvas){ Pain paint=new Paint(); //绘制半透明的图像 canvas.drawBitmap(bitmap,new Rect(0,0,bitmap.getWidth(),bitmap.getHeight()), new Rect(0,0,bitmap.getWidth(),bitmap.getHeight()),paint);}2.可以在不透明的图像上覆盖一层半透明的膜(可以使用半透明的ImageView实现)布局代码如下:<FrameLayout xmlns:android=“http://schemas.android.com/apk/res/android”android:layout_width=”match_parent”androidd:layout_height=”match_parent”<!-- 不透明的图像 --><ImageView android:layout_width=”match_parent”androidd:layout_height=”match_parent”android:src=”@drawable/image”/><!-- 半透明的薄膜(通过android:background属性设置实现) --><ImageView android:layout_width=”match_parent”androidd:layout_height=”match_parent”android:background=”#EFFF”/></FrameLayout>

(二)如何在ImageView组件中显示图像的一部分。

解析:在ImageView中显示图像的一部分最直接的方法就是截取图像的一部分显示。当然,使用图像剪切资源也可以实现截取图像的效果。只不过图像剪切资源只能从图像的一端开始截取,并没有直接截取图像灵活。答案:有两种方式实现:如果想任意截取图像,可以使用Bitmap.createBitmap方法在原图图像的基础上截获某一部分图像,并创建图像的Bitmap对象,代码如下://获取(20,20,100,100)范围的图像Bitmap smallBitmap=Bitmap.createBitmap(sourceBitmap,20,20,100,100);//获取的图像显示在ImageView组件中imageView.setImageBitmap(smallBitmap);如果只想从图像的一端(上、下、左、右)截取图像,也可以使用图像剪切资源。这种资源需要在res/drawable目录中创建一个xml的资源文件,资源文件的文件名要在ImageView布局中使用,并使用下面的代码从图像左侧开始截取图像,然后只需要将图像剪切资源当成普通图像资源使用即可。myclip.xml文件的设计:<?xml version="1.0" encoding="utf-8"?><clip xmlns:android="http://schemas.android.com/apk/res/android" android:clipOrientation="horizontal" android:drawable="@drawable/a16" android:gravity="left" ></clip>布局文件中的调用: <ImageView android:id="@+id/iv" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/myclip" />Java代码设计: 只使用图像剪切资源还无法获得图像剪切效果,最后需要使用ClipDrawable.setLevel方法设置截取的百分比。 系统预定义了10000为100%,下面的代码从图像左侧截取了30%。ImageView imageView=(ImageView)findViewById(R.id.image);ClipDrawable drawable=(ClipDrawable)iamgeView.getDrawable();//中左侧开始截取图像的50%drawable.setLevel(5000);

在资源文件中将android:clipOrientation属性设置为vertical,可以从上、下两个方向截取图像。

(三)如何为图像加上边框?

答案:首先做一个透明的带边框的nine-patch格式图像,然后通过<ImageView>标签的android:background属性指定这个图像就可以为图像加上边框。其实ImageView设置background并且设置padding就可以实现,不用什么九派图片(这是我个人的经验)。都要设置src属性。

(四)请描述如何使用Matrix对象旋转和缩放图像?

1.使用Matrix.setRotate可以实现图像的旋转主要代码:Bitmap bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.dog));Matrix matrix=new Marist();//顺时针旋转45°matrix.setRotata(45);//旋转图像,并为旋转后的图像创建新的Bitmap对象Bitmap=Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),,matrix,true);//在ImageView组件中显示旋转后的图像imageView.setImageBitmap(bitmap);2.使用Matrix.setScale可以实现图像的缩放主要代码:Bitmap bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.dog));Matrix matrix=new Marist();//图像等比例缩小50%matrix.setScale((float)0.5,(float).05);//缩小图像,并为缩小后的图像创建新的Bitmap对象Bitmap=Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),,matrix,true);//在ImageView组件中显示缩小后的图像imageView.setImageBitmap(bitmap);

五.进度组件

(一)ProgressBar的进度条颜色是否可以修改?如果可以修改,请写出具体的实现代码。

答案:可以改变ProgressBar的进度颜色。ProgressBar有3种颜色:背景颜色、第一级进度颜色,第二级进度颜色。可以使用图层列表(layer-list)资源修改这三种颜色。首先需要准备3个纯色的图像,然后在res/drawable目录中建立一个progressbar.xml文件,并输入下面的内容:<?xml: version=”1.0” encoding=”UTF-8”?><layout-list xmlns:android=”htttp://schemas.android.com/apk/res/android”><!-- 设置背景色的图像资源 --><item android:id=”@android:id/background” android:drawable=”@drawable/bg”><!-- 设置第二级进度条的颜色的图像资源 --><item android:id=”@android:id/secondaryProgress” android:drawable=”@drawable/seconddary”><!-- 设置第一级进度条颜色的图像资源 --><item android:id=”@android:id/progress” android:drawable=”@drawable/progress”></layout-list>最后在<ProgressBar>标签中使用android:progressDrawable属性指定Progressbar.xml文件的资源ID即可。

(二)如何实现垂直进度条。

解析:AndroidSDK并没有提供垂直进度条组件,因此,可以自己绘制垂直进度条。答案:垂直进度条需要自己来绘制。绘制进度条可以有多种方法,比如可以重写onDraw、onMeasure和onSizeChange方法。public class VerticalProgressBar extends ProgressBar { public VerticalProgressBar(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public VerticalProgressBar(Context context) { super(context); // TODO Auto-generated constructor stub } @Override protected synchronized void onDraw(Canvas canvas) { // TODO Auto-generated method stub canvas.rotate(-90);//反转90度,将水平ProgressBar竖起来 //将经过旋转后得到的VerticalProgressBar移到正确的位置, //注意经旋转<span style="white-space:pre"> </span> 后宽高值互换 canvas.translate(-getHeight(), 0); super.onDraw(canvas); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(heightMeasureSpec, widthMeasureSpec); setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());//互换宽高值 } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(h, w, oldw, oldh);//互换宽高值 } }

六.列表组件

(一)将数据显示在ListView组件中可以使用BaseAdapter的子类,请描述如何使用BaseAdapter的抽象方法?

解析:先说出BaseAdapter类的四个抽象方法,然后详细描述如何使用getCount和getView方法。答案:BaseAdapter类有四个抽象方法,getItem,getItemId,getCount,getView,其中前两个方法分别返回object对象和long对象类型的值。不一定要在这两个方法中编写具体的代码,一般用这两个方法返回与当前列表项相关的对象和列表项的ID(当然也可以返回任何与业务相关的数据);必须在getCount和getView方法中编写实际代码。getCount方法返回列表数据的总数,例如,列表数据来自数组,getCount方法应返回数组的长度。getView方法返回在当前列表项显示的View对象。我们并不需要为每个列表项创建一个新的View对象。系统会保存曾经显示过的列表项的View对象,如果要显示新的列表项,可以利用这些被保存起来的View对象。getView方法只有过一个convertView参数,如参数值为null,表示没有View对象可以利用,需要创建新的View对象。如果给参数值不为null,可以直接返回这个对象。参考代码:public view getView(int position,View convertview,ViewGroup parent){ //需要创建一个View对象 if(convertViet==null){ convertView=layoutInflater.inflate(R.layout.list_item,null); } Return convertView;}

(二)如何对GridView、ListView等列表组件中的数据进行增删改查操作?

解析:列表组件采用MVC模式,因此不能直接使用组件对象对数据进行增删改查操作,必须在修改数据后使用notifyDataSetInvalidated方法通知列表组件刷新数据。答案:首先应直接对数据源中的数据进行增删改查操作,然后调用BaseAdapter.notifyDataSetInvalidated方法通知列表组件更新数据。在调用notifyDataSetInvalidated方法后系统会立即调用BaseAdapter.getView方法来获取当前显示的列表项的View对象,这样就会更新当前列表中显示的数据。

(三)在ListView组件中显示数据库中的数据应如何做?

答案:如果显示的数据很简单,可以用SimpleCursorAdapter;如果数据很复杂,可以编写一个继承自CursorAdapter的类,并在newView方法中创建新的列表View对象,在bindView方法中为相应的组件赋值。

(四)如何改变ListView列表项的背景色?

答案:改变列表项选中状态的背景色可以使用<ListView>标签的android:listSelector属性,也可以使用ListView.setSelector方法。例如,将背景设置为绿色的方法是先将一个绿色的png图片(green.png)复制到res/drawable目录下,然后在<ListView>标签中设置android:listSelector=”@drawable/green”,或使用如下代码:ListView listView=(ListView)findViewById(R.id.listView);listView.setSelector(R.drawable.green);

(五)如果要做一个文件管理器,使用GridView组件显示文件列表,有的文件需要显示缩略图(如图像文件,视频文件,apk文件),应该如何优化显示过程?

解析:最好的做法就是使用任务队列技术,也就是在getView方法中要显示某个图像文件的缩略图,可以先将该任务添加到任务队列中,然后使用另一个线程不断扫描任务队列,并处理为完成的任务。当处理完某个任务后,可以刷新GridView组件的适配器来显示该图像文件的缩略图。答案:如果在BaseAdapter.getView方法中执行较耗时的操作时,需要进行异步处理,否则会使列表滑动出现卡顿的现象。可以使用数组或List对象简历任务队列和数据缓冲。getView方法中一旦遇到比较耗时的任务(如显示文件缩略图,从网络下载图像等),需要将这些操作加入到任务队列中,然后再使用另一个线程从任务队列中取得相应的任务,并执行当前的任务,最后需要调用BaseAdapter.notifyDataSetChange方法刷新列表中的数据。如果再次显示当前列表项,需要直接从数据缓冲中获取数据。线程可以通过不断扫描任务队列的方式获取任务,代码如下:public void ScanTaskThread extends Thread{ public void run(){ While(true){ //扫描任务队列以获取并处理任务 。。。 Thread.sleep(100);//每100毫秒扫描一次任务队列 } }}

(六)如何为ListView组件加上快速滑块,是否可以修改快速滑块图像?

解析:快速滑块就是ListView右边出现的小竖条。答案:使用布局文件需要将android:fastScrollEnabled属性设为true,使用java代码需要调用ListView.setFastScrollEnabled(true);方法ListView组件并没有提供修改快速滑块图像的API,因此不能直接修改快速滑动块图像。但可以通过反射技术修改快速滑动块图像,代码如下://FastScroller.mThumbDrawable变量保存了快速滑动块图像,首先要通过AbsListView.mFastScroller变量//获取FastScroller对象Field field=AbsListView.Class.getDeclaredField(“mFastScroller”);field.setaccessible(true);Object obj=field.get(listView);//获取FastScroller.mThumbDrawable变量的Field对象field=field.getType().getDeclaredField(“mThumbDrawable”);field.setAccessible(true);//获取FastScroller.mThumbDrawable变量的值Drawable drawable=(Drawable)field.get(obj);//装载新的快速滑动块图像drawable=getResource().getDrawable(R.drawable.image);//重新设置快速滑块的图像field.set(obj,drawable);

七.容器组件

(一)请尽可能说出AndroidSDK支持的容器组件。

解析:只要是ViewGroup的子类,就是容器组件,包含几大布局和AdapterView的几个子类。一般的问法只问:Android有几大布局?答案: 包括两个部分,一部分是Android有六大布局组件,线性布局LinearLayout,相对布局RelativeLayout, 帧布局FrameLayout,绝对布局AbsoluteLayout,表格布局TableLayout,网格布局GridLayout。另一部分是AdapterView的三个子类,ListView,GridView,Gallery。

(二)如何使用容器内的组件可以水平和垂直滑动?

答案:将scrollView和HorizontalScrollView组件结合使用,就可以实现垂直和水平滚动的效果。所谓结合,就是在<ScrollView>标签中使用<HorizontalScrollView>标签,或在<HorizontalScrollView>标签中使用<ScrollView>标签。

(三)如何使用Gallery循环显示图像?例如,通过一个数组(长度为10)保存图像文件路径,用Gallery组件显示组件中的路径对应图像。当Gallery组件显示到第10个图像后,第11个图像仍然显示第一个图像。

解析:本题实际上考察的不是Gallery组件的方法,而是考察BaseAdapter.getView和BaseAdapter.getCount方法的应用技巧,为了达到循环的效果,使getCount方法返回一个较大的数就可以,并且getView中的数据显示的position%10的数据。这个应用在Viewpager中也是比较常见的,比如要实现不限滑动的效果。答案:使BaseAdapter.getCount方法返回一个比较大的值(如Integer.MAX_VALUE),这是BaseAdapter.getView方法中不能直接通过Position参数获得数据的位置,需要将position参数值对10取余,并将余数作为新的数据位置,代码如下:int newPosition=position%10;

八.自定义组件

(一)如果想编写一个自定义的可视组件,你打算怎么做?

解析:本题考查开发者是否了解自定义组件答案:开发自定义可视组件一般使用如下3中模式:1.扩展现有的组件,如组件类可以直接继承自TextView。2.组合多种组件,如组件类可以直接继承容器(六大布局),可将多个组件添加到组件类中。3.直接从View继承。此类组件需要从零开始编写。一般要从写三个比较重要的方法onMeasure、onSizeChange、onDraw,如果是有划屏还要重写onTouchEvent方法。

(二)Android支持的四大应用程序组件()可以封装在jar文件中吗?使用是应该注意什么?

答案:四大应用程序组件可以放在 jar文件中,并在Android工程中静态应用jar文件。虽然与四大应用程序组件相关的.class文件都封装在jar文件中,但在使用这些组件中仍然需要在主工程的AndroidManifest.xml文件中进行注册,否则无法使用这些组件。

(三)在Android程序中java和Javascript是如何进行交互的?

解析:在Android应用程序中可以是使用java代码和javaScript脚本之间进行交互,所谓的交互就是互相调用以及传递数据。这项技术的核心是WebView组件。该组件不仅可以执行JavaScript脚本,也允许在javaScript脚本中执行java代码。由于JavaScript可动态运行,并且可以执行Java代码,所以JavaScript也常被当做Android的动态组件来使用。答案:Java代码执行JavaScript脚本可以使用WebView组件,代码如下:WebView webView=new WebView(this);WebSetting webSttings=webView.getSettings();//必须执行下面的语句,否则WebView无法执行JavaScript脚本webSetting.setJavaScriptEnabled(true);webSettomg.setWebChromeClient(new WebChromeClinet());//s为String类型变量,保存了JavaScript脚本webView.loadDataWithBaseURL(null,s,”text/html”,”utf-8”,null);在Java代码和JavaScript脚本之间传递数据以及使JavaScript脚本可以执行Java代码需要使用WebView.addJavascriptInterface方法添加可以在JavaScript中调用的Java方法,代码如下:webView.addJavascriptInterface(new Object(){ //可以在JavaScript中调用java代码 public void move(int x,int y){ //java代码 }},“demo”);//demo为在JavaScript中可访问的对象,通过该对象调用move方法在JavaScript脚本中调用move方法的代码如下:<script language=”javascript”> //调用move方法 Window.demo.move(20,100);</script>

(四)请写出安装apk程序的代码。

答案:安装apk程序的代码如下:Intent intent=new Intent(Intent.ACTION_VIEW);//指定apk文件的路径String filePath=“/sdcard/FileExplorer.apk”;//指定文件的类型intent.setDataAndType(Uri.parse(“file://”+filePath),,”application/vnd.android.package-archive”);//执行这句语句会弹出安装界面startActivity(intent);

九.四大程序应用组件

第一个应用组件:Activity

(一)如何配置Activity才能让程序启动时将Activity作为启动窗口?

解析:AndroidManifest中的配置,设置Activity的Action的。答案:在对应的Activity标签<activity>中,添加 <action android:name="android.intent.action.MAIN" />就可以,示例代码:<activity android:name="me.drakeet.QQsliddingmenu.MyActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter></activity>值得注意的是一个程序只能有一个入口!

(二)请阐述Activity中有哪几个生命周期方法以及在Activity显示和销毁的过程中生命周期方法执行的顺序?

答案:Activity共有七个生命周期方法:onCreate,onStart,onResume,onPause,onStop,onDestroy,onRestart。Activity显示的过程会依次执行onCreate,onStart,onResume,在Activity销毁的过程中会依次调用onPause,onStop和onDestroy。在执行onPause或onStop后如果Activity重新获得焦点,系统会调用onReStart方法,接着调用onStart和onResume方法。

(三)请描述调用Activity有哪几种方法?写出相关的java代码。

答案:可以采用两种方式调用Activity:显示调用和隐式调用。显示调用直接指定了Activity,代码如下:Intent intent=new Intent(this,MyActivity.class);//调用MyActivity实现跳转startActivity(intent);隐式调用通过Activity Action来调用。这种方式可以调用当前应用程序中的Activity,也可以调用其他应用程序中的Activity。隐式调用的代码如下://指定Activity ActionIntent intetn=new Intent(“mobile.android.MYACTION”);//调用可接收MYACTION动作的Activity,如果系统中有多个Activity可接收MAIN动作//则会显示一个菜单供用户选择调用哪个ActivitystartActivity(intent);

(四)在Activity之间如何传递数据,请尽可能说出你知道的传递数据的方法,并详细描述其实现的过程。

解析:由于AndroidSDK限制,不能直接调用Activity时直接访问Activity对象,因此,就不能像普通对象之间传递数据一样通过构造方法或类成员传递数据。其实传递数据的方法是蛮多的,比如最常用的Intent数据传递,单例模式的数据传递,广播的方式发送数据等等。

答案:可以通过Intent对象,静态变量、剪切板和全局对象进行数据传递,具体的数据传递方法如下:

1.Intent对象Intent对象是在Activity之间传递数据的传统方式(同样适合于Service和BroadcastReceiver)。可以通过Intent.putExtra方法设置要传递的数据,通过Intent.getXxxExtra方法获取传递的数据。其中Xxx代表Int、String等数据类型。下面的代码使用Intent对象传递数据://创建Intent对象,指定跳转的页面Intent intent=new Intent(this,MyActivity.class);//保存Int类型的数据intent.putExtra(“num”,100);//保存String类型的数据intent.putExtta(“name”,”liwen”);//保存序列化对象 People people = new People();//People已经实现了序列化//给people对象设置值,或者在构造方法传入参数 intent.putExtra("people", people);获取数据//获取Int类型的数据,可以设置一个默认值Int num=getIntent().getExtras().getInt(“num”,0);//获取String类型的数据String name=getIntent().getExtras().getString(“name”);//获取People对象的数据,两种不同序列化后的取法People people=getIntent().getExtras().getSerializable(“people”);People people=getIntent().getExtras().getParcelable(“people”);Intent还能传递的数据有:8种基本数据类型,以及它们的数组数据。和Bundle对象。2.静态变量将成员定义成public static,就可以直接通过类成员来传递数据。使用静态变量可以传递任何类型的数据。3.剪切板(用得不多!)可以利用Android系统提醒的剪切板存数据,代码如下:Intent intent=new Intent(this,MyActivity3.class);//获得管理剪切板对象(ClipBoardManager)ClipboardManager clipboard=(ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);//向剪切板保存字符串clipboard.setText(“通过Clipboard传递的数据”);startActivity(intent);//从剪切板中获取数据ClipboardManager clipboard=(ClipboardManger)getSystrmService(Context.CLOPBOARD_SERVICE);//从剪切板获得字符串String text=clipboard.getText().toString();//传递数据的限制,只能传递文本数据以及Intent对象支持的数据。4.全局对象可以为每一个应用程序定义一个全局的对象。该对象的创建由系统负责。使用全局对象需要一个继承自Android.app.Application的类,并在该类中定义任何类型的成员变量和方法。(1)创建一个MyApp类继承Applicationpublic class MyApp extends Application { @Override public void onCreate() { super.onCreate(); application = new MyApp(); } private MyApp() { } private static Application application; public static Application getInstance() { return application; } private String path; public void setPath(String path) { this.path = path; } public String getPath() { return path; }}(2)在AndroidManifest.xml中定义MyApp <application android:name=".MyApp" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name"android:theme="@style/APPTheme" >(3)在任何一个地方设置属性MyApp.getInstance().setPath("/storage/emulated/aa");(4)在任何一个地方获取属性String path=MyApp.getInstance().getPath();

(五)请写出直接拨号、将电话号码传入拨号程序、调节拨号程序、调用系统浏览器浏览网页、调用系统程序查看联系人、显示系统设置界面和显示Wi-Fi设置界面的java代码。

答案:1.拨号的代码如下:Intent callIntent=new Intent(Intent.ACTION_CALL,Uri.parse(“tel:12345678”));startActivity(callIntent);2.电话号码传入拨号程序的代码如下(上面是直接拨打,这个是输入号码后快要拨打的界面):Intent dialIntent=new Intent(Intent.ACTION_DIAL,Uri.parse(“87654321”));startActivity(dialIntent);3.调用拨号程序的代码(这是没有输入号码的拨号界面):Intent touchDialerIntent=new Intent(“com.android.phone.action.TOUCH_DIALER”);startActivity(touchDialerIntent);4.调用系统浏览器浏览网页的代码如下:Intent webIntent =new Intent(Intent.ACTION_VIEW,Uri.parse(“https://www.baidu.com”));startActivity(webIntent);5.调用系统程序查看联系人的代码如下:Intent contactListIntent=new Intent(“com.android.contacts.action.LIST_CONTACTS”);startActivity(contactListIntent);6.显示系统设置界面的代码Intent settingIntent=new Intent(“android.settings.SETTINGS”);startActivity(settingIntent);7.显示WI-FI设置界面的代码:Intent wifiSettingsIntent=new Intent(“android.settings.WIFI_SETTINGS”);startActivity(wifiSettingsIntent);

(六)如何将Activity变成半透明的对话框?

解析:可以从两个方面考虑:对话框和半透明答案:在定义Activity时指定Theme.Dialog主题就可以将Activity设置成对话框风格。通过修改Theme.Dialog主题的android:widowBackground属性值就可以改变Activity的背景图像。如果背景图像使用半透明的图像,则Activity就会变为半透明的对话框。为了修改android:windowsBackground属性,可以定义一个新的主题,该主题继承自Theme.Dialog,代码如下:<style name=”MyTheme” parent=”@android:style/Theme.Dialog”><item name=”android.windowBackground”>@drawable/msg_background </item></style>然后在定义Activity时指定MyTheme即可,代码如下:<activity android:name=”.main” android:theme=”@style/MyTheme”>...</activity>

(七)如何设置Activity显示和关闭时的动画效果

答案:通过overridePendingTransition方法可以设置Activity显示和关闭的动画效果。首先需要在res/anim目录中建立相应的动画资源文件,然后使用下面的代码在显示和关闭Activity时添加动画效果。Intent intent=new Intent(this,AnimationActivity.class);startActivity(intent);//通过淡入淡出效果显示和关闭ActivityoverridePendingTransition(R.anim.fade_in,R.anim.fade_out);

关于Activity的相关总结: Activity传递数据的经典例子:http://blog.csdn.net/wenzhi20102321/article/details/52750526?locationNum=3&fps=1 Intent的使用总结:http://blog.csdn.net/wenzhi20102321/article/details/52876648?locationNum=5&fps=1

第二个应用组件:广播接收者(BroadcastReceiver)

(1)如何接收广播?

答案:接收广播首先要编写一个广播接收者,该类必须从BroadcastReceiver或其子类继承。在BroadcastReceiver.onReceive(Context context,Intent intent)方法中编写处理广播的代码。但要注意,广播接收者在AndroidManifest.xml文件中注册,代码如下:<receiver android:name=”.ShortMessageReceiver”android:enable=”true”><intent-filter><!-- 指定可以接收的Broadcast Action(可以定义多个Action) --><action android:name=”android.provider.Telephony.SMS_RECEIVED”/></intent-filter></receiver>如果同一个广播接收者处理多个广播,可以使用intent.getAction方法判断当前接收的是哪一个广播,代码如下:if(“action1”.equals(intent.getAction())){ ...//接收到广播做相应的处理}else if(“action2”.equals(intent.getAction())){ ...//接收到广播做相应的处理}

(二)如何获取短信内容,请写出关键的代码。

答案:编写一个广播接收者(ShortMessageReceiver),其中onReceive方法的代码如下:pubic void onReceive(Context context,Intent intent){ Bundle bundle=intent.getExtras(); if(bundle!=null){ //获得收到的短信数据 Object[] objArray=(Object[])bundle.get(“pdus”); //定义封装短信内容的SmsMessage对象数组 SMsMessage[] messages=new SmsMessage[objArray.length]; //循环处理接收到的所有短信 for(int i=0;i<objArray.length;i++){ //将每条短信数据转换成SmsMessage对象 messages[i] =SmsMessage.createFrompdu((byte[])objArray[i]); //获取发送短信的电话号码和短信内容 String s=”手机号:”+message[i].getOriginatingAddress()+”/n”; s+=”短信内容:”+messages[i].getDisplayMessageBody(); //显示发送短信内容的电话号码和短信内容 Toast.makeText(context,s,Toast.LENGTH_LONG).show(); } }}然后在AndroidManifes.xml文件中定义ShortMessageReceiver时添加短信广播Action即可,代码如下:<receiver android:name=”.ShortMessageReceiver” android:enabled=”true”><intent-filter><action android:name=”android.provider.Telephony.SMS_RECEIVED”/></intent-filter></receiver>

(三)如何拦截来电,并在检测到某些特定号码时自动挂断电话?请写出关键代码。

解析:拦截来电只需要编写一个广播接收类即可,但用代码挂断电话从AndroidSDK1.5开始就将这个功能隐藏了,因此,无法通过常规的方法挂断电话。不过可以通过反射技术访问AndroidSDK的内部功能来挂断电话。答案:拦截来电的广播接收类(InCallReceiver)的onRecive方法的代码如下:public void onReceive(final Context context,Intent intent){ //获得电话管理服务,以便获得电话的状态 TelephonyManager tm=(TelephonyManager)context.getSystemServiece(Sercice.TELEPHONY_SERVICE); //根据不同的来电状态进行处理 Switch(tm.getCallState()){ case TelephonyManager.CALL_STATE_RINGING://响铃 String incomingNumber=intent.getStringExtra(“incoming_number”); //如果来电号码是12345678,则挂断电话 if(“12345678”.equals(incomingNumber)){ Class<TelephonyManager>telephonyManagerClass=TelephonyManager.class; //通过java反射技术获取getITelephony方法对应的Method对象 Method telephonyMethod=telephonyManagerClass.getDeclaredMethod( “getITelephony”,(Class[])null); //允许访问getITelephony方法 telephonyMethod.setAccessible(true); //调用getITelephony方法获取ITelephony对象 Object obj=telephonyMethod.invoke(telephonyManager,(Object[])null); //获取与endCall方法对应的Method对象 Method endCallMethod=obj.getClass().getMethod(“endCall”,null); //允许范围endCall方法 endCallMethod.setAccessible(true); //调用endCall方法挂断电话 endCallMethod.invoke(obj,null); } break; case TelephonyManager.CALL_STATE_OFFHOOK: //接听电话 Log.e(“call_state”,”offhook”); break; case TelephonyManager.CALL_STATE_IDLE: //挂断电话 closeToast(); break; }}最后需要在AndroidManifest.xml文件中设置定义广播接收者,并赋予接收广播的权限。配置InCallReceiver的代码如下:<receiver android:name=”.InCallReceiver” android:enabled=”true”><intent-filter><action android:name=”android.intent.action.PHONE_STATE”/></intent-filter></receiver>监听来电状态需要使用下面的代码设置权限。<users-permission android:name=”android.premission.READ_POONE_STATE”/>

(四)如何拦截手机屏幕休眠和唤醒的动作?

解析:在解答本题时首先要弄清楚什么叫屏幕休眠和唤醒。当按手机的电源键时手机黑屏,这叫屏幕休眠,当再次按下手机电源键时屏幕会变亮,并处于锁屏状态,这叫屏幕唤醒。Android允许通过广播接收者来拦截这两个动作。但是要注意,拦截屏幕休眠和唤醒广播的广播接收者只能通过java代码注册,不能在AndroidManifest.xml文件中进行注册,否则不起作用!答案:通过如下两个Broadcast 的Action可以拦截屏幕休眠动作和唤醒动作。休眠状态:Intent.ACTION_SCREEN_ON唤醒状态:Intent.ACTION_SCREEN_OFF假设拦截这两个动作的广播接收者类是ScreenOnOffReceiver,那么注册广播接收者的代码如下:ScreenOnOffReceiver screenOnOffReceiver=new ScreenOnOffReceiver();IntentFilter intentFilter=new IntentFilter();//设置屏幕唤醒广播的动作intentFilter.addAction(Intent.Action_SCREEN_ON);//设置屏幕休眠广播的动作intentFilter.addACtion(Intent.Action_SCREEN_OFF);registerReceiver(screenOnOffReceiver,intentFilter);

(五)如何让一个Activity在开机后自动显示?

解析:Activity本身不会在手机开机后自动运行。想要让手机开机后立刻做一些动作,需要使用广播接收者拦截手机开始广播,并在onReceive方法中完成相应的动作,如打开一个Activity。答案:需要使用广播接收者拦截手机启动广播,然后在onReceiver方法中打开Activity才能在开机时自动显示Activity。广播接收者类(假设:StartupReceiver)的onReceiver方法的代码如下:public void onReceiver(Context context,Intent intent){ Intent mainIntent=new Intent(context,Main.class); //在广播接收者中显示Activity,必须要设置FLAG_ACTIVITY_NEW_TASK标志 mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(mainIntent);}下面需要在AndroidManifest.xml文件中注册StartupReceiver类<receiver android:name=”startupReceiver”><intent-filter><!--指定手机启动的Broadcast Action --><action andorid:name=”android.intent.action.BOOT_COMPLETED”/></intent-filter></receiver>

(六)如何发送广播?

答案:可以通过sendBroadcast方法发送广播。sendBroadcast方法的定义如下://通过intent参数可指定一个广播动作Public void sendBroadcast(Intent intent)下面的代码发送了一个广播,并添加了广播数据和category。//指定广播动作Intent broadcastIntent =new Intent(“mobile.android.MYBROADCAST”);//添加categorybroadcastIntent.addCategory(“mobile.android.mycategory”);//设置广播数据broadcastInetent.putExtra(“name”,”broadcast_data”);//发送广播sendBroadcast(broadcastIntent);

Android广播接收者有一篇个人的总结:http://blog.csdn.net/wenzhi20102321/article/details/53127914

Android四大应用组件的第三个组件:服务(Service)

(一)请描述一下Service的生命周期。

解析:首先应阐述一下Service的生命周期的方法,然后描述一下各个生命周期方法在生命时候被调用。答案:Service共有3个生命周期的方法,这三个方法的定义如下:onCreate();//创建服务onStart();//开始服务onDestroy();//销毁服务 当服务首次被创建是会依次调用onCreate和onStart方法,再次调用startService方法开始一个服务时只会调用一个已经停止了的服务,只会调用onStart方法,而不会调用onCreate方法,除非Service被系统彻底释放。 上面是普通方法startService来启动Service,也可以使用bindService的方法来启动生命周期, 周期方法如下:–> onCreate() –> onBind() –>onUnbind() –>onDestroy

(二)请阐述一下开发AIDL服务的步骤

解析:AIDL(Android InterfaceDefinition Language)是Service的一种重要应用,允许一个程序访问另一个应用程序中的对象。答案:建立AIDL服务的具体步骤如下:1.在Eclipse Android工程的Java源文件目录中建立一个扩展名为aidl的文件。该文件的语法类似于java代码,但是会稍微有点不同。 2.如果aidl文件的内容是正确的,ADT会自动生成一个Java接口文件(*.java);3.建立一个服务类(Service的子类);4.实现有aidl文件生成的Java接口5.在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,<action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类构造方法的参数值。

(三)AIDL服务支持哪些数据?

解析:虽然AIDL服务可以很方便地实现两个应用程序之间的通信,但遗憾的是AIDL服务并不支持所有的Java数据类型。本题也是基于这个原因考察了开发者是否理解哪些类型的数据可以通过AIDL服务进行传递,哪些类型的数据不可以通过AIDL服务进行传递。答案:AIDL服务支持的数据类型如下:1.Java的简单类型(int,char,boolean等)。不需要导入(import)。2.String和CharSequence。不需要导入(import)。3.List和Map。但是要注意,List和Map对象的元素类型必须是AIDL服务支持的数据类型。不需要导入。4.AIDL自动生成的接口。需要导入(import)。5.实现了android.os.Parcelable接口的类。需要导入。

关于Service的总结,之前有两篇自己写的博客: Service使用总结:http://blog.csdn.net/wenzhi20102321/article/details/53155736 AIDL通信总结:http://blog.csdn.net/wenzhi20102321/article/details/53780757

Android的第四个应用组件:内容提供者(Content Provider)

(一) 如何读取联系人信息?请写出核心代码。

答案:使用ContentProvider可以读取联系人信息。例如,下面的代码读取了所有的联系人信息,并将联系人名称显示在ListView组件中。ListView listView=(ListView)findViewById(R.id.listview);//查询系统中所有的联系人Cursor cursor=getContentResolver().query(ContactsContract.Contacts.CONTENT_URL,null,null,null,null);//根据cursor创建SimpleCursorAdapter对象SImpleCursorAdapter simpleCursorAdapter=new SimpleCursorAdapter(this,android.R.layout.simple_list_item_1,curspr,new String[]{ContactsContract.Contacts.DISPLAY_NAME},new int[]{android.R.id.text1});//在ListView控件中显示联系人列表listView.setAdapter(simpleCursorAdapter);//读取联系人信息是要在AndroidManifest.xml文件中添加权限:<user-permission android:name=”android.permossion.READ_CONTACTS”/>

(二)如何查询收发的短信的信息,以及只查收信箱和发信箱?

答案:使用ContentProvider可以读取系统的短信信息。例如下面的代码查询了所有的以1开头的电话号码的短信信息。ListView lvShortMessage=(ListView)findViewById(R.id.lvShortMessages);//按照指定条件查询系统中收到的短信Cursor cursor=getContentResolver().query(Uri.Parse(“content://sms”),null,”address like ?”,new String[]{“1%”},null);lvShortMessages.setAdapter(smsAdapter);如果想值查收信箱可以将“content://sms”改成“content://sms/inbox”.如果只想查发信箱,改成“content://sms/outbox”即可。读取短信信息需要在AndroidManifest.xml文件中打开如下的权限。<user-permission android:name=”android.permossion.READ_SMS”/>

(三)请描述Content ProviderURI有哪几个部分组件。

解析:Content Provider URI与Http URI类似。答案:ContentProvider 的URI分为四个部分:1.”content://”相当于HTTP URI中的”http://”2.”authority”相对于HTTP URI中的域名“www.baid.com”3.路径(path)4.参数(param)假设有如下的ContentProvider URI,其中最后面的数字可以任意变化。content://mobile.android.mydata/product/20其中authority是mobile.android.mydataPath是productParam是20

(四)请描述开发一个ContentProvider的步骤,并写出关键的代码。

答案:开发ContentProvider的步骤如下:1.编写一个类,该类必须继承自ContentProvider2.实现ContentProvider类中的所有抽象方法。3.定义ContentProvider的URI。URI的形式为content://authority/path/param。一般情况下authority建议使用域名,因为域名是唯一的,不会重复。4.在static块中使用UriMatcher对象映射Uri和返回码,代码如下:static{ //开始映射Uri和返回码 uriMatcher =new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY,”cities”,1); uriMatcher.addURI(AUTHORITY,”code/#”,2); //#表示任意数字 uriMatcher.addURI(AUTHORITY,”cities_in_province/*”,3); //*表示任意字符}5.根据实际的需要实现相应的方法。例如,我们只想对数据进行只读操作。可以实现query方法。insert,delete,update方法也可以直接抛出异常即可。6.实现query、insert、delete和update方法时要使用UtiMatcher.match方法将URI映射成第四步与URI对应的代码(addURI方法的最后一个参数值),代码如下://实现query方法public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder){ Cursor cursor=null; //根据Uri获得返回码 switch(uriMatcher.match(uri)){ case 1: ... break; case 2: ... break; default: ... Throw new IllegalArgumentException(“<”+uri+”>格式不正确。”);; } return cursor;} 7.在AndroidManifest.xml文件中使用<provider>标签注册ContentProvider,代码如下:<provider android:name=”ReginContentProvider” andorid:authorities=”mobile.android.mydata”/>其中mobile.android.mydata就是在第四步中AUTHORITY的值。

(五)如何为ContentProvider添加访问权限?

解析:在读取联系人和短信时都需要在AndroidManifest.xml文件中设置相应的权限。如果未设置权限,系统就会抛出异常。实际上,我们也可以为自定义的ContentProvider加上这种权限,以使得ContentProvider的使用者必须加上权限才能正常访问ContentProvider。答案:在AndroidManifest.xml文件中定义ContentProvider时可以指定权限(一个字符串),代码如下:<provider android:name=”RegionContentProvider” android:authorities=”mobile.android.chll.permission.regioncontentprovider” android:readPermossion=”mobile.android.permossion.regioncontentprovider.READ_REGION”/>上面的代码通过android:readPermission属性指定的只读权限。除了在<provider>标签中指定访问权限外,还需要定义这个权限,代码如下:<permossion android:name=”mobile.androidpermossion.regioncontentprovider.READ_REGION”android:protectionLevel=”normal” android:label=”@string/label”android:description=”@string/description”/>如果想设置写权限,可以设置android:writePermission属性。当然,也可以通过android:permission属性同时设置读写权限,这时就不需要设置android:readPermission和android:writePermission属性了。如果要调用query方法,必须要使用如下的代码打开权限,否则系统就会抛出异常。<user-permission android:name=”mobile.android.permossion.regioncontentprovider.READREFION”/>

ContentProvider的使用示例: http://blog.csdn.net/wenzhi20102321/article/details/53078861?locationNum=1&fps=1

关于Android面试宝典第三章组件的内容,基本上都在上面了(打字打得我手酸!), 但是组件还是有蛮多其他的知识在面试宝典中没有提到。

之前有一篇关于Android知识点的总结(供大家参考): http://blog.csdn.net/wenzhi20102321/article/details/53790631


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表