您的位置:首页 > 移动开发 > Android开发

android优化以及相关知识点

2015-08-12 16:57 399 查看
对于android的界面分为动态加载和静态加载,但是实际上归根结底其实也只是界面的设计生成而已,只是前者更为直观,后者更考验技术而已。但是无论是哪一种加载方式,都面临着一个重要的问题,那就是界面的优化,这不是一个简单的问题,因为对于一个app,将图片合成并不慢,但是将图片放到屏幕却是最好时间的,这就是为什么使用静态加载速度快,而动态加载却很慢的直接原因了。这里讲一讲一些常见的界面问题。

对于android开发中,需要actionbar,对于actionbar一般的开发者有两种选择,一种是直接将系统的actionbar去掉,也就是使用android:windowNoTitle的自定义style,然后在xml布局中,添加actionbar界面,但其实这种方式的actionbar并不是严格意义上的actionbar,而应该说这是界面的部分而已。而另一种加载方式使用的是系统推荐的actionbar,这种加载方式虽然合乎系统,速度较快,但是麻烦的是,这种加载方式不是很直观,或者说actionbar,titlebar不会在xml中显示,而且需要考虑兼容性的问题,所以老一辈的android程序员会使用一个ActionBarSherlock的第三方库来弥补android2.1以下系统不支持actionbar的问题,但是这个问题在2013google
I/O大会发布兼容包之后就不存在了,因为新发布的support-v7-appcompat已经修复了这个问题,但是需要注意support-v7-appcompat和ActionBarSherlock不能同时使用,以为有些文件重复,会出问题。所以,兼容actionbar的问题,只需要使用support-v7-appcompat就可以了。ps:如果使用ActionBarSherlock,那么使用中,应该使用SherlockActivity,SherlockActivity的方法跟Activity的是不一样的,onCreateOptionsMenu方法中的Menu,MenuItem都是Sherlock的,这点需要注意!

提到兼容包,这里顺便提一下,support-v13是为了支持平板,support-v17是为了支持电视,而support-v7-mediarouter是为了多媒体的使用,例如电视上多用户模式等。support-v8只有一个特性,就是用于渲染脚本。support-v4基本上新建项目就已经自带了。support的开发包在sdk的extras下面的support下,import即可,import之后包名自动修改。而support-v7有一些很有用的东西,例如GridLayout。需要特别注意,GridView是AdapterView的子类,他需要Adapter进行,而GridLayout不用,但是需要更高的APIlevel,所以可以关联support-v7-gridlayout,但应该注意,导入是没有用的,这点注意,这点和support-v7-compat一样。

在使用ActionBar时,一般回调以下方法

@Override

public boolean onCreateOptionsMenu(Menu menu) {

getSupportMenuInflater().inflate(R.menu.main, menu);

return true;

}

这里,我们的布局代码是在项目的menu文件夹下的,文件一般如下

<menu xmlns:android="http://schemas.android.com/apk/res/android" >





<item

android:id="@+id/action_search"

android:actionViewClass="android.widget.SearchView"

android:showAsAction="ifRoom|collapseActionView"

android:title="@string/action_search" />





<!-- 这个是Sherlock的 -->



<item

android:id="@+id/add"

android:icon="@android:drawable/ic_menu_add"

android:showAsAction="never"

android:title="@string/add"

android:titleCondensed="@string/add">

</item>

<item

android:id="@+id/delete"

android:icon="@android:drawable/ic_menu_delete"

android:showAsAction="never"

android:title="@string/delete"

android:titleCondensed="@string/delete">

</item>







<!-- 下面这个是系统自身的 -->

<item

android:id="@+id/action_settings"

android:icon="@android:drawable/ic_input_add"

android:orderInCategory="100"

android:showAsAction="never"

android:title="@string/action_settings"/>

</menu>



这里注意,在使用系统自带的ActionBar的返回按钮时,如果这里使用的ActionBar不变而跳转多个Activity,返回时,可以在AndroidMenifest定义ParentActivity,这里低版本的可以使用meta-data,即<meta-data

android:name="android.support.PARENT_ACTIVITY"

android:value="com.example.actionbartest.LaunchActivity" />

这种类型,而高版本4.1以后可以使用android:parentActivityName指定.然后在使用

@Override

public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {

case android.R.id.home:

Intent upIntent = NavUtils.getParentActivityIntent(this);

if (NavUtils.shouldUpRecreateTask(this, upIntent)) {

TaskStackBuilder.create(this)

.addNextIntentWithParentStack(upIntent)

.startActivities();

} else {

upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

NavUtils.navigateUpTo(this, upIntent);

}

return true;

......

}

}

即可,这里如果ParentActivity是在一个task里面,则使用navigateUpTo方法即可,如果不是则需要使用TaskStackBuilder创建task



下面是返回箭头的代码,这里这个箭头的id为android.R.id.home,但是使用系统的返回箭头并不好看,所以估计不会使用。

