android项目笔记整理(3)

61.AlphabetIndexer字母索引辅助类
       实现对链表类型的数据进行快速索引. 应用于类似联系人列表右侧的导航栏

注意:
      1.链表里的元素必须是Object类型,并实现toString()方法。

      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)按指定数据项的位置,返回匹配的索引项

public void setCursor(Cursor cursor) 当数据发生变化时,更新数据源(Cursor)
 
62.FragmentTransaction的add和replace的区别
    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没有任何关系。
63.Android 4.0以后在菜单项上显示图标
//通过反射机制来实现
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();
   }
}

64.自定义绘制图形时的StaticLayout类
        使用Canvas的drawText绘制文本是不会自动换行的,即使一个很长很长的字符串,drawText也只显示一行,超出部分被隐藏在屏幕之外。
可以逐个计算每个字符的宽度,通过一定的算法将字符串分割成多个部分,然后分别调用drawText一部分一部分的显示,但是这种显示效率会很低。
        StaticLayout是android中处理文字换行的一个工具类,StaticLayout已经实现了文本绘制换行处理:
public void onDraw(Canvas canvas){
       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来实现换行的。
其中一个构造方法:
public StaticLayout(CharSequence source,int bufstart,int bufend,TextPaint paint,int outerwidth,Layout.Alignment align,
                                             float spacingmult,float spacingadd,boolean includepad,TextUtils.TruncateAt ellipsize,int ellipsizedWidth)
a.需要分行的字符串
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);
65.去掉Android的ListView的分割线
(1).设置android:divider ="@null"
(2).android:divider="#00000000" //最开始的两个0表示透明
(3).setDividerHeight(0):高度设为0

66.<xliff.g/>标签的使用
(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);
67.android:stretchColumns 与 android:scrollHorizontally
其中android:stretchColumns="0"作用是让第一列可以扩展到所有可用空间;
TableLayout几个重要的属性:
    collapseColumns:设置隐藏那些列,列ID从0开始,多个列的话用","分隔
    stretchColumns :设置自动伸展那些列,列ID从0开始,多个列的话用","分隔
    shrinkColumns :设置自动收缩那些列,列ID从0开始,多个列的话用","分隔
可以用"*"来表示所有列,同一列可以同时设置为shrinkable和stretchable。

另外android:scrollHorizontally = "true"表示一个EditText满了后是自动横着移动不是默认的换行。
 
​68.TextWatcher的使用
对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);
         }
      }
}

69.<activity-alias/>标签
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。
 
​70.从资源文件中生成Bitmap对象
Drawable icon = mContext.getResources().getDrawable(resId);
if(icon instanceof BitmapDrawable){
    BitmapDrawable bd = (BitmapDrawable)icon;
    return bd.getBitmap();
}else{
    return null;
}

71.TextView上个性化设置文本
(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:webmaster@google.com"),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(前后都包括)。
}

72.android:imeOptions控制软键盘右下角按键
调用软键盘输入时发现有的软键盘右下角的字是“回车”箭头,有的是“完成”等等文字,并且有点击功能
一、布局文件中加入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值相呼应。

73.android:nextFocus属性介绍
(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>

74.fragment中设置菜单
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();
}

75.actionBar上面的menuItem
可以为menuItem指定布局文件
<item
    android:id="@+id/location_sel"
    android:title="menuItem"
    app:showAsAction ="always"
    app:actionLayout ="@layout/layout_address_button"/>

76.CountDownTimer倒计时的使用
定时执行在一段时候后停止的倒计时,在倒计时执行过程中会再固定间隔时间得到通知,下面的例子显示在一个文本框中显示一个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():启动倒计时时

77.Android中的多线程操作
(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()

原文地址:https://www.cnblogs.com/evilKing/p/4419297.html