android项目笔记整理(3)
61.AlphabetIndexer字母索引辅助类
实现对链表类型的数据进行快速索引. 应用于类似联系人列表右侧的导航栏
2.链表元素的顺序需按照字母顺序排列(toString()的结果排序)
构造函数:
public AlphabetIndexer(Cursor cursor,int sortedColumnIndex,CharSequence alphabet)
参数1:包含数据的Cursor对象
参数2:进行索引排序的列号
参数3:字母表(空格将会作为第一个字符。字母要大写,并且按ASCII/UNICODE排序。)
常用方法:
public Object[] getSections():返回索引数组
public int getPositionForSection(int sectionIndex)按指定索引查找,返回匹配的第一行数据项位置或比较接近的数据项的位置
public int getSectionForPosition(int position)按指定数据项的位置,返回匹配的索引项
add 和 replace影响的只是界面,而控制回退的,是事务
add是把一个fragment添加到一个容器container里。
replace是先remove掉相同id的所有fragment,然后在add当前的这个fragment。
在大部分情况下,这两个的表现基本相同。因为一般我们会使用一个FrameLayout来当容器,而每个Fragment被add或replace到这个FrameLayout的时候,
都是显示在最上层的。所以你看到的界面都是一样的。但是,使用add的情况下,这个FrameLayout其实有2层,多层肯定比一层要来的浪费,所以还是推荐使用replace。
当然有时候还是需要使用add的。比如要实现轮播图的效果,每个轮播图都是一个独立的fragment,而他的容器FrameLayout需要add多个Fragment,这样他就可以根据提供的逻辑进行轮播了。
而至于返回键的时候,这个跟事务有关,跟使用add还是replace没有任何关系。
//通过反射机制来实现
public boolean onCreateOptionsMenu(Menu menu){
//运行时,参数Menu其实就是MenuBuilder对象
/*利用反射机制调用MenuBuilder的setOptionallconsVisible方法设置mOptionalIconsVisible为true,
给菜单设置图标时才可见*/
setIconEnable(menu,true);
MenuItem item1 = menu.add(0,1,0,"item1");
item1.setIcon(R.drawable.camera);
MenuItem item2 = menu.add(0,1,0,"item2");
item2.setIcon(R.drawable.dial);
return super.onCreateOptionsMenu(menu);
}
//enable为true时,菜单添加图标有效,enable为false时无效。
//4.0系统默认无效
private void setIconEnable(Menu menu,boolean enable){
try{
Class<?> clazz =Class.forName("android.support.v7.internal.view.menu.MenuBuilder");
Method m =clazz.getDeclaredMethod("setOptionalIconsVisible",boolean.class);
m.setAccessible(true);
//MenuBuilder实现Menu接口,创建菜单是,传进来的menu其实就是MenuBuilder对象(java的多态特征)
m.invoke(menu,enable);
}catch(Exception e){
e.printStackTrace();
}
}
?
使用Canvas的drawText绘制文本是不会自动换行的,即使一个很长很长的字符串,drawText也只显示一行,超出部分被隐藏在屏幕之外。
可以逐个计算每个字符的宽度,通过一定的算法将字符串分割成多个部分,然后分别调用drawText一部分一部分的显示,但是这种显示效率会很低。
super.onDraw(canvas);
TextPaint tp = new TextPaint();
tp.setColor(Color.BLUE);
tp.setStyle(Style.FILL);
tp.setTextSize(50);
String message ="jdlkfajlsdjflaksdjlkfjalsdkjflksdjlfkjsadlkjfsadlkjf";
StaticLayout myStaticLayout = new StaticLayout(message,tp,canvas.getWidth(),Alignment.ALIGN_NORMAL,1.0f,0.0f,false);
myStaticLayout.draw(canvas);
canvas.restore();
}
这跟TextView的效果是一样的,其实TextView也是调用StaticLayout来实现换行的。
其中一个构造方法:
b.需要分行的字符串从第几的位置开始
c.需要分行的字符串到哪里结束
d.画笔对象
e.layout的宽度,字符串超出宽度时自动换行
f.layout的对齐方式,有ALIGN_CENTER,ALIGN_NORMAL,ALIGN_OPPOSITE三种
g.相对行间距,相对字体大小,1.5f表示行间距为1.5倍的字体高度
h.在基础行距上添加多少,实际行间距等于这两者的和
i.参数未知
j.从什么位置开始省略
k.超过多少开始省略
需要指出的是这个layout是默认画在Canvas的(0,0)点的,
如果需要调整位置只能在draw之前移Canvas的起始坐标canvas.translate(x,y);
?
(1).设置android:divider ="@null"
(2).android:divider="#00000000" //最开始的两个0表示透明
(3).setDividerHeight(0):高度设为0
?
(1).常规类型、字符类型和数值类型的格式说明符的语法如下:
%[argument_index$][flags][width][.precision]conversion
可选的argument_index是一个十进制整数,用于表明参数在参数列表中的位置。第一个参数由"1$"引用,第二个参数由"2$"引用,依次类推。
可选flags是修改输出格式的字符集。有效标志集取决于转换类型。
可选width是一个非负十进制整数,表明要向输出中写入的最少字符数。
可选precision是一个非负十进制整数,通常用来限制字符数。特定行为取决于转换类型。
所需conversion是一个表明应该如何格式化参数的字符。给定参数的有效转换集取决于参数的数据类型。
(2).用来表示日期和实际类型的格式说明符的语法如下:
%[argument_index$][flags][width]conversion
可选的argument_index、flags 和width的定义同上。
所需的conversion是一个由两字符组成的序列。第一个字符是‘t‘或‘T‘。第二个字符表明所使用的格式。这些字符类似于但不完全等同于那些由GNUdate和POSIXstrftime(3c)定义的字符。
(3).与参数不对应的格式说明符的语法如下:
%[flags][width]conversion
可选flags 和 width 的定义同上。
所需的conversion是一个表明要在输出中所插内容的字符。
在Java代码中动态的方法: getResources().getString(int id,Object... formatArgs);
?
其中android:stretchColumns="0"作用是让第一列可以扩展到所有可用空间;
TableLayout几个重要的属性:
collapseColumns:设置隐藏那些列,列ID从0开始,多个列的话用","分隔
stretchColumns :设置自动伸展那些列,列ID从0开始,多个列的话用","分隔
shrinkColumns :设置自动收缩那些列,列ID从0开始,多个列的话用","分隔
可以用"*"来表示所有列,同一列可以同时设置为shrinkable和stretchable。
另外android:scrollHorizontally = "true"表示一个EditText满了后是自动横着移动不是默认的换行。
对EditText中输入的内容也经常需要进行限制,我们可以通过TextWatcher去观察输入框中的输入的内容。
mEditText.addTextChangedListener(mTextWatcher);
TextWatcher mTextWatcher = new TextWatcher(){
private CharSequence temp;
private int editStart;
private int editEnd;
public void beforeTextChanged(CharSequence s,int arg1,int arg2,int arg3){
temp =s;
}
public void onTextChanged(CharSequence s,int arg1,int arg2,int arg3){
mTextView.setText(s);
}
public void afterTextChanged(Editable s){
editStart = mEditText.getSelectionStart();
editEnd = mEditText.getSelectionEnd();
if(temp.length()>10){
s.delete(editStart-1,editEnd);
int tempSelection = editStart;
mEditText.setText(s);
mEditText.setSelection(tempSelection);
}
}
}
?
activity-alias是android里为了重复使用Activity而设计的。
当在Activity的onCreate()方法里,执行getIntent().getComponent().getClassName();得到的可能不是这个Activity的名字,有可能是别名的名字。
例如:在AndroidMenifest.xml有如下配置:
<activity
android:name =".TestAndroid"
android:icon ="@drawable/ic_menu_mark">
<intent-filter>
<action android:name ="android.intent.action.MAIN"/>
<category android:name ="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity-alias
android:name ="TestAndroidAlias"
android:targetActivity ="TestAndroid"
android:label ="testAndroidlias"
android:icon ="@drawable/ic_launcher_phone">
<intent-filter>
<action android:name ="android.intent.action.MAIN"/>
<category android:name ="android.intent.category.DEFAULT"/>
<category android:name ="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
这个应用会再桌面上建两个进入点,即建两个可以进入TestAndroid这个Activity的快捷图标。
这时getIntent().getComponent().getClassName()得到的名字就不一样,一个是com.test.TestAndroid,一个是com.test.TestAndroidAlias。
Drawable icon = mContext.getResources().getDrawable(resId);
if(icon instanceof BitmapDrawable){
BitmapDrawable bd = (BitmapDrawable)icon;
return bd.getBitmap();
}else{
return null;
}
?
(1).通过HTML标签
String source ="测试<u>下划线</u>、<i>斜体字</i>、<font color=‘red‘>红色字</font>的格式";
htmlFormateTextView.setText(Html.fromHtml(source));
(2).通过SpannableString进行格式化操作
public class TextViewLinkActivity extends Activity{
TextView mTextView =null;
SpannableString msp = null;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTextView =(TextView)findViewById(R.id.myTextView);
//创建一个SpannableStrting对象
msp =new SpannableString("字体测试");
//设置字体(default,default-bold,monospace,serif,sans-serif)
msp.setSpan(new TypefaceSpan("monospace"),0,2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//设置字体大小(绝对值,单位:像素)
msp.setSpan(new AbsoluteSizeSpan(20,true),6,8,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//第二个参数boolean dip,如果为true,表示前面的字体大小单位为dip,否则为像素,同上
//设置字体大小(相对值,单位:像素):参数表示默认字体大小的多少倍
msp.setSpan(new RelativeSizeSpan(0.5f),8,10,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//0.5f表示默认字体大小的一半
msp.setSpan(new RelativeSizeSpan(2.0f),10,12,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//2.0f表示默认字体大小的两倍
//设置字体前景色
msp.setSpan(new ForegroundColorSpan(Color.MAGENTA),12,15,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//设置前景色为洋红色
//设置字体背景色
msp.setSpan(new BackgroundColorSpan(Color.CYAN),15,18,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//设置背景色为青色
//设置字体样式正常,粗体,斜体,粗斜体
msp.setSpan(new StyleSpan(android.graphics.Typeface.NORMAL),18,20,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//正常
msp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),20,22,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//粗体
msp.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC),22,24,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//斜体
msp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC),24,27,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//粗斜体
//设置下划线
msp.setSpan(new UnderlineSpan(),27,30,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//设置删除线
msp.setSpan(new StrikethroughSpan(),30,33,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//设置上下标
msp.setSpan(new SubscriptSpan(),34,35,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//下标
msp.setSpan(new SubscriptSpan(),36,37,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//上标
//超级链接(需要添加setMovementMethod方法响应)
msp.setSpan(new URLSpan("tel:23232323",37,39,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE));//电话
msp.setSpan(new URLSpan("mailto:[email protected]"),39,41,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//邮件
msp.setSpan(new URLSpan("http://www.baidu.com"),41,43,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//网络
msp.setSpan(new URLSpan("sms:4155551212"),43,45,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//短信 使用sms:或者smsto:
msp.setSpan(new URLSpan("mms:3232323213"),45,47,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//彩信 使用mms:或者mmsto:
msp.setSpan(new URLSpan("geo:38.899533,77.036476"),47,49,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//地图
//设置字体大小(相对值,单位:像素)参数表示为默认字体宽度的多少倍
msp.setSpan(new ScaleXSpan(2.0f),49,51,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//2.0f表示默认字体宽度的两倍,即X轴方向放大为默认字体的两倍,而高度不变
//SpannableString对象设置给TextView
myTextView.setText(msp);
//设置TextView可点击
myTextView.setMovementMethod(LinkMovementMethod.getInstance());
}
//在使用SpannableString对象时要注意
//Spanned.SPAN_EXCLUSIVE_EXCLUSIVE等的作用:
//用来标识在 Span 范围内的文本前后输入新的字符时是否把它们也应用这个效果。
//分别有 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括)、
//Spanned.SPAN_INCLUSIVE_EXCLUSIVE(前面包括,后面不包括)、
//Spanned.SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括)、
//Spanned.SPAN_INCLUSIVE_INCLUSIVE(前后都包括)。
}
?
调用软键盘输入时发现有的软键盘右下角的字是“回车”箭头,有的是“完成”等等文字,并且有点击功能
一、布局文件中加入imeOptions
android:imeOptions ="actionDone" //右下角按键“完成”
android:imeOptions ="actionGo" //开始
android:imeOptions ="actionSearch" //右下角按键“搜索”
android:imeOptions ="actionSend" //右下角按键“发送”
android:imeOptions ="actionNext" //下一步
android:imeOptions ="actionNone" //输入框右侧不带任何提示
android:imeOptions ="flagNoExtractUi" //横屏时,软键盘只占用部分屏幕
二、代码中实现setOnEditorActionListener接口
etSearchEditText.setOnEditorActionListener(new OnEditorActionListener(){
public boolean onEditorAction(TextView v,int actionId,KeyEvent event){
if(actionId == EditorInfo.IME_ACTION_SEND){
//这里编写自己想要实现的功能
}
return false;
}
});
//return 默认是false。如果处理了该事件,返回true;否则返回false。
//actionId 的值从EditorInfo中查询到 应与设置的imeOptions值相呼应。
?
(1).默认情况下:系统会按照布局从上到下,从左到右的传递focus
(2).自定义focus传递:可通过以下属性设置:
<Button
style ="@style/clockFaceNum"
android:text="12"
android:id="@+id/button12"
android:layout_alignParentTop="true"
android:layout_centerHorizontal ="true"
android:nextFocusUp ="@id/button11"
android:nextFocusLeft ="@id/button21"
android:nextFocusRight ="@id/button1"
android:nextFocusDown ="@id/button01">
<requestFocus/>
</Button>
requestFocus 设置初始Focus为button12
(3).如何取得focus状态
mFocusFinder = FocusFinder.getInstance();
mFocusFinder.findNextFocus(mRoot, v, View.FOCUS_FORWARD);
(4).如何设置当前获得focus的控件
代码中:button12.requestFocus();
布局文件中:<Button><requestFocus/></Button>
?
fragment中要想显示菜单,需要设置mHasMenu变量为true:
如果mHasMenu为false,那么是不会执行onCreateOptionsMenu(menu,inflater)方法的,也就是不会添加fragment的menu菜单。
所以,在fragment中使用menu菜单,需要在onCreate()方法里面添加语句setHasOptionsMenu(true);
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
如果想在fragment中清除menu,可以调用menu.clear();方法
public void onCreateOptionMenu(Menu menu,Inflater inflate){
super.onCreateOptionMenu(menu,inflate);
menu.clear();
}
?
可以为menuItem指定布局文件
<item
android:id="@+id/location_sel"
android:title="menuItem"
app:showAsAction ="always"
app:actionLayout ="@layout/layout_address_button"/>
?
定时执行在一段时候后停止的倒计时,在倒计时执行过程中会再固定间隔时间得到通知,下面的例子显示在一个文本框中显示一个30s倒计时:
new CountdownTimer(30000,1000){
//在延时进行中
public void onTick(long millisUntilFinished){
mTextField.setText("seconds remaining: "+millisUntilFinished/1000);
}
//在倒计时完成时
public void onFinish(){
mTextFiled.setText("done!");
}
}.start();
其中onTick的调用是同步的,保证这次调用不会再之前调用完成前发生。
onTick的实现需要很多时间执行比倒计时间隔更重要的事情。
构造函数: public CountDownTimer(long millisInFuture, long countDownInterval)
参数:millisInFuture: 从开始调用start()到倒计时完成并onFinish()方法被调用的毫秒数。
countDownInterval: 接收onTick(long) 回调的间隔时间。
公共方法:public final void cancel():取消倒计时
public abstract void onFinish():倒计时完成时被调用
public abstract void onTick(long millisUntilFinished):固定间隔被调用
public synchronized final CountDownTimer start():启动倒计时时
?
(1).Java多线程基础
Runnable Thread TreadPool ScheduleExecutor
线程同步:Synchronized / Lock / Semaphore
(2).多线程和界面交互
当我们在非主线程操作UI时,Android会抛出异常,所以我们应当确保UI操作应该在主线程运行
a.Activity.runOnUiThread(Runnable)
b.View.post(Runnable) ; View.postDelay(Runnable , long)
c.Handler
d.AsyncTask
(3)Android UI 主线程简单原则
不要 lock UI Thread
不要在UI线程外直接操作UI
Handle作用:
(1).执行计划任务,你可以再预定的实现执行某些任务,可以模拟定时器
(2).线程间通信。在Android的应用启动时,会创建一个主线程,主线程会创建一个消息队列来处理各种消息。当你创建子线程是,你可以再你的子线程中拿到父线程中创建的Handler,就可以通过该对象想父线程的消息队列发送消息了。由于Android要求在UI线程中更新界面,因此,可以通过该方法在其他线程中更新界面。
(3).确保操作始终在某个特定的线程中运行。例如当我们从数据库加载数据时,除了程序启动时需要加载外,每当我们收到数据改变的通知时也需要重新加载。为了确保数据的有效性(始终使用最后一次查询是得到的数据),并减少不必要的查询操作,我们应当确保他们在同一个线程中运行。
角色描述:
(1).Looper:(相当于隧道)一个线程可以产生一个Looper对象,由它来管理此线程里的Message Queue(车队,消息隧道)
(2).Handler:你可以构造Handler对象来与Looper沟通,以便Push新消息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的消息
(3).Message Queue(消息队列):用来存放线程放入的消息
(4).线程:UI Thread通常就是main thread ,而Android启动程序时会替它建立一个Message Queue
每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。
线程必须调用Looper.loop()让其开始消息处理过程,且此时该线程无法执行其他代码。
(1).Handler实例与消息处理是关联的,发送和接收要匹配
(2).只能依附在HandlerThread
(3).可以通过设置Looper来选择其依附的线程
(4).所有操作都是在用一个线程中
(5).removeMessage只能一次队列中的Message
使用AsyncTask快速实现异步任务
(1).Android为了降低异步操作开发难度,结合Handler和线程池,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。他具有可以再后台执行耗时操作,同时可以将执行进度与UI进行同步的优点。
(2).AsyncTask定义了三种泛型类型Params,Progress和Result
Params:启动任务执行的输入参数,比如HTTP请求的URL
Progress:后台任务执行的百分比
Result:后台执行任务最终返回的结果
AsyncTask方法:
doInBackground(Params...)后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。
此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress...)来更新新任务的进度。
onPostExecute(Result) 相当于Handler处理UI的方式,在这里面可以使用在doInBackground得到的结果处理操作UI。此方法在主线程执行,任务执行的结果作为此方法的参数返回。
onProgressUpdate(Progress...)可以使用进度条增加用户体验度。此方法在主线程执行,用于显示任务执行的进度。
onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
onCancelled() 用户调用取消时,要做的操作
AsyncTask三个状态:pending,running,finished
AsyncTask必须在主线程创建;
execute()只能调用一次;
execute()必须在主线程执行;
不要自己调用onPreExecute(),onPostExecute(),doInBackground(),onProgressUpdate();
(3).任务可以被中止,并需要不断使用时用AsyncTask
任务需要被多次重复执行,且和UI交互少时用Handler
检测程序中是否有需要使用多线程的地方
(1).StrictMode.ThreadPolicy
detectDiskReads()
detectDiskWrites()
detectNetwork()
(2).检测后的处理方法
penaltyLog()
penaltyDeath()
penaltyDialog()
penaltyDropBox()
penaltyFlashScreen()
?
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。