ActionBar actionBar = getActionBar();

actionBar.setDisplayHomeAsUpEnabled(true);

下面是actionbar的使用方式,ActionBar的基本使用方式,这一点跟TitleBar是一样的。

final ActionBar actionBar = getActionBar();

actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);

actionBar.setCustomView(R.layout.action_bar_activity_welcome);

如果使用的是tab模式,那么使用一下代码即可,

final ActionBar actionBar = getActionBar();

actionBar.setNavigationMode(ActionBar.N***IGATION_MODE_TABS);

actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

//特别注意,这里Tab必须要一个TabListener,否则会报错

actionBar.addTab(actionBar.newTab().setText("Tab选项卡一").setTabListener(new MyTabListener()));

actionBar.addTab(actionBar.newTab().setText("Tab选项卡二").setTabListener(new MyTabListener()));



下面是使用actionbar的搜索框的代码,这个框可以在点击之后弹出不需要的时候回缩。

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);



MenuItem searchItem = menu.findItem(R.id.action_search);

//这里可以SearchView进行属性配置,除此之外,还可以通过setOnActionExpandListener方法监听

SearchView searchView = (SearchView) searchItem.getActionView();





return true;

}

下面的代码,可以设置actionbar的OverFlow按钮列表一直显示,

官方做法:

private void setOverflowShowingAlways() {

try {

ViewConfiguration config = ViewConfiguration.get(this);

Field menuKeyField = ViewConfiguration.class

.getDeclaredField("sHasPermanentMenuKey");

menuKeyField.setAccessible(true);

menuKeyField.setBoolean(config, false);

} catch (Exception e) {

e.printStackTrace();

}

}

或者

其他做法:

private void getOverflowMenu() {

try {

ViewConfiguration config = ViewConfiguration.get(this);

Field menuKeyField = ViewConfiguration.class

.getDeclaredField("sHasPermanentMenuKey");

if (menuKeyField != null) {

menuKeyField.setAccessible(true);

menuKeyField.setBoolean(config, false);

}

} catch (Exception e) {

e.printStackTrace();

}

}

这里注意,调用自定义的getOverflowMenu方法可以得到OverFlow按钮,但是前提是onCreateOptionsMenu的Menu有定义也就是Item项里面android:showAsAction="never"的都会出现在OverFlow按钮里面,同时应该注意IfRoom,Always这些属性的用处





这个方法回调点击事件。

@Override

public boolean onOptionsItemSelected(MenuItem item) {







return true;

}



重写这个方法可以改变OverFlow按钮只显示文字的特性,这里还涉及到一个MenuBuilder类,但是这个类是内部类,这个类可以设置很多特性,如OverFlow的item项的属性,这里应该注意,MenuBuilder.setOptionalIconsVisible就是用于设置图标是否显示的,但是我们不可以直接设置,因为这个类是内部类,所以用的是回调显示,也就是说,可以在onCreateOptionsMenu方法中进行回调,

@Override

public boolean onMenuOpened(int featureId, Menu menu) {

if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {

if (menu.getClass().getSimpleName().equals("MenuBuilder")) {

try {

Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);

m.setAccessible(true);

//MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)

m.invoke(menu, true);

} catch (Exception e) {

}

}

}

return super.onMenuOpened(featureId, menu);

}



需要特别注意,在使用ActionBar时,如果版本不能高于11,那么需要使用v7兼容包,然后继承ActionBarActivity,然后调用getSupportActionBar方法而不是getActionBar方法,但是使用了ActionBarActivity就意味着需要使用兼容包的theme作为风格,否则就会报错,这点需要特别注意!

说道框架,在使用框架中,需要注意.aar格式的文件,这种文件更加的好用,.jar文件不能包含res下的文件,以及其他一些文件,但是.aar可以包含基本所有文件,所以在使用UI框架中,最好使用.aar文件。但是需要注意的是.aar文件在AndroidStudio中使用,在eclipse中不能使用,特别注意!



上面这些就是ActionBar设计时,应该注意的一些问题了,但是实际设计中,我们往往是不是用这种方式,因为过于麻烦,尽管效率更高。



下面讲讲布局中控件的使用。

ViewConfiguration是用于规范UI控件等的设计的类,一般可以在final ViewConfiguration configuration= ViewConfiguration.get(getContext());之后得到对象,然后操作这个对象即可,例如自定义布局平滑移动configuration.getScaledMaximumFlingVelocity();总的来说,ViewConfiguration就是得到UI控件需要遵守的系统参数

SlidingDrawer,DrawerLayout,SlidingPaneLayout这三个抽屉式布局各有不同,使用上也是也是不尽人意。

SlidingDrawer是滑块布局,这个滑块的位置只能是位于下边框,有边框的中间位置,点击之后出现滑出被隐藏的部分,而前面的部分也是会跟着移动的。而这里需要特别注意的是,最好不要使用SlidingDrawer,因为这个控件不仅仅是官方废弃使用了,更重要的是功能不行,在点击的时候相当部分情况下没反应,而且滑块按钮位置不能改变。使用中需要在SlidingDrawer中指定handle,content两个元素,使用android:orientation指定滑出方向可以看源码示例掌握基本用法。但是不推荐使用!

DrawerLayout控件,他是一个非常特别的控件,它并不像SlidingMenu一样滑出,它的滑出是覆盖在原本界面上的,这一点从他的名字可以看出.但是奇怪的是,DrawerLayout虽然是以覆盖的方式覆盖在原本界面上,但是原本界面的控件却还是可以点击的,这点需要特别注意!总的来说就是,DrawerLayout滑出之后如果自己的宽度不足以占据整个界面,那么会有黑底填充剩余的界面,而滑出的界面如果其实不会拦截原本界面的点击事件。DrawerLayout的滑出是重叠的方式!控制滑出界面从哪里滑出的是android:layout_gravity,DrawerLayout里面会包含两个控件,第一个是原本的界面,而第二个就是滑出的界面。另外使用DrawerLayout.openDrawer()方法可以打开滑动界面。

对于DrawerLayout本身其实也只是支持左右而已,并不支持上下滑出,这点需要特别注意,如果DrawerLayout结合ActionBarDrawerToggle使用,那么只能从左边滑出。ps:DrawerLayout往往会跟ActionBarDrawerToggle搭配使用。

SlidingPaneLayout虽然可以向SlidingMenu一样滑动,但是有一个缺陷,就是实际上虽然说可以左右滑动,可以是能是向右边滑动,不能向左滑动。SlidingPaneLayout与DrawerLayout同属v4包里面的.另外需要特别注意,对于SlidingPaneLayout其实并不像SlidingMenu,因为SlidingPaneLayout其实里面包含两个控件,第一个是被第二个覆盖的,第二个是主界面,而滑出其实更应该说是,让第二个界面不要遮挡第一个界面,所以从效果上,其实并不比SlidingMenu好。

所以,如果实现实现的是滑动效果,最好还是使用第三方库的slidingmenu,不要使用SlidingDrawer,DrawerLayout,SlidingPaneLayout了,因为可控性不高。如果实现抽提效果,可以考虑一下,但是最好也不要使用,所以总的来说,SlidingDrawer,DrawerLayout,SlidingPaneLayout基本没什么作用。

ps:在网上讨论中说的NavigationDrawer,其实说的就是DrawerLayout。



其实以前设计过ActionSheet,原理其实并不难,就是继承LinearLayout然后添加控件而已,如果需要拖曳效果,还可以使用DragShadowBuilder进行,关键只是一些位置的设置以及调整,并不是很难,另外ActionSheet是IOS的叫法,如果真的需要可以参考开源项目ActionSheetForAndroid。另外android中按下手机的menu键,可以弹出菜单,这个是PopupMenu,我们也可以参照这个PopupMenu进行设计,当然根基实际需要自行设计。这里我的资源里面有自己设计的ActionSheet。ps:其实ActionSheet就是菜单列表。



attrs文件夹下的declare-styleable标签可以用于给自定义控件设置属性,然后自定义控件之后需要至少使用XX(Context context, AttributeSet attrs, int defStyle)然后在这个方法里面,使用类似下面代码这样的,就可以进行操作了,详细的attrs自定义控件属性可以根据实际需要自定义,但是需要注意的是,需要添加引用,也就是xmlns:app="http://schemas.android.com/apk/res-auto"这种格式的引用,其实前面的xmlns:app="http://schemas.android.com/apk/"一般是一样的,而后面的可以引用到apk下的资源,例如res-auto可以修改为res/包名,而res-auto是自动的意思,

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);

mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);

mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR);

a.recycle();

另外,需要特别注意的是,使用styleable也就是declare_styleable时,例如

* <declare-styleable name="CircleImageView">

<attr name="border_width" format="dimension" />

<attr name="border_color" format="color" />

</declare-styleable>

这种情况下,如果使用R得到属性的话,需要写成R。styleable。CircleImageView_boarder_width,也就是说,declare-styleable与attr属性需要用下划线_连接。





说到自定义,如果我们需要声效,那么View.playSoundEffect()并且设置这个View的setSoundEffectEnabled为true即可,但是这种方式是View也就是控件的,存在局限,这里特别注意!





下面是一些有用的知识点:



1. TextView中android:ellipsize=marquee可以将文字设置成跑马灯格式,即多出的部分会移动显示,这个是很有用的,这里提一下。

2.这里特别注意,因为raw资源不会被系统编译,所以系统下的raw文件夹下的资源也就引用不了了,也就是说,android.R.raw下的资源我们引用不了!

3.android:imeActionLabel用于设置输入法那里的一些属性,例如设置为“登陆”,然后我们可以设置setOnEditorActionListener监听。

4.以后设置字体可以使用系统的字体外观,例如设置android:textAppearance为textAppearanceSmall,textAppearanceMedium,textAppearanceLarge

5.Spinner的属性android:spinnerMode可以选择Spinner的弹出方式,有dialog,dropdown两种可以选择。一种弹出框模式,一种下拉框模式,所以如果需要Spinner下拉数据列表,实际上并不用自定义,因为Spinner本社就有这种功能。另外设置Spinner的背景需要使用9patch格式图片,并且注意除了图片的伸缩,还要留出文字区域的伸缩。

6.对于ListView的项与项间divider有阴影可以试一下ndroid:divider="@android:color/transparent"。android.R.layout.simple_list_item_1是单行显示,每一行都是一个TextView,而android.R.layout.simple_list_item_2是两行,根控件时TwoLineListItem,两行都是TextView,android.R.layout.two_line_list_item跟android.R.layout.simple_list_item_2一样,不同的是android.R.layout.two_line_list_itemTextView的字体大小一样,但是上面的是加粗,也就是android:textStyle=bold,而android.R.layout.simple_list_item_2则是上面字体是ListView的常见大小,而下面的则是小字体,而且风格使用的是系统自带的,两者分别为textAppearanceListItem和textAppearanceSmall",另外,android:textAppearance用于设置TextView外观。android.R.layout.simple_list_item_multiple_choice是带多选框的布局,android.R.layout.simple_list_item_single_choice是带单选框的布局,android.R.layout.simple_list_item_checked是带有勾选框的系统布局,这里配合ListView.setChoiceMode使用。布局其实可以修改,这些布局,使得效果更加绚烂,但实际未必用的上,因为这种界面只对简单的文字勾选框,也就是CheckedTextView界面有效。

而且对于ListView的Adapter,一般使用BaseAdapter进行设计就好,如果使用自带的例如ArrayAdapter,SimpleCursorAdapter,SimpleAdapter,其实会有很多的限制,例如加载ImageView如果是,需要网络加载图片,那么SimpleAdapter将非常麻烦,另外,android.R.layout下的ListView的相关布局会有系统的调用部分,如果需要可以草找这些系统自带的布局进行设计,这样系统会调用,也就优化了属性,但是会有很多的属性,所以,对于ListView的系统自带的SimpleAdapter,android.R.layout布局,一般还是别用,作为参考就好,以为限制很大!

另外注意,setChoiceMode这个只对ListView使用的是例如android.R.layout.simple_list_item_single_choice这一类的布局时才有用,我们自定义的布局是没用的。

另外需要注意的是,CheckedTextView的android:checkMark可以修改图标,在android.R.layout.simple_list_item_single_choice这一类布局里面基本使用的是CheckedTextView控件。

其实android.R.layout.simple_list_item_multiple_choice,android.R.layout.simple_list_item_single_choice等布局其实里面都仅仅只是一个CheckedTextView控件,这布局仅仅是CheckedTextView的图标不一样而已,实际单选多选是通过setChoiceMode决定的。

对于HeaderView,FooterView,ListView的HeaderView,FooterView如果被添加了,那么getAdapter返回的Adapter就不是我们setAdapter的Adapter了,而是我们设置的Adapter加上HeaderView,FooterView之后的Adapter,这一点需要特别注意!

这里需要特别注意,在使用ListView.setItemChecked方法中,其实ListView是检测item布局的第一项是否有实现Checkable接口,如果有就会调用Checkable.setChecked方法。这就是系统的调用过程.另外需要特别注意的是,实现单选,多选实际上也是调用Checkable接口的。

注意!对于ListView的子项布局,在ListView中,子项如果出现Button,CheckBox这些焦点优先级高于ListView的控件时,ListView子项的焦点将会被截取,这时候ListView的子项点击将会失效,这个时候如果想要点击生效,只需要在抢夺焦点的控件里面添加android:focusable="false"即可,但是需要特别注意的是,如果在父控件里面添加了android:focusable,android:focusableInTouchMode,android:clickable并且值为true时,会起到反效果,这点需要特别注意!另外,这里android:desendantFocusability将不起作用,也就是对焦点拦截没有任何作用,但是在出ListView之外的布局还是很有用的。

最后ListView的尺寸必须是可以让系统确定的,这样Adapter的getView才不会调用多次,因为如果尺寸不确定,那么系统需要先确定尺寸在可以开始添加数据,所以getView才会被调用多次,这点需要注意!如果需要点击效果,那么需要使用android:drawSelectorOnTop="true",否则,项的根父布局控件的点击效果将会被它的子控件所掩盖,应该说点击效果就体现在项的根父布局控件的背景上,只有使用了android:drawSelectorOnTop="true"才可以将背景前置,这点特别注意!



7.只有在ListActivity中,并且ListView的id使用系统的id,TextView使用系统的id,这样在ListView没有数据时,TextView显示,而ListView有数据时,TextView不显示。这种效果在ListActivity的源码中已经有注释了,查看源码即可!这样,在一个界面中,如果只是ListView显示的,可以使用ListActivity,这样更方便点,因为剩下一个界面。

8.说道ListView,如果需要自带刷新效果的ListView,那么就需要使用第三方库了,这里推荐使用PullToRefreshListView项目,但是需要注意的是PullToRefreshListView中,使用PullToRefreshListView.getRefreshableView().getCount()中,返回的数值跟ListView是不一样的,这里返回的数字最少都是2,一个是顶部的下拉界面,一个是底部的下拉界面,这两个界面的根控件为FrameLayout,所以PullToRefreshListView子项应该从1开始从count
- 1,这点需要特别注意!

9.GridView的item的布局根布局控件需要match_parent,这样才能填满GridView留给的空间,这点需要注意.另外,设置android:columnWidth可以修改每一列的宽,但是一般没什么用,因为android:numColumns分好列就行了,另外,使用android:horizontalSpacing,android:verticalSpacing可以设置每一个项之间的间隔。另外GridView与ListView不一样的地方在于GridView高度就算不确定,为wrap_content,也不会加载多次getView方法。总的来说,应该说理解GridView可以按照ListView,不一样的地方在于GridView的每一个项是某一个方块,而不是某一行。

10.activity里面添加android:windowSoftInputMode="adjustPan"可以让ScrollView里面如果存在EditText,ScrollView下面的控件不会因为软键盘而被顶起。对于ScrollView的子控件只能有一个,如果这个控件需要占满ScrollView,需要将android:fillViewPort设置为true,但是不许在ScrollView里面的子控件在嵌套多一个layout控件,总的来说,就是ScrollView的子控件需要match_parent就需要android:fillViewPort为true。



11.android:windowSoftInputMode属性是用来控制界面跟软键盘的交互的,因此这个属性非常重要,这个属性值一般以state或adjust开头,一般adjust开头的是界面去适应软键盘,而state的则是软键盘适应界面,或者说软键盘自身的状态。



12.这里需要特别注意,对于selector,如果需要使用color资源,那么需要将color资源在resource里面声明一下,例如可声明为drawable,color等,有些selector,如果需要color改变的,那么就一定需要声明resource的color。如果就仅仅是点选改变,那么可以直接写出颜色值。

13.RadioButton,这里需要特别注意,不同手机对RadioButton这一类的控件的android:button="@null"有不同的处理方式,高级一点的会把button设置为gone,但是低级的只会设置成invisible,这样如果设置成invisible,那么原来的button的位置虽没有控件,但却会有保留空间,这是非常不好的,所以如果允许的话,可以使用Button控件代替RadioButton。像RadioButton,CheckBox这一类的分为两个部分的控件,其实是以文字作为主体的,而框只是辅助作用,所以如果没有android:button="@null"的话,使用android:paddingLeft可以增加框与文字之间的距离,但是一旦使用了android:button="@null",那么一般使用android:drawablePadding调节,因为这个时候这些控件已经失去了原本的checked属性了,只是像一般的Button这样的控件了,所以距离调节方式发生改变!

14.这里需要特别注意,如果使用的属性是父控件作用在子控件上的,例如android:paddingRight这样的,如果这个父控件里面的最右边子控件被设置为gone,那么这个属性将不会生效,因为这个属性是作用在最右边的控件的,不会传递给其他控件,而这个控件gone,所以这种情况需要多注意!

15.在RelativeLayout里面使用android:gravity="center_vertical"不起作用,可以使用android:layout_centerVertical="true",毕竟RelativeLayout是继承自LinearLayout的,这点需要特别注意!在RelativeLayout里面使用android:gravity="center_vertical"不起作用,可以使用android:layout_centerVertical="true",毕竟RelativeLayout是继承自LinearLayout的,这点需要特别注意!另外需要特别注意,在LinearLayout中,使用android:layout_margin中,控件可以的该属性可以将LinearLayout父控件看成相对控件,但是在RelativeLayout中不行,在RelativeLayout中,如果android:layout_alignParentBottom这一类属性设置后android:layout_marginBottom属性将会失效。总的来说,其实是因为对于android:layout_margin属性,真正的含义是:控件与相对控件之间的距离,LinearLayout与RelativeLayout对于相对控件概念有所不同,这点需要特别注意!我们可以设置一个高度为0的相对控件即可解决!

16.对于RadioButton,一般多个RadioButton在RadioGroup下使用。之所以这样,是因为RadioButton自身属性中,如果自己没check,则点击之后会被check,而如果已经check了,则点击之后不能返回没check的状态,如果要返回没check的状态只能通过点击别的RadioButton,这其实从RadioButton被设计出来的意图就可以知道他的这种属性。另外CheckBox点击可以在check与没check之间切换,并无限制!

17.在适配中,特别注意,使用RadioButton的话,最好将android:button="@null",然后使用android:drawableLeft这一类属性,因为无论按钮是否在左边,因为使用android:button对于一些手机来说,即使使用了android:paddingLeft也是很麻烦的,因为有些手机使用android:button属性,android:paddingLeft数值如果增大,那么文字和按钮的距离可能会变长,也可能会变短,所以为了适配,最好使用android:drawableLeft这一类属性,别使用android:button="@null"这个属性了。

18.对于TextView及其子类,需要特别注意,setGravity在一些手机上是没有效果,甚至效果变得更差的,这一点跟静态加载不一样,需要特别注意,也就是说,如果是如果是动态加载,需要考虑使用setPadding代替setGravity,这点需要特别注意!





19.对于android的播放器,多媒体播放有三种方式,(1).使用系统自带的播放器。(2).使用VedioView。(3).MediaPlayer结合SurfaceView。

如果是播放音频,那么是很简单的,基本上使用MediaPlayer就可以了,比较麻烦的是播放视频。这里MediaController提供一个控制界面,用于控制VideoView的播放。简单点说,VideoView加MediaController就是一个播放界面加控制界面。

其实VideoView本身包含了MediaPlayer,这一点可以从MediaController.setMediaPlayer(VideoView)可以看出来,而实际上,如果MediaPlayer要结合MediaController使用,那么就需要实现MediaController。mediaPlayerControl接口用于回调,然后setAnchorView,setEnabled,show即可。ps:控件中有一个setEnabled方法非常有用,特别是在播放媒体的时候,可以用于控制控件自身是否可用,这点特别注意!

应该说VideoView结合MediaController的方式其实相当于使用MediaPlayer进行的,因为VideoView本身原理是使用MediaPlayer的,简单点说,就是如果我们不需要界面自己控制,仅仅集中在播放上,可以使用VideoView结合MediaController的方式, 但是如果需要估计所有细节,那么最好使用MediaPlayer结合SurfaceView的方式。这里应该注意,MediaPlayer本身主要用于播放音频,如果需要播放视频,那么就需要一个SurfaceView用于作为播放窗口,MediaPlayer结合SurfaceView的关键在于MediaPlayer.setDisplay(SurfaceHolder)这个方法,然后使用MediaPlayer的各种监听接口进行监听。

需要特别注意的是,android视频播放本身并不是那么好搞的,因为需要考虑硬件,系统本身,这里需要考虑视频的格式是否被手机所支持,有可能即使转换了格式还是不能被识别播放,可以查看MediaPlayer的参数例如MediaPlayer.MEDIA_ERROR_UNKNOWN就是常见的错误,一般是视频格式不能识别播放才会出现。而返回的错误中MediaPlayer error (1, -2147483648)中的key=1指的就是MediaPlayer.MEDIA_ERROR_UNKNOWN=1;

20.需要特别注意,对于布局控件的背景,不是说想设就设的,对于图片很大的背景往往会导致错误的结果,因为如果布局使用的是wrap_content,那么布局控件的高度将会按照子控件的整体高度作为自身高度,但是图片太大了,这个时候,就会出现控件高度,背景高度两种高度,也就是说布局控件的容纳子控件的高度跟自身的高度不一样了,这个时候适配就很麻烦了,所以这点需要特别注意!总的来说就是,需要注意布局控件的控件高度,背景高度的不一致性!

21.对于本地用户的cookie,在android中,登陆比起网页来的简单,因为在网页中,需要服务器的session,以及本地的cookie。这样做是为了随时保持连接状态,这样安全性也更高。但是总的来说,就是一个身份时候时间限制的,所以才会这样设定,在android中需要使用第三方库的Cookie结合CookieStore这些进行。但是实际上,在android使用中,并不需要像网页中这样,因为在android中,存储本地用户以及姓名即可,cookie这些东西不需要了,因为app不允许中途使用中断掉,所以登陆之后session实用的cookie实际上需要服务器让其一直不会过期,知道退出。这一点可以从微信,微博等app可以看出。所以在android的登陆仅仅需要基础用户姓名密码即可,并不需要那么复杂,这点需要特别注意!

22.在设计代码中,如果是由一个类操作另一个类,那么一般的操作模式是,操作类进行设置,然后调用某个方法使这些设置生效,这种方式很想命令模式。一般使用操作类设置被操作类进行一系列的操作,然后操作类使用最终的一个命令令设置最终生效,例如BaseAdapter。notify方法,NotificationManager。notify方法。这种情况需要掌握!

23.EditText.setRawInputType(Configuration.KEYBOARD_QWERTY);可以设置软键盘弹出是以什么方式弹出,例如这里是以数字键盘弹出!但需要特别注意的是,对于不同版本的android系统可能会有不同的效果,这个时候android:inputType就不能设置了,不然新版本的android系统起作用,而旧版本的会由于设置了android:inputType,而EditText.setRawInputType(Configuration.KEYBOARD_QWERTY),这是就版本的bug,需要特别注意,特别是需要弹出数字软键盘,而EditText输入类型又不希望受限制的情况,这个时候android:inputType千万不能设置!这点需要特别注意!





对于android的优化,有几个方面需要注意。

对于android下的资源,其实很多时候如果是简单的,我们完全可以自己使用代码生成,不必使用图片,这样可以优化代码,例如使用shape,layer-list设置生成图片。这里注意,shape里面的padding跟控件的padding是一样效果的,是用于控制控件内容的,而不是shape自己内容的,这点需要特别注意,总的来说,就是shape的padding跟控件本身的padding是一样的,所以shape自身使用item结合android:left这样的来控制缩进!另外需要注意的是,shape的size也是用于控件的大小的,而且会被控件本身设置的大小所覆盖。下面是layer-list和shape的示例

<?xml version="1.0" encoding="utf-8"?>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

<item >

<shape android:shape="oval" >

<stroke

android:width="1dp"

android:color="#B8B8B8" />

<solid android:color="#FFFFFF" />

<size

android:height="65dp"

android:width="65dp" />

</shape>



</item>

<item>

<bitmap android:src="@drawable/bm_edu_booka"

android:gravity="center" />

</item>



</layer-list>

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android"

android:shape="rectangle" >



<!-- 特别注意,使用padding其实没有效果,因为shape里面padding的效果需要在item里面设置,而这有涉及到layer-list,

同时注意,使用layer-list可以让shape更加多变,甚至可以让方框只改变三边 -->





<stroke android:color="#737373" android:width="1dp" />

<solid android:color="#FFFFFF" />

<corners android:radius="4dp" />

</shape>



对于android界面的优化,在开发中,应该多使用RelativeLayout,GridLayout进行开发,减少层级结构,尽量扁平开发,少使用layout_weight。多使用ViewStub,这样可以在布局层面优化性能。另外,一个布局的第一层最好是ScrollView,因为一个手机的屏幕的长宽比永远都是未知的,一旦遮住了,就需要用户可以看得到,所以就需要滑动了。

对于我们常用的ViewPager的优化,这里特别注意,使用setOffscreenPageLimit对Fragment进行缓存,不然ViewPager自身就只会缓存前面的两个,这样如果第一次加载直接跳到第三个就会出错。另外,不要使用FragmentPagerAdapter.notifyDataSetChanged方法进行界面刷新,因为这种刷新方式是用于Fragment的销毁生成才使用的,是非常低级的方法。这种方法需要重载getItem,instantiateItem,getItemPosition三个方法,getItem方法每次都必须生成新对象而不是使用现有的对象,getItemPosition只返回PagerAdapter.POSITION_NONE以迫使instantiateItem生成新对象,从而调用getItem方法。总的来说,FragmentPagerAdapter.notifyDataSetChanged方法刷新界面不要使用,太低级了!而且他本来设计就不是用来刷新Fragment界面的,这点需要特别注意!



android系统下,放置图片的文件夹其实也是存在优化的,在使用图片中需要将图片放置在正确的文件夹下,不可乱放,不然会由于android的优化出现图片缩放变形的情况。例如1280,720的图片放置在xhdpi的文件夹下是正确显示的,但是放在hdpi下会出现图片拉伸放大的情况。之所以会出现这种情况,其实可以从文件夹的名字得到,xhdpi意味着文件夹使用的是xh的dpi值320,换算成density就是2,而hdpi换算成density则是1.5,所以px换算成dp值可以知道hdpi的值肯定是比xhdpi值要大的,所以也就出现图片缩放的情况了,也就是说,文件夹dpi值越小,缩放越严重,这点是需要特别注意的!



对于优化,android的优化关键体现在堆栈的管理,例如task栈,这里涉及到Activity,Fragment等的管理,可以从它们的属性进行研究,例如AndroidManifest中的属性,例如Activity的android:alwaysRetainTaskInstance,android:taskaffinity,android:launchMode,android:allowTaskReparenting,android:clearTaskOnLaunnch,android:finishOnTaskLaunch以及Fragment的setRetainInstance等。

对于android:launchMode其实最麻烦的是singleInstance,对于singleInstance如果从其他Activity跳转到该singleInstance的Activity然后返回,该Activity不会作为起点,但是如果singleInstance的Activity使用startActivity跳转或者返回,则这个singleInstance的Activity就回座位起点Activity,也就是说按back键之后最终需要到这个singleInstance的Activity才可以退出。可以简单的记为,singleInstance的Activity如果使用startActivity则自身将会转变为起点Activity!

对于singleTask的Activity,其实是生成了一个新的task堆栈,然后在这个Activity之后的Activity都是在这个堆栈里面的,但如果后面的Activity也是singleTask的话,那么每个Activity都生成task,这样的话,就跟没使用singleTask一样,因为后退的顺序不变,这点需要注意!另外,使用Intent.setFlag设置Intent.FLAG_ACTIVITY_NEW_TASK并没什么作用,应该在launchMode里面设置,这样才有效果!ps:singleTop,standard不会创建新task,而singleTask,singleInstance会创建新task。singleTask一般不要作为启动项的Activity,因为会丢失Activity在堆栈的跳转轨迹。

使用lint工具可以优化代码。

有时候使用命令可以减少代码,加快速度,所以有时候可以尝试使用android自身的命令。Runtime mRuntime = Runtime.getRuntime();Process mProcess = mRuntime.exec("adb version");这里需要特别注意,使用Runtime类可以使用命令,在Java中可以使用java命令,在android中可以使用shell命令,是非常有用的一个工具类,这里需要特别注意!





对于自定义控件,我们一般结合xml进行设计,尽管会多出文件,但是性能更好,这里自定义涉及到ImageView的话,需要注意,在设置图片时,往往不知道图片的宽高,这个时候可以设置android:adjustViewBounds=“true”属性,这个时候设置宽高以及scaleType之后图片才会根据自身大小调节,这种调节跟指定宽高之后的调节是一样的。也就是说android:adjustViewBounds=“true”可以让我们在宽高不确定的情况下正确调节ImageView的src图片,但是需要注意android:adjustViewBounds=“true”一般需要maxWidth,maxHeight才行,但是ImageView这里就算不指定也是可以的。使用Context.obtainStyledAttributes方法是用于获取我们自己定义的属性的,而如果需要获取系统的属性,则需要使用AttributeSet的方法,例如getAttributeResourceValue("http://schemas.android.com/apk/res/android",
"src", 0)可以得到ImageView的src属性值。

其实自定义控件在XML中的显示说白了就是图片的控制,也就是说,控制图片的显示,大小尺寸,颜色等的控制,总的来说就是,XML对于控件的显示就是我们利用继承的控件的属性,让控件的图片显示出来,然后对图片的大小尺寸等数据进行加工,而我们自定义的属性,就是为了进行加工,也就是说,想要控件显示正确,关键在于利用继承的控件的属性,让控件图片正确显示!

对于android控件的宽高,一般在使用getWidth,getHeight,getMeasuredWidth,getMeasuredHeight之恩那个返回0,这是因为一般尺寸数据在界面布置完成之后才会生成,所以才会返回0.但是我们可以使用LayoutParams。height,LayoutParams。width得到,之所以是这样的,是因为getWidth,getHeight,getMeasuredWidth,getMeasuredHeight针对的是控件自己,而LayoutParams。height,LayoutParams。width则是布局控件用来限制控件的,尺寸数据放在这里面所以总的来说,如果先要在布局完成前得到尺寸数据,就用LayoutParams。height,LayoutParams。width,布局完成之后则没有限制了!可以简单的记为控件的尺寸数据放在它的布局控件那里。这点需要特别注意!ps:使用LayoutParams。width,LayoutParams。height可以在onDraw方法里面得到尺寸,当然这需要提前设置了LayoutParams。width,LayoutParams。height才会返回,也就是说XML设置了,如果纯动态加载,就需要手动设置LayoutParams。width,LayoutParams。height,这是它的限制!

如果在XML中添加了宽高,那么使用getLayoutParams.height是可以得到值得,但是如果并没有标明值这个时候无论在布局完成之前还是之后都不能得到值,这个时候应该使用getHeight,这个时候在布局完成之后使用getHeight可以得到值,但是之前是不可以的,这里特别注意!



对于一些框架,在使用时应该注意有原则点选择,如果可以自己写,最好自己写,这样不会生成框架依赖性。同时需要注意,框架需要保证是否能持续更新。如果是控件类的框架,最好把框架中的核心代码摘取,然后自己写控件,减少依赖,并能自己维护。这里例举几个框架例子

1.在使用AndroidAnnotations中,文件非常难以删除,这点很麻烦,而且一旦使用了,那么所有的Activity都需要使用注解否则出错,最重要的是,注解的控件不能使用private,这点非常麻烦,所以如无必要暂时不使用注解框架。另外,AndroidAnnotations和TouchGallery框架有冲突。ps:注解会使得app速度变慢,如果是app在运行中总是用到,那么需要考虑性能问题。

2.使用gif_drawable项目应该使用1.0.8的,而不能使用高版本的,因为高版本用于支持AndroidStudio导致Eclipse不能使用

3.相对于ImageViewZoom的不成熟,我们可以使用PhotoView框架进行开发,PhotoView框架比较成熟。

4.TouchGallery由于存在资源的引用,所以不能做成jar包,这点需要注意!但是TouchGallery在新版中已经改好网络不缓存的问题但是作者已经不在更新了,这是特别需要注意的地方!同时需要注意的是,TouchGallery会用到资源文件,所以不能打包成jar包,特别注意!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: