耗时整整3个月,我梳理了200道Android面试基础(下)【面试必考,全网最全,每天一遍】

耗时整整3个月,我梳理了200道Android面试基础(下)【面试必考,全网最全,每天一遍】,第1张

文章目录 前言准备好挑战了吗?那么我们开始

前言

本篇内容比较快捷短小。属于快问快答形式。大家可以下载下来,每天一遍。
记住,答案只是引导,在回答完后发散自己的引导思维。去引申。

上篇:耗时整整3个月,我梳理了200道Android面试基础(上)

准备好挑战了吗?那么我们开始 如何将table1表的数据和结构复制到table2上
create table table2 as select * from table1

102.SQLite

多次插入开启事务 //节省回滚时间
try{
	mSqliteDatabase.beginTransaction()
	…
	mSqliteDatabase.execSQL(.)
	…
	mSqliteDatabase.setTransactionSuccessful()
     }catch(Exception e)
     {
	e.printStackTrace()
     }finally{
	mSqliteDatabase.endTransaction()
     }
alter *** 作
a).alter table student add sex integer default 0 //增加sex column
b).目前不支持drop column //采用新建临时表,复制数据,删除旧表
mSqliteDatabase.execSQL(“create table temp as select … from student”)
mSqliteDatabase.execSQL(“drop table if exists student”)
mSqliteDatabase.execSQL(“alter table temp rename to student)
SQLiteOpenHelper.getReadableDatabase和SQLiteOpenHelper.getWritableDatabase将数据库文件放哪了
保存在/data/data//databases/DATABASE_NAME

104.然后将带数据的SQLite同apk一起发布

SQLite放置在res/raw
a).InputStream is= getResources().openRawResource(R.id.filename)
b).InputStream is= getAssets().oepn(path) //path基于assets文件夹Android不能打开放置在apk的数据库文件,因此在初始化时将文件拷贝到sdcard中String databaseFilename=‘/sdcard/test.db’
if(!new File(databaseFilename).exists())
  {
    InputStream is=getResources().openRawResource(R.raw.test)
    FileOutputStream fos=new FileOutputStream(databaseFiename)
    byte[] buffer= new byte[1024]
    int count=0
    while((count=is.read(buffer))!=-1)
    {
      fos.write(buffer,0,count)
    }
    fos.close()
    is.close()
  }
  SQLiteDatabase database=SQLiteDatabase.createOrOpenDatabase(databaseFilename,null)

105.Socket连接成功后,怎么获取服务器的ip和域名

socket.getInetAddress().getHostName()
socket.getInetAddress().getHostAddress()
BufferedInputStream mark //只有BufferedInputStream实现了mark方法 mark(int readmit) //设置在标记位置失效前能够读取的字节数
  a)bis.mark(is.available());
    byte[] buffer=new byte[1024];
    String result="";
    int len;
    while ((len=bis.read(buffer))>0)
    {
   	result+=new String(buffer,0,len);
    }
    bis.reset();
    while ((len=bis.read(buffer))>0)
    {
 	result+=new String(buffer,0,len);
    }
    System.out.println(result);
    is.close();
    bis.close();
如何打开手机中的蓝牙功能 使用Intent
  Intent enableIntent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
  startActivityForResult(enableIntent,1)
BluetoothAdapter
  BluetoothAdapter bluetoothAdapter=BluetoothAdapter.getDefaultAdapter()
  bluetoothAdapter.enable()

111.如何获取已绑定的蓝牙设备

Set<BluetoothDevice> devices=bluetoothAdapter.getBoundedDeviecs()

112.搜索蓝牙的过程中经过哪些状态

IntentFilter filter=new IntentFilter(BluetoothDevice.ACTION_FOUND)
  this.registerReceiver(receiver,filter)
  filter=new IntentFilter(BluetoothDevice.ACTION_DISCOVERY_FINISHED)
  this.registerReceiver(receiver,filter)
  private final BroadcastReceiver receiver=new BroadcastReceiver()
  {
    @Override
    public void onReceive(Context context,Intent intent)
    {
	String action=intent.getAction()
 	if(BluetoothDevice.ACTION_FOUND.equals(action)
       {
	  BluetoothDevice device=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
  	  if(device.getBondState()!=BluetoothDevice.BOND_BONDED)
	  {
            //TODO:处理这些未绑定的设备
 	  }
  	}else if(BluetoothDevice.ACTION_DISCOVERY_FINISHED.equals(action)
	{

	}
    }
  } 
  
  adapter.startDiscovery() 

113.隐式Intent
系统默认 Intent
a).Intent.ACTION_DIAL 拨打电话,需要添加权限android.permission.CALL_PHONE
b).Intent.ACTION_NEW_OUTGOING_CALL 用户主动发起拨打电话
c).Intent.ACTION_SCREEN_ON|Intent.ACTION_SCREEN_OFF

114.如何采用广播监听去电和来电

public class MyReceiver extends BroadcastReceiver
  {
    @Override
    public void onReceive(final Context context,Intent intent)
    {
	if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)
	{
		//todo:去电
	}else{
		//todo:来电
	}
    } 
  }

xml描述

  <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
  <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  <receiver android:name=".PhoneBroadcastReceiver">
	<intent-filter android:priority="1000">
	  <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
	  <action android:name="android.intent.action.PHONE_STATE"/> 
        </intent-filter>
  </receiver>
Android支持的电话状态
TelephonyManager tm =(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)
  switch(tm.getCallState())
  {
    case TelephonyManager.CALL_STATE_RINGING:
 
      break;
    case TelephonyManager.CALL_STATE_IDLE:

      break;
  }
Android如何控制接听和挂断电话
TelephonyManager telephonyManager=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
       Class<TelephonyManager> telephonyManagerClass=TelephonyManager.class;
       Method telephonyMethod=telephonyManagerClass.getDeclaredMethod("getITelephony",null);
       telephonyMethod.setAccessible(true);
       Object obj=telephonyMethod.invoke(telephonyManager,null);
       Method endCallMethod=obj.getClass().getDeclaredMethod("endCall");
       endCallMethod.setAccessible(true);
       //执行电话挂断
       endCallMethod.invoke(obj,null);

       Method answerRinginCallMethod=obj.getClass().getDeclaredMethod("answerRinginCallMethod",null);
       answerRinginCallMethod.setAccessible(true);
       answerRinginCallMethod.invoke(obj,null);

117.请给出访问通话记录的Content Provider URI

>><uses-permission android:name=“READ_CALL_LOG”/>
>>Uri.parse(“content://call_log/calls”)
>>M版本以上进行动态权限申请
  a).if(PackageManager.PERMISSION_GRANTED==checkSelfPermission(Manifest.permission.READ_CALL_LOG)) {
       Cursor cursor = getContentResolver().query(Uri.parse("content://call_log/calls"), null, null, null, null, null);
       cursor.moveToFirst();
       while (!cursor.isAfterLast()) {
         int phone = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.NUMBER));
 	 String name=cursor.getString(cursor.getColumnIndex(CallLog.Calls.CACHED_NAME));
        Log.v(“call_log”,phone+””);
         cursor.moveToNext();
       }
     }else{
        requestPermissions(new String[]{Manifest.permission.READ_CALL_LOG},1);
     }
     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
	 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode)
        {
	   case 1:
	     if(grantResuls[0]==PackageManager.PERMISSION_GRANTED)break;
        }
     }

119.发送短信 //需要动态请求权限:android.permission.SEND_SMS

SmsManager smsManager=SmsManager.getDefault()
  String message=“i gonna fuck u”
  List<String> msges=smsManager.divideMessage(message);
  for(int i=0;i<msges.size();i++)
  {
      smsManager.sendTextMessage(12345678,null,”你好吗”,PendingIntent pi,PendingIntent di)	
  }
ContactsContract

Contacts&CommonDataKinds.Phone //存储通讯录中每个人的概要信息
a).查询姓名

    Cursor c=getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null,null,)
    String name=c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY))

b).查询电话

Cursor c=getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null,)
int id=c.getInt(c.getColumnIndex(ContactsContract.Contacts._ID))
c.close()
c=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID+=?,id,null)
c.moveToFirst()
while(!c.isAfterLast())
{
  String 														phone=c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER))}
c.close()
VideoView 播放视频
Uri uri =Uri.parse(path)
  videoView.setVideoURI(uri)
  videoView.start()
  
  videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {

                mp.start();// 播放
                Toast.makeText(MainActivity.this, "开始播放!", Toast.LENGTH_LONG).show();
            }
        });

  videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                Toast.makeText(MainActivity.this, "播放完毕", Toast.LENGTH_SHORT).show();
            }
        });
在工程路径下的res/drawable存放tree.png,如果将图片显示在View上
InputStream is=getResources().openRawResource(R.raw.xxx)  //只适合读取raw下的资源
  BitmapFactory.Options options=new BitmapFactory.Options()
  options.inSampleSize=2
  Bitmap bitmap=BitmapFactory.decodeStream(is,null,opts)
  canvas.drawBitmap(bitmap,10,10,null)
Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.tree)

123.调用Drawable进行绘图

Drawable.draw(canvas)	//调用setBounds设置范围,在调用draw
  Drawable drawable=getResources().getDrawable(R.drawable.tree)
  drawable.setBounds(x,x,x,x)
  drawable.draw(canvas)

124.如何设置图像透明度

Paint paint=new Paint()
  paint.setAlpha(0.5)
  canvas.drawBitmap(bitmap,sourceRect,destRect,paint)

125.如何旋转View

Matrix
  Matrix matrix=new Matrix()
  matrix.setRotate(120,80,80)
  canvas.setMatrix(matrix)

126.Activity 切换

overridePendingTransition(int enterAnim,int exitAnim)
  a).Intent intent=new Intent(this,xxx.class)		  //跳转
     startActivity(intent);
     overridePendingTransition(R.anim.enter,R.anim.exit)
  b).public void finish()
     {
	overridePendingTransition(R.anim.enter,R.anim.exit)	//退场
     }

127.Android

xml //定义animation-list,位于res/drawable,属于帧动画
  //lottey_animlist.xml
  <?xml version="1.0" encoding="utf-8"?>
  <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
      android:oneshot="false"><!— oneshot 代表只会播放一次,默认为循环播放->
      <item
        android:drawable="@mipmap/lottery_1"
        android:duration="200" />
      <item
        android:drawable="@mipmap/lottery_2"
        android:duration="200" />
      <item
        android:drawable="@mipmap/lottery_3"
        android:duration="200" />
      <item
        android:drawable="@mipmap/lottery_4"
        android:duration="200" />
      <item
        android:drawable="@mipmap/lottery_5"
        android:duration="200" />
      <item
        android:drawable="@mipmap/lottery_6"
        android:duration="200" />
  </animation-list>
  //使用ImageView作为载体显示
  imageView.setImageResource(R.drawable.lottery_animlist)
  AnimationDrawable animationDrawable=(AnimationDrawable)button.getBackground()
  animationDrawable.start()
AnimationDrawable //api
.start()
.stop()
.isRunning()
.getNumberOfFrames()
.setOneShot()

onAnimationEnd 接口 采用hashCode()进行区分

128.动画

AlphaAnimation 透明度渐变,针对
a)动画声明 =>

<alpha xmlns:android="http://schemas.android.com/apk/res/android"  
android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
android:fromAlpha="1.0"  
android:toAlpha="0.1"  
android:duration="2000"/>  

b)动画调用 =>

Animation animation= AnimationUtils.loadAnimation(this,R.anim.alpha_demo)
imageView.startAnimation(animation)

RotateAnimation 旋转渐,针对
a)动画声明 =>

<rotate xmlns:android="http://schemas.android.com/apk/res/android"  
android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
android:fromDegrees="0"  
android:toDegrees="360"  
android:duration="1000"  
android:repeatCount="1"  
android:repeatMode="reverse"/>

ScaleAnimation 放缩渐变,需要指定参考点,针对
a)动画声明 =>

  <scale xmlns:android="http://schemas.android.com/apk/res/android"  
    android:interpolator="@android:anim/accelerate_interpolator"  
    android:fromXScale="0.2"  
    android:toXScale="1.5"  
    android:fromYScale="0.2"  
    android:toYScale="1.5"  
    android:pivotX="50%"  
    android:pivotY="50%"  
    android:duration="2000"/>  

TranslateAnimation 位移渐变,需要指定开始和结束坐标,针对
a)动画声明 =>

<translate xmlns:android="http://schemas.android.com/apk/res/android"  
android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
android:fromXDelta="0"  
android:toXDelta="320"  
android:fromYDelta="0"  
android:toYDelta="0"  
android:duration="2000"/>

LayoutAnimation //在ViewGroup中指定,并作用于它的各个子元素

a)动画声明 => //res/anim/anim_layout.xml

<layoutAnimation
   xmlns:android=“http://schemas.android.com/apk/res/android”
   android:delay=0.5”
   android:animationOrder=“normal”
   android:animation=@anim/anim_item”/>

b)为子元素指定具体动画

<set xmlns:android=“http://schemas.android.com/apk/res/android”
     android:duration=3000>
<alpha android:fromAlpha=0.0 android:toAlpha=1.0/>
<translate android:fromXDelta=500” android:toXDelta=0/>
</set>

c)设置父容器属性

<ListView android:layoutAnimation=@anim/anim_layout”/>

AnimationSet 动画集合,针对
a)动画声明 =>

<set xmlns:android="http://schemas.android.com/apk/res/android"  
  android:interpolator="@android:anim/decelerate_interpolator"  
  android:shareInterpolator="true" >  
  
  <scale  
    android:duration="2000"  
    android:fromXScale="0.2"  
    android:fromYScale="0.2"  
    android:pivotX="50%"  
    android:pivotY="50%"  
    android:toXScale="1.5"  
    android:toYScale="1.5" />  
  
  <rotate  
    android:duration="1000"  
    android:fromDegrees="0"  
    android:repeatCount="1"  
    android:repeatMode="reverse"  
    android:toDegrees="360" />  
  
  <translate  
    android:duration="2000"  
    android:fromXDelta="0"  
    android:fromYDelta="0"  
    android:toXDelta="320"  
    android:toYDelta="0" />  
  
  <alpha  
    android:duration="2000"  
    android:fromAlpha="1.0"  
    android:toAlpha="0.1" />  
  
 </set>  

129.属性动画 Animator

ObjectAnimator
  a)ObjectAnimator
    .ofFloat(view,”rotateX”,0f,360f)
    .setDuration(500)
    .start();
  b)ObjectAnimator
    .ofFloat(view,”y”,sunYStart,sunYEnd)
    .setDuration(3000)
    .setRepeatCount(Animation.INFINITE)
    .setRepeatMode(Animation.REVERSE)
    .setInterpolator(new AccelerateInterpolator());	//设置插值模式为加速
    oa.start();
  c)TypeEvaluator	//辅助ObjectAnimator精确第计算由初始值到结束值的插值模式
    ObjectAnimator
    .ofInt(mSkyView,”backgroundColor”,mBlueSkyColor,mRedSkyColor)
    .setDuration(3000)
    .setEvaluator(new ArgbEvaluator())		//针对色彩的evaluator
    .start();
  d)添加插值监听
    oa.start();
    oa.addUpdateListener(new AnimatorUpdateListener()
    {
	@Override
	public void onAnimationUpdate(ValueAnimator animator)
	{
	  float cVal = (Float) animator.getAnimatedValue();  
          view.setAlpha(cVal);  
          view.setScaleX(cVal);  
          view.setScaleY(cVal);  
	}
    }
ValueAnimator
  a)添加插值监听
   	ValueAnimator animator=ValueAnimator.ofFloat(0,mScreenHeight-mBlueBall.getHeight()); 
	animator.setDuraton(3000).start();
	animator.addUpdateListener(new AnimatorUpdateListener(){
	  @Override
	  public void onAnimationUpdate(ValueAnimator animation)
	  {
	    mBlueBall.setTranslationY((Float)animation.getAnimatedValue())
	  }
	});
	va.setDuration(3000)
  b)返回自定义类型的估值
 	ValueAnimator animator=new ValueAnimator();
	animator.setDuration(3000);
	animator.setObjectValues(new PointF(0,0));
	animator.setEvaluator(new TypeEvaluator<PointF>(){
	    
	    // fraction = t / duration  
            @Override  
            public PointF evaluate(float fraction, PointF startValue,  
                    PointF endValue)  
            {  
                Log.e(TAG, fraction * 3 + "");  
                // x方向200px/s ,则y方向0.5 * 10 * t  
                PointF point = new PointF();  
                point.x = 200 * fraction * 3;  
                point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);  
                return point;  
            }  

	});
AnimatorSet 动画集合
	ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX",1.0f, 2f);  
	ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY", 1.0f, 2f);  	 
	AnimatorSet animSet=new AnimatorSet();
	animSet.setDuration(2000)
	animSet.setInterpolator(new LinearInterpolator());
	animist.playTogether(anim1,anim2);
	animist.start();
  a)AnimatorSet 设置动画执行秩序  
 	animSet.play(anim1).with(anim2)
	animSet.play(anim2).before(anim3)
  b)AnimatorSet xml设置
    Animator animator=AnimatorInflater.loadAnimator(this,R.animator.property_t);
    animator.setTarget()
    animator.start()
定义字符串数组资源 在res/values 定义xxx.xml
  <resources>
    <string-array name=‘planet_array’>
	<item>venus</item>
	<item>mars</item>
	<item>earth</item>
    </string-array>
  </resources>
程序加载
  String[] names=getResources().getStringArray(R.array.names)
图层layer资源
在res/drawable layer.xml
  <?xml version=1.0” encoding=“utf-8?>
  <layer-list xmlns:android=“http://schemas.android.com/apk/res/android”>
    <item>
      <bitmap android:src=“” android:gravity=“center”/>
    </item>
    <item android:top=20dp” android:left=20dp”>
      <bitmap android:src=“” android:gravity=“center”/>
    </item>
  </layer-list>
Clip图像资源 放置在res/drawable clip.xml
  <clip xmlns=“http://schemeas.android.com/apk/res/android”
	android:drawable=“”
	android:orientation=“horizontal”
	android:gravity=“left”
  />
ImageView imageView
  ClipDrawable drawable=(ClipDrawable)imageView.getBackground()
  drawable.setLevel(3000)//内部预设最大值为10000
ShapeDrawable
放置在res/drawable shape.xml
  <shape xmlns=“http://schemas.android.com/apk/res/android” android:shape=“rectangle”>
    <!— 定义渐变色 —>
    <gradient android:startColor=“#00f” android:endColor=“#f00” android:angle=45/>
    <padding  android:left=7dp” android:right=7dp”/>
    <corners android:radius=8dp”/>
    <size android:height="20dp" android:width="20dp"/>
    <solid android:color=“”/>
    <stroke android:color=“” android:width=“”/>
  </shape>
如何统一设置多个View的android:textSize和android:textColor
放置于res/values style.xml
  <resources>
    <style name=“customText” parent=@style/Text>
	<item name=“android:textSize”>20sp</item>
	<item name=“android:textColor”>#008</item>
    </style>
  </resources>

布局文件中的”@“、”+”、”?”含义
引用资源
+号代表所引用的资源id在R类不存在
?代表引用当前主题的属性

android获取屏幕高度和宽度的办法
:1.通过获取DisplayMetrics

DisplayMetrics dm=getResources().getDisplayMetrics()
 int width=dm.widthPixels
 int height=dm.heightPixels

:2.通过windowManager

  >DisplayMetrics dm=new DisplayMetrics()
   getWindowManager().getDefaultDisplay(dm)
   dm.widthPixels , dm.heightPixels

138.AsyncTask
在ui主线程 执行.execute(T… params, T …progress,T result) 对应的参数会再doInBackground接收到回调 => onPreExecute、onPostExecute、doInBackground、onProgressUpdate
AsyncTask的模板参数

示例:
:1.ProgressBarAsyncTask asyncTask = new ProgressBarAsyncTask(textView, progressBar);
asyncTask.execute(1000);
//AsyncTask子类
public class ProgressBarAsyncTask extends AsyncTask{

    private TextView textView;  
    private ProgressBar progressBar; 

    public ProgressBarAsyncTask(TextView textView, ProgressBar progressBar) {  
        super();  
        this.textView = textView;  
        this.progressBar = progressBar;  
    }  
    
    @Override  
    protected String doInBackground(Integer... params) {  
        NetOperator netOperator = new NetOperator();  
        int i = 0;  
        for (i = 10; i <= 100; i+=10) {  
            netOperator.operator();  
            publishProgress(i);  			//进入onProgressUpdate回调
        }  
        return i + params[0].intValue() + "";  
    }  
    
    //该回调处于ui主线程
    @Override  
    protected void onProgressUpdate(Integer... values) {  
        int vlaue = values[0];  
        progressBar.setProgress(vlaue);  
    }

    //该方法运行在UI线程当中
    @Override  
    protected void onPreExecute() {  
        textView.setText("开始执行异步线程");  
    }  

    //该回调处于ui主线程,onPostExecute的形参类型由result决定
    @Override  
    protected void onPostExecute(String result) {  
        textView.setText("异步 *** 作执行结束" + result);  
    }    
  }

139.Intent可传递的数据类型

8种基本数据类型:double、int、float、char、long、byte、short、String
实现了Parcelable接口的类
实现了Serializable接口的类

141.AlarmManager //闹钟

初始化
:1.AlarmManager am=(AlarmManager)getSystemService(Context.ALARM_SERVICE)类型
:1.AlarmManager.RTC_WAKEUP | AlarmManager.RTC //按系统时钟计算,WAKEUP表示睡眠可用
:2.AlarmManager.ELAPSED_REALTIME | AlarmManager.ELAPSED_REALTIME_WAKEUP//按真实流逝时间计算
:3.AlarmManager.POWER_OFF_WAKEUP //关机也可使用设定闹钟
a). am.set(int type,long startTime,PendingIntent pi)
b). am.setRepeating(int type,long startTime,long interval,PendingIntent pi) //设置重复闹钟
c).pi //当闹钟触发后,执行pi。可以通过Service或者Activity去进行提示 HandlerThread
//例子
  HandlerThread mThread=new HandlerThread(“xx”);
  mThread.start();
  handler = new Handler( myHandlerThread.getLooper() ){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //这个方法是运行在 handler-thread 线程中的 ,可以执行耗时 *** 作
                Log.d( "handler " , "消息: " + msg.what + "  线程: “+
   				Thread.currentThread().getName()  ) ;
            }
   };
  handler.send(xxx)

Thread

  a)没有Looper 所以需要在Thread的run中去执行Looper.prepare()Looper.loop()
  b)Hanlder的初始化需要当前线程具有looper,所以也得放置在Looper的循环中

HandlerThread
a)HandlerThread自行进行Looper的prepare、loop等api
b)允许调用getLooper()获取Looper实例
c)可以在handleMessage执行耗时
d)HandlerThread自己创建Looper,分担了主Looper的压力
e)异步请求是排队调用的,不适合网络IO

自定义ViewGroup
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs)		//返回支持设置的属性
  {
    return new MarginLayoutParams(getContext(),attrs);
  }
  
onMeasure => a)View的宽高测量调用  b)setMeasuredDimension设置宽高
//例子
  @Override 
  protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec)
  {
    int widthMode=MeasureSpec.getMode(widthMeasureSpec);
    int heightMode=MeasureSpec.getMode(heightMeasureSpec);
    int sizeWidth=MeasureSpec.getSize(widthMeasureSpec);
    int sizeHeight=MeasureSpec.getSize(heightMeasureSpec);
    //进行childView的宽高计算,会进入view的onMeasure回调
    measureChildren(widthMeasureSpec, heightMeasureSpec)	
		//for+measureChild(child,widthMeasureSpec,heightMeasureSpec)
    int cCount = getChildCount();  
    int cWidth = 0;  
    int cHeight = 0;  
    MarginLayoutParams cParams = null;  
    for (int i = 0; i < cCount; i++)  
    {
      View childView = getChildAt(i);  
      cWidth = childView.getMeasuredWidth();  
      cHeight = childView.getMeasuredHeight();
      cParams = (MarginLayoutParams) childView.getLayoutParams();
      // 上面两个childView  
      if (i == 0 || i == 1)  
      {  
        tWidth += cWidth + cParams.leftMargin + cParams.rightMargin;  
      } 
      if (i == 2 || i == 3)  
      {  
         bWidth += cWidth + cParams.leftMargin + cParams.rightMargin;  
      }  
      width=Math.max(tWidth,bWidth) 
      
    }
    setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth  
                : width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight  
                : height);  
  }
onLayout => 作为虚函数需要由子类实现  a)放置各个子View
  protected void onLayout(boolean changed,int l,int t,int r,int b)
  {
    int cCount = getChildCount(); 
    MarginLayoutParams cParams = null;
    for(int i=0;i<cCount;i++)
    {
      View childView = getChildAt(i);
      int cWidth=childView.getMeasuredWidth()
      int cHeight=childView.getMeasuredHeight()
      //……
      childView.layout(cl, ct, cr, cb);  
    }
  }

147.JVM的GC算法

标记-清除 //只清除可回收内存,使得在清除后出现很多不连续的小空间碎片
a)标记对象分为:可用内存、可回收内存、存活对象
b)释放可回收内存
c)缺点:清除标记后产生大量的不连续空间标记-整理 //需要进行整理,同时将存活对象移动到边界的一端
a)标记对象: 略
b)增加存活对象的整理过程复制算法 //新生代采用复制算法 - > 8:1:1
a)它将内存分为大小相等的2块,每次只是使用其中一块。当一块内存用完之后,就将存活的对象复制到另外一块内存区域并将本块内存清理
b)新生代的复制算法:
’8’比例和一块’1’比例的内存作为活动空间,剩余的’1’比例作为空闲空间
每次新建对象放置于’8’比例的内存中,GC时清除活动空间的可回收对象,并把存活对象移动到空闲空间活动空间和空闲空间的轮换,始终在’1’比例的内存块中进行分代收集 //新生代的对象有’年龄’计算,当超过阀值,转入老年代内存
a)新生代=>Eden+s0+1 老生代=>Perm OkHttp
使用
:1.get方式 //new OkHttpClient -> 构造Request对象 -> newCall ->enqueue or execute
> String url = "http://wwww.baidu.com"		//同步
  OkHttpClient okHttpClient = new OkHttpClient()
  final Request request = new Request.Builder()
    .url(url)
    .get()
    .build();
  Response response= okHttpClient.newCall(request).execute()
  String result= response.body().toString
> String url = "http://wwww.baidu.com"		//异步
  OkHttpClient okHttpClient = new OkHttpClient()
  final Request request = new Request.Builder()
    .url(url)
    .get()
    .build()
  okHttpClient.newCall(request).enqueue(ne Callback(){
@Override
	  public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: ");
      }
 	@Override
      public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, "onResponse: " + response.body().string());
    }
  })

:2.post方式 //new OkHttpClient -> 构造RequestBody、指定mimeType -> 构造request

   > OkHttpClient okHttpClient= new OkHttpClient()
     RequestBody requestBody=new FormBody.Builder()
				.add("username","danding")
				.build()
     Request request= new RequestBody.Builder()
			.url(url)
			.post(requestBody)
			.build()
     okHttpClient.newCall(request).enqueue(new CallBack(){
	@Override
    	  public void onFailure(Call call, IOException e) {
            Log.d(TAG, "onFailure: ");
          }
     	@Override
          public void onResponse(Call call, Response response) throws IOException {
            Log.d(TAG, "onResponse: " + response.body().string());
        }
     })

:3.自定义Interceptor

> @Override
  public Response intercept(Chain chain) throws IOException {
 Request request=chain.request()
 //todo.... 
 Response response=chain.proceed(request)
 return response
  }

源码
:1.创建OkHttpClient

> public OkHttpClient() {		//直接创建的 OkHttpClient对象并且默认构造builder对象进行初始化
   this(new Builder());
  }
  OkHttpClient(Builder builder) {
this.interceptors = Util.immutableList(builder.interceptors)
...
  }

:2.创建Request //代码new Request.Builder().url(url).build()

> public final class Request {
public Builder() {
  	  this.method = "GET";
   	  this.headers = new Headers.Builder();
    }
public Builder url(String url) {
  HttpUrl parsed = HttpUrl.parse(url);	//获取scheme、host、port等信息
  return url(parsed)		//设置this.url成员
}
  }

:3.okHttpClient.newCall(request)

> public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
    @Override 
    public Call newCall(Request request) {
     return new RealCall(this, request, false /* for web socket */);
    }
    ...
  }
> final class RealCall implements Call {
 @Override 
     public void enqueue(Callback responseCallback) {
     synchronized (this) {
   if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
       }
       captureCallStackTrace();
       client.dispatcher().enqueue(new AsyncCall(responseCallback))
     }
  }
> class AsyncCall extends NamedRunnable{	//implements Runnable 
protected void execute() {
  try {
        Response response = getResponseWithInterceptorChain()//!!!核心
    ... List<Interceptor> interceptors = new ArrayList<>()
	interceptors.addAll(client.interceptors())
	interceptors.add(retryAndFollowUpInterceptor)
	interceptors.add(new BridgeInterceptor(client.cookieJar()))
	interceptors.add(new ConnectInterceptor(client))
	interceptors.add(new CallServerInterceptor(forWebSocket))
   
    ... Interceptor.Chain chain = new RealInterceptorChain(
    		interceptors, null, null, null, 0, originalRequest);
	return chain.proceed(originalRequest)

    ... public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec 			httpCodec ,RealConnection connection) throws IOException {
	  if (index >= interceptors.size()) throw new AssertionError()
	  val interceptor=interceptos.get(index)
	  Response response = interceptor.intercept(next)
	
	}
    responseCallback.onResponse(RealCall.this, response)
}
  }

:4.Dispatcher线程池

 > 	/** 最大并发请求数为64 */
private int maxRequests = 64;
/** 每个主机最大请求数为5 */
private int maxRequestsPerHost = 5;

/** 线程池 */
private ExecutorService executorService;

/** 准备执行的请求 */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

/** 正在执行的异步请求,包含已经取消但未执行完的请求 */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

/** 正在执行的同步请求,包含已经取消单未执行完的请求 */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

> enqueue //压入请求
  synchronized void enqueue(AsyncCall call) {
   //maxRequest==64	
   if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
  	 runningAsyncCalls.add(call);		//压入正在执行队列
     executorService().execute(call);
   } else {
     readyAsyncCalls.add(call);		//压入就绪队列
   }
  }

:5.Interceptor

>BridgeInterceptor -> 添加Content-TypeContent-LengthUser-Agent等协议头
>ConnectInterceptor -> ....
>CallServerInterceptor -> 实际发送网络请求

149.ButterKnife //源码阅读
初始化
:1.定义处理器


```java
  public class MyProcessor extends AbstractProcessor {

    //用来指定你使用的 java 版本。通常你应该返回
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    //会被处理器调用,可以在这里获取Filer,Elements,Messager等辅助类,后面会解释
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }

  //这个方法返回stirng类型的set集合,集合里包含了你需要处理的注解
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> annotataions = new LinkedHashSet<String>();
        annotataions.add("com.example.MyAnnotation");
        return annotataions;
    }


   //核心方法,这个一般的流程就是先扫描查找注解,再生成 java 文件
   //这2个步骤设计的知识点细节很多。
    @Override
    public boolean process(Set<? extends TypeElement> annoations,
            RoundEnvironment env) {
        return false;
    }
}

:2.注册处理器

     @AutoService(Processor.class)
     Public class xxx extends AbstractProcessor{

     }
>>流程 
  :1.process (annotations:Set , env:RoundEnvironment)
   ->Map<TypeElement, BindingSet> targetClassMap = findAndParseTargets(env)
     ...Map<TypeElement,BindingSet> targetClassMap
	//查找用BindView注解的元素
     ...for(Element element:env.getElementsAnnotatedWith(BindView.class)
	try{
   	  parseBindView(element, Map<TypeElement,BindingSet.Builder>builderMap,...) 
	       ....enclosingElement=(TypeElement)element.getEnclosingElement()
   		    TypeMirror elementType = element.asType()//转换成TypeMirror才能获取类型等信息
		    if (elementType.getKind() == TypeKind.TYPEVAR) {//变量类型
			TypeVariable typeVariable = (TypeVariable) elementType
		        elementType = typeVariable.getUpperBound()//获取上限类型
		    }
		    //检查1!!!
		    if (!isSubtypeOfType(elementType, VIEW_TYPE) && !isInterface(elementType)) {
			throw Error
		    }
		    int id = element.getAnnotation(BindView.class).value()//获取资源id
		    BindingSet.Builder builder = builderMap.get(enclosingElement)
		    if(builder!=null){}
		    else
		      builder = getOrCreateBindingBuilder(builderMap, enclosingElement)
			... builder=BindingSet.newBuilder(enclosingElement)
			     ->packageName= getPackage(enclosingElement).getQualifiedName()
				 className=enclosingElement.getQualifiedName().toString()
				 bindingClassName = ClassName.get(packageName, className + "_ViewBinding")
			... builderMap.put(enclosingElement,builder)
		      
		    String name = simpleName.toString();//绑定注解的变量名
		    TypeName type = TypeName.get(elementType)//变量类型
		    //往刚刚生成的BuildingSet.Builder加入field信息
		    builder.addField(resourceId, new FieldViewBinding(name, type, required))
		       ... new FieldViewBinding(name, type, required)//分配变量名、变量类型

		       ... viewId=new ViewBinding.Builder(id)
			   viewIdMap.put(id,viewId)//viewIdMap为BindingSet的私有变量
		     	   viewId.setFieldBinding(biding)
			  

	  }
	   
  :2.for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) {
       TypeElement typeElement = entry.getKey();
       BindingSet binding = entry.getValue();
       binding.brewJava 
	 ... BuildingSet.createType	//创建TypeSpec
             TypeSpec.Builder result = TypeSpec.classBuilder(bindingClassName.simpleName())
        	.addModifiers(PUBLIC);     //创建类
	      //设置类要实现的接口
	      if (parentBinding != null) {
      		 result.superclass(parentBinding.bindingClassName);
    	      } else {
      		 result.addSuperinterface(UNBINDER);//设置实现Unbinder
    	      }
	      if (hasTargetField()) {	   //检查FieldViewBinding
     		 result.addField(targetTypeName, "target", PRIVATE);
              }
	      //创建构造函数
	      if (isActivity) 
      		result.addMethod(createBindingConstructorForActivity(useAndroidX));
   		  .... MethodSpec.Builder builder = MethodSpec.constructorBuilder()
        		.addAnnotation(useAndroidX ? UI_THREAD_ANDROIDX : UI_THREAD)
 		        .addModifiers(PUBLIC)
		        .addParameter(targetTypeName, "target");//targetTypeName指向Activity
	      //构建bind
	      result.addMethod(createBindingConstructor(sdk, debuggable, useAndroidX))
		... if (hasViewBindings()) {
			for (ViewBinding binding : viewBindings) {
        	           addViewBinding(constructor, binding, debuggable)
			    -> FieldViewBinding fieldBinding = binding.getFieldBinding()
				
      			}
		    }
	      //针对hasViewBinding,构建unbind函数
	      if (hasViewBindings() || parentBinding == null) {
	        result.addMethod(createBindingUnbindMethod(result, useAndroidX));
              }
	
	      
     }

概念

Element //包含程序中的包、类、方法等
TypeElement //类
VariableElement //变量
ExecutableElement //函数TypeElement
不含有类的信息,转换为Element后,调用element.asType()获取TypeMirror
:3.Typemirror //tm=element.asType()
包含元素信息 //比如TYPEVAR等
getKind() //DECLARED|EXECUTE
toString() //返回类型完全限定名
:4.FieldViewBinding 类
constructor
FieldViewBinding(String name, TypeName type, boolean required) {
this.name = name;
this.type = type;
this.required = required;
}
b).getModifiers //返回Modifier修饰
c).getSimpleName //返回注释元素的变量名
d).getEnclosingElement //返回上一级Element,Enclosing(Activity)= Annotation,Enclosing(Button)=Activity
e). processingEnv.getElementUtils().getPackageOf(Element ) //获取包名
解析BindView的流程
  :1.parseBindView(Element element,....)
     TypeMirror elementType = element.asType()
     if (elementType.getKind() == TypeKind.TYPEVAR) //注解在变量
     {
       TypeVariable typeVariable = (TypeVariable) elementType;
       elementType = typeVariable.getUpperBound();//获取变量的上界,比如TextView extends View 
     }
     //判断是否为View的子类型,不是的话报错
     if (!isSubtypeOfType(elementType, VIEW_TYPE) && !isInterface(elementType)) {
      if (elementType.getKind() == TypeKind.ERROR) {
        note(element, "@%s field with unresolved type (%s) "
                + "must elsewhere be generated as a View or interface. (%s.%s)",
            BindView.class.getSimpleName(), elementType, enclosingElement.getQualifiedName(),
            element.getSimpleName());
      } else {
        error(element, "@%s fields must extend from View or be an interface. (%s.%s)",
            BindView.class.getSimpleName(), enclosingElement.getQualifiedName(),
            element.getSimpleName());
        hasError = true;
      }
    }
    //获取@BindView的id值
    int id = element.getAnnotation(BindView.class).value();
    //检查是否有缓存,有则生成ViewBindings
    BindingClass bindingClass = targetClassMap.get(enclosingElement);
    if (bindingClass != null) {
      ViewBindings viewBindings = bindingClass.getViewBinding(getId(id));
      if (viewBindings != null && viewBindings.getFieldBinding() != null) {
        FieldViewBinding existingBinding = viewBindings.getFieldBinding();
        error(element, "Attempt to use @%s for an already bound ID %d on '%s'. (%s.%s)",
            BindView.class.getSimpleName(), id, existingBinding.getName(),
            enclosingElement.getQualifiedName(), element.getSimpleName());
        return;
      }
    } else {
      //声称_ViewBinding类
      bindingClass = getOrCreateTargetClass(targetClassMap, enclosingElement);
    }
    //name就是word
    String name = element.getSimpleName().toString();
    //类型的名字
    TypeName type = TypeName.get(elementType);
    //生成FieldViewBinding实体
    FieldViewBinding binding = new FieldViewBinding(name, type, required)
    //5.加入到 bindingClass 成员变量的集合中
    bindingClass.addField(getId(id), binding);
:2.getOrCreateTargetClass			//获取或者创建BindingClass
 >BindingClass bindingClass = targetClassMap.get(enclosingElement);
  //再次判断
  if (bindingClass == null) {
     TypeName targetType = TypeName.get(enclosingElement.asType())
 String packageName = getPackageName(enclosingElement);//获取该类的包名
 //类名字
     String className = getClassName(enclosingElement, packageName)
     ClassName bindingClassName = ClassName.get(packageName, className + "_ViewBinding")
     boolean isFinal = enclosingElement.getModifiers().contains(Modifier.FINAL)
     bindingClass = new BindingClass(targetType, bindingClassName, isFinal)
 //加入集合,缓存
     targetClassMap.put(enclosingElement, bindingClass);
  }

:3.process //生成java文件

 >//遍历生存生成java 文件
  for (Map.Entry<TypeElement, BindingClass> entry : targetClassMap.entrySet()) {
    TypeElement typeElement = entry.getKey();
    BindingClass bindingClass = entry.getValue();

    JavaFile javaFile = bindingClass.brewJava();
    try {
      javaFile.writeTo(filer);
    } catch (IOException e) {
    }
  }

:4.brewJava //生成

BindingClass的数据结构
:1.

注解

  @Target({ElementType.FIELD})
  @Retention(RetentionPolicy.CLASS)
  public @interface BindView{
    @IdRes int value();
  }
JavaPoet用法
a).目标模板
 >public final class HelloWorld{
public static void main(String[] args){
  System.out.println(“hello,JavaPoet!);
}
  }

b).? extends AbstractProcessor

 {
private Filer filer;

@Override  
   public synchronized void init(ProcessingEnvironment processingEnv) {  
     super.init(processingEnv);  
     // Filer是个接口,支持通过注解处理器创建新文件  
     filer = processingEnv.getFiler();  
   }  	

public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
   for (TypeElement element : annotations) {  
         if (element.getQualifiedName().toString().equals(JPHelloWorld.class.getCanonicalName())) {  
            // 创建main方法  
            MethodSpec main = MethodSpec.methodBuilder("main")  
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)  
                    .returns(void.class)  
                    .addParameter(String[].class, "args")  
                    .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")  
                    .build();  
            // 创建HelloWorld类  
            TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")  
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)  
                    .addMethod(main)  
                    .build();  
  
            try {  
                // 生成 com.example.HelloWorld.java  
                JavaFile javaFile = JavaFile.builder("com.example", helloWorld)  
                        .addFileComment(" This codes are generated automatically. Do not modify!")  
                        .build();  
                // 生成文件  
                javaFile.writeTo(filer);  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
         }  
      }  
      return true;  
}	
 }
addViewBinding //赋值BindView对应的View id
  :1.CodeBlock.Builder builder=CodeBlock.builder()
	.add("target.$L",fieldBinding.getName())
  :2.赋值
     if (requiresCast) {	//需要转型
        builder.add("($T) ", fieldBinding.getType());
      }
     builder.add("source.findViewById($L)", binding.getId().code);  //getId对应设置时的数字
- bind 				//运行时
  :1.public static Unbinder bind(Activity target){		//针对Activity和DecorView
	View sourceView=target.getWindow().getDecorView()
	return createBinding(target,sourceView)
     }
  :2.public static Unbinder crateBinding(Object target,View source)
     {
	Class<?> targetClass =target.getClass()
       if (debug) Log.d(TAG, "Looking up binding for " + targetClass.getName());
       Constructor<? extends Unbinder> constructor = findBindingConstructorForClass(targetClass)
	//返回构造器,以便初始化对象
       if (constructor == null) {
         return Unbinder.EMPTY;
       }
       try {
         return constructor.newInstance(target, source);		//初始化对象
       } catch (IllegalAccessException e) {.
       }
    }
  :3.Constructor<? extends Unbinder> findBindingConstructorForClass(Class<?> cls){
	Constructor<? extends Unbinder> bindingCtor = BINDINGS.get(cls)//查看缓存
  	if (bindingCtor != null) {
           if (debug) Log.d(TAG, "HIT: Cached in binding map.");
           return bindingCtor;
        }
	String clsName = cls.getName()		//cls属于Class,调用getName获取类名
	
	try {
          Class<?> bindingClass = cls.getClassLoader().loadClass(clsName +"_ViewBinding”)
          bindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);
         } catch (ClassNotFoundException e) {
            bindingCtor = findBindingConstructorForClass(cls.getSuperclass());
         } catch (NoSuchMethodException e) {
         }
         BINDINGS.put(cls, bindingCtor)	
     }

150.Dalvik内存模型

Heap=Active Heap + Zygote HeapBitmap来标记引用情况
:1.采用一个unsigned long数组来维护Heap Bitmap, Bitmap的某个位为1则标记该对象正在使用
:2.采用Live Bitmap+ Mark Bitmap来描述堆对象

Live Bitmap用于标记上一次GC时被引用的对象,也就是未回收对象
Mark Bitmap标记当前GC有被引用的对象
回收Live Bitmap=1, Mark Bitmap=0的对象

垃圾收集
:1.mark阶段

标记根对象(非并行) -> 标记栈变量、静态成员、方法区常量、本地方法被引用的对象
标记被根集所引用的对象(允许并行) -> 增加Card Table,以免其他线程更改了该对象的引用情况

Card Table
:1.Card Table 由Card组成,每个Card可以为CLEAN或者DIRTY,每个Card占用一个字节
:2.在堆中,连续GC_CARD_SIZE地址的对象共用一个Card,Dalvik设置为128,在32位机器上就是4个对象Mark Stack //递归方式的标记对象
:1.避免函数递归层次过深占用内存
:2.在第一次标记的过程中,先找到根集对象,然后将其压入Mark Stack

在之后的过程中,d出Mark Stack的对象,并标记在Bitamap之中,并将该对象的引用也压入Mark Stack

151.ART垃圾回收

Image Space、Zygote Space、Allocation Space、Large Object Space、Card TableBitmap=Live Bitmap +Mark Bitmapmod_union_table
:1.image_mod_union_table -> 记录在并行GC阶段,image space上所分配的对于在Zygote、Allocation对象的引用
:2.zygote_mod_union_table -> 记录在并行Gc阶段,zygote space上分配的对于Allocation堆的对象的引用
:3.跟Card Table配合,使得Card Table可以在标记阶段重复使用第一步是调用ModUnionTable类的成员函数ClearCards清理Card Table里面的Dirty Card,并且将这些Dirty Card记录在Mod
Union Table中。第二步是调用ModUnionTable类的成员函数Update将遍历记录在Mod Union Table里面的Drity Card,并且找
到对应的被修改对象,然后将被修改对象引用的其它对象记录起来。第三步是调用ModUnionTable类的成员函数MarkReferences标记前
面第二步那些被被修改对象引用的其它对象。通过这种方式,就可以使用Card Table可以在标记阶段重复使用,即在执行第二步之前,重
复执行第一步,最后通过Mod Union Table将所有被被修改对象引用的其它对象收集起来统一进行标记,避免对相同对象进行重复标记stack
:1.Mark Stack,用于在GC过程中递归标记对象

151.2.JVM 可达性分析中哪些对象可以作为根节点

栈的引用对象本地方法栈中的引用对象 //指jni类的静态成员方法区重的常量引用对象 HashSet 采用HashMap进行实现,值为new出的Object采用HashMap的put进行不重复性的保证 SSL中的对称加密和非对称加密 对称加密
a).当通过浏览器向服务器请求安全网页时(https://…)
b).服务器同时把证书和公钥发送过来
c).浏览器检查证书是不是由信赖机构颁发的
d).浏览器随机生成对称密钥,并采用服务器发送的公钥加密自身的公钥,同时采用公钥加密请求,一并发送至服务器
e).服务器用自己的私钥解密了发过来的密钥,并用该密钥解析加密后的请求
f).服务器用收到的密钥加密返回的数据
G).浏览器用自身的私钥解密服务器返回的加密消息
//那么中间人有没有可能解密出信息呢,关注点主要在客户端发来的信息
//从d步骤开始检测,中间人截取到了被加密的浏览器密钥,但是无法猜测对应服务器的公钥,故无法解密
// a)假设中间人清除目标服务器,首先获取了服务器的公钥,但是只有私钥才能解密被该公钥加密后的信息,故也无法解密 Handler的内存泄露问题 当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用(不然你怎么可 能通过Handler来 *** 作Activity中的View?)。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收改善
:1.Activity的引用包装为WeakReference<>弱引用
:2.声明Handler为静态类 Android volatile关键字 JVM对于volatile所提供的内存屏障 //内存屏障的作用 -> 阻止屏障2侧的指令重排
a).Load Barrier //在指令前插入Load Barrier,可以让高速缓存的数据失效,强制从主存加载
b).Store Barrier //在指令后插入Store Barrier,强制写回主存
c).在每个volatile写 *** 作前插入StoreStore屏障,在写 *** 作后插入StoreLoad屏障
在每个volatile读 *** 作前插入LoadLoad屏障,在读 *** 作后插入LoadStore屏障多线程工作时,线程对于特定变量采取对主存读取后拷贝到自身内存区的办法进行 *** 作volatile保证该变量是通过共享内存进行同步的volatile不能替代synchronized,因为不能保证原子性 *** 作 EventBus 源码阅读 //反射Class通常采用通配符 =>Class或者Class 成员
:1.subscriptionsByEventType:HashMap //subscription = subscriber+subscriberMethod
:2.typesBySubscriber
:3.subscriberMethodFinder
:4.METHOD_CACHE:HashMap //缓存
:5.PostingThreadState //带有事件队列,当前线程的posting状态流程
:1.register
val subscriberClass=subscriber.getClass()
  
List<SubscriberMethod> subscriberMethods=subscriberMethodFinder.findSubscriberMethods(cls)
   {
	...findUsingReflection
           ...moveToSuperclass 		//从子类到父类都去查找注解信息
              ...findUsingReflectionInSingleClass 
		-> 检查参数是否只有一个 -> getAnnotation -> 获取Subscribe注解信息 -> 生成subscriberMethod
   }	

:2.subscribe

   >for(subscriberMethod in subscriberMethods)
    {
  	subscribe(subscriber,subscriberMethod)
	  ...Class<?> eventType = subscriberMethod.eventType;//获取订阅的事件类型
	     subscription newSubscription = new Subscription(subscriber, subscriberMethod)
	     val subscriptions=subscriptionsByEventType.get(eventType)
	     if(subscriptions.contains(newSubscription))//检查1!!!
		throw new Error
	     subscriptionsByEventType.put(eventType,subscriptions)
	  
	  ...List<Class<?>> events=typesBySubscriber.get(subscriber)//获取订阅者监听的所有消息
	     events.add(eventType)    
    }

:3.post //发送事件

   >public void post(Object event)
    {
	..PostingThreadState postingState=currentPostingThreadState.get()//ThreadLocal变量保存
	  List<Object> eventQueue=postingState.eventQueue
	  eventQueue.add(event)

	..if(!postingState.isPosting)
	  {
	    postingState.isMainThread=Looper.getMainLooper()==Looper.myLooper()
	    try{
		while(!eventQueue.isEmpty())
		  postingSingleEvent(eventQueue.remove(0),postingState)//发送单个事件!!!
		     ...//查找eventClass类所有的父类以及接口
            		List<Class<?>> eventTypes = lookupAllEventTypes(eventClass)
			for(clazz in eventTypes)
			{
			  postSingleEventForEventType(event , postingState , clazz )
			  -> CopyOnWriteArrayList<Subscription> subscriptions
			     subscriptions=subscriptionsByEventType.get(clazz)
			     for(subscription in subscriptions)
				postToSubscription(subscription, event, postingState.isMainThread)
				..区别一下主进程的派送方式 -> 根据getMainLooper创建handler再sendMessage
			}
	    }catch(){}
	  }
    }
EventBus使用
a).EventBus.getDefault().register(subscriber: this) //注册
b).单例模式
>public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

c).@Subscribe(threadMode=ThreadMode.POSTING)

 public void handleSomethingElse(Msg msg)		//Msg为普通po,handleSomethingElse名字不固定
 {.
 }

d).线程指定
>ThreadMode.POSTING //在信息发送的线程进行响应
>ThreadMode.MAIN //ui主线程进行响应
e).StickyEvent
>EventBus.getDefault().postSticky(new Msg(“Hello everyone!"))
>Msg msg= EventBus.getDefault().getStickyEvent(Msg.class)
>EventBus.getDefault().removeStickyEvent(msg)

register //注册
:1.获取SubscriberMethods
 List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass){
List<SubscriberMethod> subscriberMethods=METHOD_CACHEA.get(subscriberClass)
    if(subscriberMethods!=null)	return subscriberMethods
    subscriberMethods=findUsingReflection(subscriberClass)
    METHOD_CACHE.put(subscriberClass, subscriberMethods);
    Return subscriberMethods
 }

:3.根据反射遍历

 private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
    //FindState 用来做订阅方法的校验和保存
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        //通过反射来获得订阅方法信息
        findUsingReflectionInSingleClass(findState);
        //查找父类的订阅方法
        findState.moveToSuperclass();
    }
    //获取findState中的SubscriberMethod(也就是订阅方法List)并返回
    return getMethodsAndRelease(findState);
}

:4.获取注解以及注解的值

  private void findUsingReflectionInSingleClass(FindState findState){
Method[] methods
    try{
  methods=findState.clazz.getDeclaredMethods()//通过反射获取方法
}
catch(Throwable th){}
//遍历Method
    for (Method method : methods) {
   int modifiers = method.getModifiers();
   if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) 
   {
      Class<?>[] parameterTypes = method.getParameterTypes();
      //保证必须只有一个事件参数
          if (parameterTypes.length == 1) {
	//获取注解
	Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class)
	if (subscribeAnnotation != null) {
               Class<?> eventType = parameterTypes[0];
                 
               ThreadMode threadMode = subscribeAnnotation.threadMode();
               //实例化SubscriberMethod对象并添加
               findState.subscriberMethods.add(new SubscriberMethod(method, eventType,
		threadMode,
                    subscribeAnnotation.priority(), 
		subscribeAnnotation.sticky()));
                  
             }
      }
   }
}
  }
Subscription //封装注册信息
a).Object subscriber
b).SubscriberMethod subscriberMethodSubscriberMethod
a).Method method
b).int priority
c).boolean sticky
d).ThreadMode threadMode
e).Class eventType注释类 //@Retention定义了该Annotation被保留的时间长短,@Target({ElementType.METHOD})注释对象为方法
    public @interface Subscribe{
       ThreadMode threadMode() default ThreadMode.POSTING;
       boolean sticky() default false;
       int priority() default 0;
    }
>>subscribe //注册方法
  :1.private void subscribe(Object subscriber, SubscriberMethod subscriberMethod)
     {
	//获取订阅的事件类型
        Class<?> eventType = subscriberMethod.eventType;
	//创建Subscription对象
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod)
	CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
	if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
	    //一个类只能监听一个事件一次
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
	//根据优先级priority来添加Subscription对象
        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
	//将订阅者对象以及订阅的事件保存到typesBySubscriber里,以便后续取消订阅
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber)
	if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
	//区别sticky事件,如果为sticky事件则立即分发
	if(subscriberMethod.sticky){
	  if(eventInheritance)//是否考虑监听事件的父类也作为事件去监听
	  {}
	  else{
	      Object stickyEvent = stickyEvents.get(eventType)//stickEvents为全局对象
              checkPostStickyEventToSubscription(newSubscription, stickyEvent)
	  }
	}
     }
post //发送事件
:1.PostingThreadState //本线程用于保存事件队列信息
 final static class PostingThreadState {
    final List<Object> eventQueue = new ArrayList<Object>();
    boolean isPosting;
    boolean isMainThread;
    Subscription subscription;
    Object event;
    boolean canceled;
  }

:2.public void post(Object event) //主循环

{
PostingThreadState postingState = currentPostingThreadState.get()//ThreadLocal变量
List<Object> eventQueue = postingState.eventQueue 
eventQueue.add(event)
if (!postingState.isPosting) {
      postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
      postingState.isPosting = true;
      if (postingState.canceled) {
        throw new EventBusException("Internal error. Abort state was not reset");
      }
      try {
        while (!eventQueue.isEmpty()) {
            postSingleEvent(eventQueue.remove(0), postingState)//发送事件
        }
      } finally {
        postingState.isPosting = false;
        postingState.isMainThread = false;
      }
   } 

 }

:3.分发单个事件

 private void postSingleEvent(Object event, PostingThreadState postingState)
 {
 Class<?> eventClass = event.getClass()
 boolean subscriptionFound = false
 if(eventInheritance)
 {
    List<Class<?>> eventTypes = lookupAllEventTypes(eventClass)//将事件类和其父类都加入链表
    int countTypes = eventTypes.size()
    for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
        }
 }

 }

D).反射调用方法

 private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass)
 {
CopyOnWriteArrayList<Subscription> subscriptions
synchronized(this){
  subscriptions=subscriptionsByEventType.get(eventClass)
}
   if (subscriptions != null && !subscriptions.isEmpty()) {
  for(Subscription subscription:subscriptions)
  {  
     postingState.event=evnet
     postingState.subscription=subscription
     postToSubscription(subscription,event,postingState.isMainThread)
  }
  return ture
}
return false
 }

e).postToSubscription(subscription,event,isMainThread) //isMainThread代表是否post的线程为主线程

{
switch(subscription.subscriberMethod.threadMode)
{
  case ThreadMode.POSTING:
    invokeSubscriber(subscription,event) ->
    >try{
       subscription.subscriberMethod.method.invoke(subscription.subscriber,event)
     }catch(e)
     {}
    break;
  case ThreadMode.MAIN:
    if (isMainThread) {
          invokeSubscriber(subscription, event);		    //如果post线程就是主线程
        } else {
          mainThreadPoster.enqueue(subscription, event);
        }
    break;
      case BACKGROUND:
        if (isMainThread) {
            backgroundPoster.enqueue(subscription, event);
        } else {
            invokeSubscriber(subscription, event);
        }
        break;
}
 }	

f).mainThreadPoster //HandlerPoster实例

 class HandlerPoster extends Handler{
private final PendingPostQueue queue
private EventBus eventBus
…
HandlerPoster(EventBus eventBus,Looper looper,..)
{
  super(looper)
  this.eventBus=eventBus
}

void enqueue(Subscription subscription,Object event)
{
  PendingPost pendingPost=PendingPost.obtainPendingPost(subscription,event)
  synchronized(this)
  {
    queue.enqueue(pendingPost)
    if(!handlerActive)
    {
      handlerActive=true
      sendMessage(obtainMessage())
    }
  }
}

@Override
public void handleMessage(Message msg)
{
  PendingPost pendingPost = queue.poll()
  if (pendingPost == null) {	//此时没有消息
        synchronized (this) {
           // Check again, this time in synchronized
           pendingPost = queue.poll();
           if (pendingPost == null) {
                 handlerActive = false;
                 return;
           }
        }
      }
   eventBus.invokeSubscriber(pendingPost)
}

 }

g).BackgroundPoster //如果派发线程不是主线程则直接invokeSubscriber,否则调用线程池execute

     final class BackgroundPoster implements Runnable{

     }
>>sticky事件
  public void postSticky(Object event) {
    synchronized (stickyEvents) {
        stickyEvents.put(event.getClass(), event);
    }
    // Should be posted after it is putted, in case the subscriber wants to remove immediately
    post(event)
  }

>>executorService = Executors.newCachedThreadPool()

>>eventTypesCache		//Map, List>> 
  a).
String a=“ abc”;String b=“ abc”; 创建了几个对象 //栈存放引用变量 堆存在new出来的对象,并且堆划分出一部分作为常量池

当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加
b)Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象
c)使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象
d)使用包含变量的表达式来创建String对象,会在堆栈创建新的

java的单例创建
a)懒汉式 //线程不安全,指令重排
>>public class Singleton {
    private static Singleton instance;
    private Singleton (){}

    public static Singleton getInstance() {
     if (instance == null) {
         instance = new Singleton();
     }
     return instance
    }
  }

b)饿汉式

>>public static synchronized Singleton getInstance() //效率浪费,单例对象只有在创建阶段才需要同步
  {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
  }

c)双重检测锁 //效率提高,双重指的是2次检查instance是否为null

>>public class SafeDoubleCheckedLocking {
    private volatile static Instance instance;

    public static Instance getInstance() {
        if (instance == null) {
           synchronized (SafeDoubleCheckedLocking.class) {
             if (instance == null)
               instance = new Instance();//此句会出现问题,因为构造函数存在多次赋值,而第1层检测是允许重入的,
						 //所以其它线程可能会去引用一个未初始化完成的对象,造成系统崩溃
						//加入volatile后保证在多线程环境下对变量的写 *** 作优先于读 *** 作
            }
        }
        return instance;
    }
  }

163.Android进程优先级
a)Foreground processes 前台进程
进程中包含处于前台的正与用户交互的activity;
进程中包含与前台activity绑定的service;
进程中包含调用了startForeground()方法的service;
进程中包含正在执行onCreate(), onStartCommand(), 或onDestroy()方法的service;
进程中包含正在执行onReceive()方法的BroadcastReceiver.
b)Visiable processes 可视进程

进程中包含未处于前台但仍然可见的activity(调用了activity的onPause()方法, 但没有调用onStop()方法)。 典型的情况是:运行>>activity时d出对话框(类似对话框,将activity遮挡), 此时的activity虽然不是前台activity, 但其仍然可见。
进程中包含与可见activity绑定的service.可视进程不会被系统杀死, 除非为了保证前台进程的运行而不得已为之.
c)Service processes 服务进程
正在运行的Service(不在onCreate(),onStartCommand(),onDestroy()状态中)
d)background processes 后台进程
如:不可见状态的activity

164.ThreadLocal 源码
ThreadLocalMap
:1.由Thread维护
>ThreadLocal.ThreadLocalMap threadLocals,装载因子为2/3,超过即扩容
:2.ThreadLocalMap //结构

    a).static class Entry extends WeakReference<ThreadLocal<?>> {
	
	  Object value;
	  Entry(ThreadLocal<?>k,Object v)
	  {
	    super(k)
	    value=v
	  }
       }
    b).private Entry[] table	//Entry表
    c).private static final int INITIAL_CAPCITY=16		//必须为2的幂
    d).ThreadLocalMap(ThreadLocal<?> firstKey,Object firstValue)
	{
	  table=new Entry[INITIAL_CAPACITY]
	  int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1)
		//当新建ThreadLocal实例时会生成threadLocalHashCode,主要针对ThreadLocal的开地址解决冲突策略
          // 初始化该节点
          table[i] = new Entry(firstKey, firstValue);
	}
       
    e).线性探查
      >寻找下个索引
       private static int nextIndex(int i ,int len)
       {
	  return i+1<len?i+1:0
       }
      >寻找上个索引
       private static int prevIndex(int i ,int len)
       {
	 return i-1>=0?i-1:len-1
       } 
   g).获取元素
     > getEntry(ThreadLocal<?> key)
       {
         int i=key.threadLocalHashCode & table.length-1
         Entry e=table[i]
         if(e!=null&&e.get()==key)
	   return e
         while(e!=null)
         {
	   ThreadLocal<?>k = e.get()
	   if(k==key)
	     return e
	   if(k==null)	//弱引用被垃圾回收
	     expungeStaleEntry(i)		//清理staleEntry
	   else
	     i=nextIndex(i,len)
	   e=tab[i]
         }
       }
    > expungeStaleEntry(int slot)		//清理槽
      {
	Entry[] tab=table
	int len=tab.length
	tab[slot].value=null
	tab[slot]=null
	//遇到空的entry即停止
	for(int i=nextIndex(slot,len);(e=tab[i])!=null;i=nextIndex(i,len))
	{
	  ThreadLocal<?> k=e.get()
	  if(k==null)
	  {
	     e.value=null
	     tab[i]=null
	  }
	  else{
	    //get the hash of this new slot
	    int h= k.threadLocalHashCode()&(len-1)
	    if(h!=i)//rehash,鉴于该hash有可能是基于线性探查才决定的位置
            {
	      tab[i]=null
	      while(tab[h]!=null){
		h=nextIndex(h,len)
	      }
	      tab[h]=e
	    }
	  }
	
	}
      }
    h).设置元素
     > private void set(ThreadLocal<?> key,Object value)
       {
	 Entry[] tab=table
	 int len=tab.length
 	 int i= key.threadLocalHashCode & (len-1)
	 for(Entry e=tab[i]; e!=null ;e=tab[i=nextIndex(i,len)])
	 {
	   ThreadLocal<?> k=e.get()
	   if(k==key)
	     e.value=value
	     return
	   if(k==null)//该entry的引用已被GC回收
	     replaceStaleEntry(key, value ,i)
	     return
	 }
       }
     > 取代旧有的entry
       private void replaceStaleEntry(ThreadLocal<?> key, Object value,
                               int staleSlot) {
	 Entry[] tab=table
	 int len=tab.length
	 
	 for(int i=nextIndex(staleSlot,len);(e=tab[i])!=null;i=nextIndex(i,len))
	 {
	   ThreadLocal<?> k= e.get()
	   if(k==key)
	   {
	     e.value=value
	     //交换空槽和匹配的槽
	     tab[i]=tab[staleSlot]
	     tab[staleSlot]=e
           }
	 }

       }
 

>>ThreadLocal
  a).ThreadLocal::ThreadLocal()
  b).public T get()
     {
	Thread t=Thread.currentThread()
	ThreadLocalMap map=t.getMap(t)
	if(map!=null)
	{
	  ThreadLocalMap.Entry e=map.getEntry(this)
	  if(e!=null)
	  {
	    T result=(T)e.value
	    return result
	  }
	}
	return setInitialValue()
     }
  c).private Entry getEntry(ThreadLocal<?> key)
     {
	int i = key.threadLocalHashCode & (table.length - 1)
	Entry e=table[i]
	if (e != null && e.get() == key)
           return e
	else
	    return getEntryAfterMiss(key, i, e)
     }
  d).private Entry getEntryAfterMiss(ThreadLocal<?> key,int i,Entry e
  c).ThreadLocal::set(T)
  d).ThreadLocal::remove()
>>set					//
b).ThreadLocal.set()  => Thread t= Thread.currentThread();  ThreadLocalMap map=getMap(t);
c).ThreadLocal初始化时,会自动调用nextHashCode生成,以便随后根据hashCode进行数组元素的索引
d).如果当前thread的threadLocalMap不为空 => map.set(this,value)
   如果为空 => createMap
   >>t.threadLocals= new ThreadLocalMap(this,firstValue);
>>//实例
  ThreadLocal<String> name=new ThreadLocal<>();  
  name.set(“dancing”)

165.自定义View对象

自定义View的属性
:1.res/values/styles.xml
  >  <resources>
       <!--name为声明的"属性集合"名,可以随便取,但是最好是设置为跟我们的View一样的名称-->
    	<declare-styleable name="MyView">
          <!--声明我们的属性,名称为default_size,取值类型为尺寸类型(dp,px等)-->
          <attr name="default_size" format="dimension" />
       </declare-styleable>
     </resources>

在View的构造函数中获取自定义属性
:1.public CustomTitleView(Context context, AttributeSet attrs, int defStyle)

   {  
        super(context, attrs, defStyle);  
        /** 
         * 获得我们所定义的自定义样式属性 
         */  
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0);  
        int n = a.getIndexCount();  
        for (int i = 0; i < n; i++)  
        {  
            int attr = a.getIndex(i);  
            switch (attr)  
            {  
            case R.styleable.CustomTitleView_titleText:  
                mTitleText = a.getString(attr);  
                break;  
            case R.styleable.CustomTitleView_titleTextColor:  
                // 默认颜色设置为黑色  
                mTitleTextColor = a.getColor(attr, Color.BLACK);  
                break;  
            case R.styleable.CustomTitleView_titleTextSize:  
                // 默认设置为16sp,TypeValue也可以把sp转化为px  
                mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(  
                        TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));  
                break;  
  
            }  
  
        }  
        a.recycle();  
  
        /** 
         * 获得绘制文本的宽和高 
         */  
        mPaint = new Paint();  
        mPaint.setTextSize(mTitleTextSize);  
        // mPaint.setColor(mTitleTextColor);  
        mBound = new Rect();  
        mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);  
  
    } 

c).重写onMeasure //非必需

>>@Override
  protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec)
  {
    super.onMeasure(widthMeasureSpec,heightMeasureSpec);  
    //当自定义view采用wrap_content匹配时需要重写     a).setMeasuredDimension(width,height)
  }

d).重写onDraw

>>@Override
  protected void onDraw(Canvas canvas)
  {
    mPaint.setColor(Color.YELLOW);  
    canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); 
  }

Android @Override //重写
a).重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载
b).重写方法的访问修饰符一定要大于被重写方法的访问修饰符 public>protected>default>private
c).重写的方法的返回值必须和被重写的方法的返回一致
d).重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类
e).被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写

Android Semaphore机制

>>final Semaphore semaphore=new Semaphore(1)//资源数量为1
  semaphore.acquire()	//相当于P *** 作
  semaphore.release()	//相当于V *** 作
>>例子
  final Semaphore sema = new Semaphore(3);
  for (int index = 1; index < 10; index++) {
     new Thread(new Runnable(){
	@Override 
	public void run (){
	  sema.acquire()
	  //todo...
	  sema.release()
  	}

     })
  } 

169.Android Lock同步
ReentrantLock
:1.比synchronized更加适用于描述多个线程互相获取资源的场景,对象级别声明为static有效与否未知
unlock //相当于V
lock //相当于P
b).ReadWriteLock //读写锁
private ReentrantReadWriteLock rw1=new ReentrantReadWriteLock()
rw1.readLock().lock() //unlock释放
rw1.writeLock().lock() //unlock释放
实例
:1.ReentrantLock

    > class Outputter {
	private Lock lock = new ReentrantLock(); // 定义锁对象
 
	public void output(String text) throws InterruptedException {
		lock.lock(); // 得到锁
		try {
	          for (int i = 0; i < text.length(); i++) {
		    System.out.println(text.charAt(i));
		    Thread.sleep(1000);
		  }
		} finally {
		  lock.unlock(); // 释放锁
		}
	}
      }
  :2.ReadWriteLock//读写锁
    >class Data {
	private int data;
	private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
 
	public void set(int data) throws Exception {
		readWriteLock.writeLock().lock(); // 获取写锁
		try {
		  Thread.sleep(50); // 模拟耗时 *** 作
		  this.data = data;
		} finally {
	          readWriteLock.writeLock().unlock(); // 释放写锁
		}
	}
	public void get() throws Exception {
	  readWriteLock.readLock().lock(); // 获取读锁
	  try {
	    Thread.sleep(50); // 模拟耗时 *** 作
	  } finally {
	    readWriteLock.readLock().unlock(); // 释放读锁
	  }
	}
     }

170.ThreadPoolExecutor 线程池
a)newFixedThreadPool //返回一个固定线程数量的线程池

>>ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    for (int i = 1; i <= 10; i++) {
        final int index = i;
        fixedThreadPool.execute(new Runnable() {
             @Override
             public void run() {
                 String threadName = Thread.currentThread().getName();
                 Log.v("zxy", "线程:"+threadName+",正在执行第" + index + "个任务");
                 try {
                        Thread.sleep(2000);
                 } catch (InterruptedException e) {
                        e.printStackTrace();
                 }
             }
         });
     }

b)newSingleThreadExecutor //该池只跑一个线程,对所有耗时任务进行FIFO排队
c)newScheduledThreadPool //创建一个可以定时或者周期性执行任务的线程池

>> //延迟1秒后,每隔2秒执行一次该任务
   scheduledThreadPool.schedule(new Runnable() {
      @Override
      public void run() {

      }
   }, 2, TimeUnit.SECONDS);

d)自定义ThreadPoolExecutor //可以根据优先级进行排队

>>public abstract class PriorityRunnable implements Runnable, Comparable<PriorityRunnable> {
    private int priority;

    public PriorityRunnable(int priority) {
        if (priority < 0)
            throw new IllegalArgumentException();
        this.priority = priority;
    }

    @Override
    public int compareTo(PriorityRunnable another) {
        int my = this.getPriority();
        int other = another.getPriority();
        return my < other ? 1 : my > other ? -1 : 0;
    }

    @Override
    public void run() {
        doSth();
    }

    public abstract void doSth();

    public int getPriority() {
        return priority;
    }
  }
>> ExecutorService priorityThreadPool = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.SECONDS, new   PriorityBlockingQueue<Runnable>());

        for (int i = 1; i <= 10; i++) {
            final int priority = i;
            priorityThreadPool.execute(new PriorityRunnable(priority) {
                @Override
                public void doSth() {
                    String threadName = Thread.currentThread().getName();
                    Log.v("zxy", "线程:" + threadName + ",正在执行优先级为:" + priority + "的任务");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

171.Android下载图片通过bitmap设置ImageView

>>public class ActivityMain extends Activity {  

  String imageUrl = "http://i.pbase.com/o6/92/229792/1/80199697.uAs58yHk.50pxCross_of_the_Knights_Templar_svg.png";  
  Bitmap bmImg;  
  ImageView imView;  
    
  Button button1;  
    
  @Override  
  public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.main);  
     imView = (ImageView) findViewById(R.id.imview);  
     imView.setImageBitmap(returnBitMap(imageUrl));  
  }
 
  
  public Bitmap returnBitMap(String url) {  
    URL myFileUrl = null;  
    Bitmap bitmap = null;  
    try {  
      myFileUrl = new URL(url);  
    } catch (MalformedURLException e) {  
    e.printStackTrace();  
    }  
    try {  
      HttpURLConnection conn = (HttpURLConnection) myFileUrl  
       .openConnection();  
      conn.setDoInput(true);  
      conn.connect();  
      InputStream is = conn.getInputStream();  
      bitmap = BitmapFactory.decodeStream(is);  	//容易OOM
      is.close();  
    } catch (IOException e) {  
      e.printStackTrace();  
    }  
    return bitmap;  
  }    
}

ImageView
ScaleType
:1.FIT_CENTER 默认,图片等比例缩放到宽或者高能够填充控件大小
:2.FIT_START,FIT_END 等比例缩放,并放置在控件的左边或者上方
:3.FIT_XY 完全填充控件大小,但不是等比例
:4.CENTER -> 图片大小为原始大小,如果大于ImageView组件,则截取中间部分,若小于则将图片居中显示
:5.CENTER_CROP ->图片等比例缩放,使图像的短边填满,截取中间部分

onSaveInstanceState //保存app数据,当系统因内存不足时而销毁app,会得到调用

>>public void onSaveInstanceState(Bundle outState)
  {
    outState.put(“index”,3);
  }
>>public void onCreate(Bundle saveInstanceState){
    int curIndex=saveInstanceState.get(“index”,0);//默认值是0
  }

177.ViewPager&PagerAdapter&TabFragmentPagerAdapter
实例
:1.fragments=mutableListOf(Fragment1(),Fragment2())
val adapter= TagFragmentPagerAdapter(getSupportFragmentManager(),fragments)
view_pager.adapter=adapter
:2.view_pager.addOnPageChangeListener
:3.view_pager.setCurrentItem //设置默认选中的item

Fragment在横竖屏切换时的数据保存
onCreate-> setRetainInstance(true)
当设置retain后,Fragment的生命周期不再经过onCreate、onDestroy

DialogFragment //采用子类继承的方式进行使用,相比AlertDialog由FragmentManager负责自动重建

>>public class DatePickerFragment extends DialogFragment{
    a).public Dialog onCreateDialog(Bundle saveInstanceState)  
       {
	 Date date = (Date) getArguments().getSerializable(ARG_DATE);
         Calendar calendar = Calendar.getInstance();
         calendar.setTime(date);
         int year = calendar.get(Calendar.YEAR);
         int month = calendar.get(Calendar.MONTH);
         int day = calendar.get(Calendar.DAY_OF_MONTH);
         return new DatePickerDialog(context, this,year,month,day)
       }   
  }

180.SQLiteDatabase
helper //通过helper来获取database实例

  a).public class DbOpenHelper extends SQLiteOpenHelper {

      private static final int VERSION=1;
      private static final String DATABASE_NAME="crimeBase.db";

      public DbOpenHelper(Context context) {
        super(context, DATABASE_NAME, null  , VERSION);
      }

      @Override
      public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table crimes (" +
                "_id integer primary key autoincrement ," +
                "title varchar(10) ," +
                "date datetime," +
                "solved boolean" +
                ")");
      }

      @Override
      public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

      }
     }

getWritableDatabase、getReadableDatabase
a).getWritableDatabase //以读写方式打开数据库,一旦数据库的磁盘空间满了就只能读,因此会报错
b).getReadableDatabase //首先以读写方式打开,失败后转换为只读方式打开
c).锁 //SqliteOpenHelper,针对数据库进行了加锁,故遵循读写-锁原则,可多个读只有一个写
CursorWrapper //1).自动针对Cursor实现了getItem、getCount 2).通过convertView去调用createView|bindView
a).bindView(view,context,cursor)
b).newView(context,cursor,parent)
DateTime的数据存储 //cursor不支持直接Date类型的数据存取
String dateStr =DateFormat.getDateTimeInstance().format(date) //getDateTimeInstance获取针对DateTime的转换器
cv.put(“date”,dateStr) //SQLite中设置date为datetime

IntentFilter的匹配规则
>><intent-filter>			//进行匹配
  :1.<action android:name=“…”/>		//目标intent-filter可以有多个action,intent只要符合其中一个
  :2.<category android:name=“…”/>	//addCategory,intent可以没有category,但是intent的category都必须在目标中存在
  :3.<data android:scheme=“string”
    android:host=“string”
    android:port=“string”
    android:path=“string”
    android:mimeType=“string”/>       //intent.setDataAndType(Uri.parse(…),”image/png”)
>>预查询能匹配的Activity         	      //返回ResolveInfo
  a)getPackageManager().queryIntentActivities(intent,0)//0代表MATCH_DEFAULT_ONLY
  b)getPackageManager().resolveActivity(intent,0)      //

183.Android多进程

Messenger
:1.服务器端所持有的Messenger
 >private Messenger serviceMessenger = new Messenger(new ServiceHandler());//初始化
  private class ServiceHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
       switch(msg.what){
	case 0x01:

	break;
   }
    }
  }
  @Override
  public IBinder onBind(Intent intent) {
    Log.i("DemoLog", "MyServivce -> onBind");
    //获取Service自身Messenger所对应的IBinder,并将其发送共享给所有客户端
    return serviceMessenger.getBinder();
  }

:2.设置在service在别的进程

 <service android:name=".MessengerService" android:process=":remote" />

:3.客户端

>>private Messenger mService;
  private ServiceConnection mConnection=new ServiceConnection(){
 public void onServiceConnected(ComponentName xx,IBinder service)
 {
   mService=new Messenger(service);
   Message msg=Message.obtain(null,what);
   Bundle data=new Bundle();
   data.put(“”,”xx”);
   msg.setData(data);
	   try{
	mService.send(data);
   }catch(RemoteException e)
   {
	e.printStackTrace();
   }
 }
  }
  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
 bindService(intent,mConnection,Context.BIND_AUTO_SERVICE);
  }

:4.服务器回应客户端

>客户端设置replyTo
 Message msg=Message.obtain()
 msg.replyTo=new Messenger(new Handler(){new Runnable(){}})
 serverMessenger.send(msg)
AIDL
a)服务器 -> 创建Service来监听客户端的连接请求,创建AIDL文件,将暴露给客户端的接口在该文件中声明,最后Service实现
b)客户端 -> 绑定Service,将返回的Binder转换为AIDL类型,调用AIDL方法
c)AIDL接口的创建 //引入一个接口和声明2个方法
    >>import com.ryg.chapter_2.aidl.Book;
      interface IBookManager{
 	 List<Book> getBookList();
  	 void addBook(in Book book);
      }
    >>AIDL支持的数据类型 -> 基本数据类型、StringCharSequenceArrayListHashMapParcelable、AIDL
    >>AIDL不支持声明静态常量 
  d)针对AIDL服务端Service的创建
    public class BookManagerService extends Service{
	private CopyOnWriteArrayList<Book> mBookList=new CopyOnWriteArrayList<Book>();
 	private Binder mBinder=new IBookManager.Stub(){
		@Override
		public List<Book> getBookList() throws RemoteException{
			return mBookList;
		}
		@Override
		public void addBook(Book book)throws RemoteException{
			mBookList.add(book);
		}
       }

	@Override
	public IBinder onBind(Intent intent)
	{
		return mBinder;
	}
    }
  e)针对AIDL客户端
    private ServiceConnection mConnection=new ServiceConnection(){
	public void onServiceConnected(ComponentName className,IBinder service)
        {
	   IBookManager manager=IBookManager.Stub.asInterface(service);
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
	bindService(intent,mConnection,Context.BIND_AUTO_CREATE);	//在onDestroy中调用unbindService
    }
>>RemoteCallbackList //专门用于维护跨进程的监听队列
  a)final int N=mListenerList.beginBroadcast()
    for(int i=0;i<N;i++)
    {
	IOnNewBookArrivedListener l=mListenerList.getBroadcastItem(i)
        l.onNewBookArrived(Book);
    }
    mListenerList.finishBroadcast()
>>权限验证
  a)自定义权限	-> <permission android:name=“com.ryg.chapter_2.permission.ACCESS_BOOK_SERVICE” 
 			android:protectionLevel=“normal”/>
  b)检查申请应用是否有对应权限
    ->public IBinder onBind(Intent intent)
      {
	 int check=checkCallingOrSelfPermission(“com.ryg.chapter_2.permission.ACCESS_BOOK_SERVICE”)
	 if(check==PackageManager.PERMISSION_DENIED)
           return null
 	 else
	    return mBinder;
      }
>>ContentProvider	//专门用于不同应用间进行数据共享
  

186.Android Scroller

>>Scroller mScroller=new Scroller(context)	//创建实例
>>mScroller.startScroll();			//开始滑动,并需要调用invalidate刷新界面
  invalidate();
>>@Override					//滑动开始后的回调
  public void computeScroll()
  {
    if(mScroller.computeScrollOffset)
      scrollTo(mScroller.getCurX(),mScroller.getCurY())
    invalidate();
  }

188.Sqlite 连接 *** 作

>>cross join 	//交叉连接,如果不进行条件筛选,则结果为笛卡尔积
  a)select e.no,e.name from emp e cross join dept d 
>>inner join   //内连接,table1 (inner) join table2 on …
>>natural join //自然连接,自动检测相同属性是否值相等
>>outer join	//外连接,table1 left outer join table2 on ….

190.Spinner

>>setOnItemSelectedListener		//设置监听
>>setAdapter				//设置数据源

191.RelativeLayout 源代码

sortChildren()
a).DependGraph,形成依赖图和依赖子图
b).findRoots返回当前没有依赖的view结点集合roots
c).通过roots集合采用bfs遍历所有view结点,具体是访问某个view时去除该view的相邻边,sorted[index++]=viewgetLayoutDirection() //RTL,主要针对阿拉伯地区,默认LayoutDirection.LTR
a).LayoutDirection.LTR,容器内容左对齐
b).LayoutDirection.RTL, 容器内容右对齐水平方向和垂直方向的尺寸测量

192.Message //static Message sPool,指向队列前头的可用Message对象

obtain
  public static Message obtain(){
    synchronized (sPoolSync) {
      if (sPool != null) {
         Message m = sPool
         sPool = m.next;
         m.next = null;
         m.flags = 0; // clear in-use flag
         sPoolSize--;
         return m;
      }
    }
    return new Message()
  }
recycleUnchecked
  synchronized (sPoolSync) {
    if (sPoolSize < MAX_POOL_SIZE) {
       next = sPool	
       sPool = this
       sPoolSize++
    }
  }

193.ArrayDeque 源代码阅读

成员 //transient标识的在通过ObjectOutputStream进行持久化时不进行该成员处理
a).private transient E[] elements
b).private transient int head
c).private transient int tail
d).private static final int MIN_INITIAL_CAPACITY = 8初始化时的分配
a).allocateElements(int numElements) //后续 *** 作保证capacity为2的n次方
b).elements = new Object[initialCapacity]doubleCapacity //扩容,当tail+1==head时,进行扩容
a).int p = head;
int n = elements.length;
int r = n - p;
int n = elements.length
int newCapacity = n << 1
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);插入
a).addFirst //头部插入数据
elements[head = (head - 1) & (elements.length - 1)] = e;//elements.length-1 equals 1111…111
if (head == tail)
doubleCapacity();
b).addLast //尾部插入数据
elements[tail] = e;
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();遍历
a).成员 //cursor,fence,lastRet
b).public E next()
   >if(cursor==fence) throw new Exception
    >lastRet=cursor
    >cursor = (cursor + 1) & (elements.length - 1)
    >return result

c).public void remove()
delete(lastRet) //调用私有方法delete删除lastRet对应下标
>final int front = (i - h) & mask;
final int back = (t - i) & mask;
if(front

194.RecyclerView

ViewHolder复用
:1.Recycler
 >mAttachedScrap 		//仍然依赖于RecyclerView,但已经被标记移除的vh(例如已经滑出可视范,但还没被移除)
 >mChangedScrap  		//存储notifyXXX时需要改变的vh
 >mCachedViews		//mAttachedScrap不再依赖RecyclerView的vh

:2.getViewForPosition //1).从mChangedScrap 2).mAttachedScrap 3).mCachedViews
:3.recycleView
>recycleViewHolderInternal(holder)-> mCachedViews.add -> mRecyclerPool

RecyclerView::onMeasure //测量
a).dispatchLayoutStep2 -> mLayout.onLayoutChildren

b).dispatchLayoutStep3 //执行动画

LayoutManager
a).onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)

 {
//1)确认锚点信息
if(mAnchorInfo.mLayoutFromEnd)
{
}else{
  firstLayoutDirection=LayoutState.ITEM_DIRECTION_TAIL//向底部填充
}
//2)填充
    fill(recycler, mLayoutState,RecyclerVie.State::state, false)->
{
   while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
     layoutChunk(recycler, state, layoutState, layoutChunkResult)>
      > addView
   }
}
 }
RecycledViewPool //存放ViewHolder
a).public ViewHolder getRecycledView(int viewType)
 {
 final ArrayList<ViewHolder> scrapHeap = mScrap.get(viewType);
    if (scrapHeap != null && !scrapHeap.isEmpty()) {
        final int index = scrapHeap.size() - 1;
        final ViewHolder scrap = scrapHeap.get(index);
        scrapHeap.remove(index);
        return scrap;
    }
    return null;
 }

b).

  public void putRecycledView(ViewHolder scrap) {
        final int viewType = scrap.getItemViewType();
        final ArrayList scrapHeap = getScrapHeapForType(viewType);
        if (mMaxScrap.get(viewType) <= scrapHeap.size()) {
            return;
        }
        if (DEBUG && scrapHeap.contains(scrap)) {
            throw new IllegalArgumentException("this scrap item already exists");
        }
        scrap.resetInternal();
        scrapHeap.add(scrap);
    }

195.LinearLayoutManager //RecyclerView的布局管理器

onLayoutChildren
:1.更新layoutState的状态,并等待getItemCount()的刷新
 mAnchorInfo.mLayoutFromStart=true	
  updateLayoutStateToFillEnd -> 
mLayoutSTate.mAvailable = mOrientationHelper.getEndAfterPadding()-offset//一开始就是很大的

:2.填充子view

 fill(recycler , mLayoutState,state,false)
  ... int start=layoutState.mAvailable
      int remainSpace=layoutState.mAvailable//主要用于保存滑动的偏移距离
      while(remainSpace>0&&layoutState.hasMore(state))//判断是否有剩余空间&&mItemCount>position
	 layoutChunk(recycler, state, layoutState, layoutChunkResult)
	    ... View view=layoutState.next(recycler)
		if(mScrapList!=null)
		  return nextViewFromScrapList()
		View view=recycler.getViewForPosition(mCurrentPosition)
		 ... holder=getScrapOrHiddenOrCachedHolderForPosition(position)
		    if(holder==null)
			holder=getRecycledViewPool().getRecycledView(type)
		    if(holder==null&&mAdapter!=null)
			holder=mAdapter.createViewHolder()  //!!,调用Recycler.Adapter
		    ...
		    mAdapter.onBindViewHolder()          //!!,调用
                    addView(view)		//加入子view
		measureChildWithMargins(view)	//view.measure(..,..)
		result.mConsumed=view.height
		if(mOrientation==VERTICAL)
		  

196.1 GridLayoutManager

>>mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup(){
    override public getSpanSize(position:int):int{
      val type=mAdapter.getItemViewType(position)
      switch(type)
      {
	...
      }
    }
  })

196.2.RecyclerView 使用

>>封装adapter
  :1.public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private List<String> list;
    
    public MyAdapter(List<String> list) {
        this.list = list;
    }
 
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view =  LayoutInflater.from(parent.getContext()).inflate(R.layout.item_base_use, parent, false);
        MyAdapter.ViewHolder viewHolder = new MyAdapter.ViewHolder(view);
        return viewHolder;
    }
 
    @Override
    public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {
        holder.mText.setText(list.get(position));
    }
 
    @Override
    public int getItemCount() {
        return list.size();
    }
 
    class ViewHolder extends RecyclerView.ViewHolder {
        TextView mText;
        ViewHolder(View itemView) {
            super(itemView);
            mText = itemView.findViewById(R.id.item_tx);
        }
    }
  }

196.1 Binder

BpBinder
:1.val in:Parcel ,val out:Parcel
>>MediaPlayerService	//class MediaPlayerService : public BnMediaPlayerService,媒体服务  
  :1.调用了BpServiceManager::addService(String16& name,const sp<IBinder> &service)
    ...	Parcel data, reply;
	data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
	data.writeString16(name)
	data.writeStrongBinder(service)
	remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply)//remote是BpBinder
  :2.BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
   ...  status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags)
Service Manager
  :1.打开Binder设备文件,分配内存 -> 告诉Binder驱动自己成为Binder的上下文管理者 -> binder_loop(bs,svcmgr_handler)
   ...  struct binder_state *bs
	void *svcmgr = BINDER_SERVICE_MANAGER	//句柄为0
	bs = binder_open(128*1024)
	if (binder_become_context_manager(bs)) {
	}
        svcmgr_handle = svcmgr
	binder_loop(bs, svcmgr_handler)
  :2. fd是文件描述符,mapped是把设备文件/dev/binder映射到进程空间的起始地址;mapsize是上述内存映射空间的大小
   .... struct binder_state
        {
    	  int fd;
     	  void *mapped;
    	  unsigned mapsize;
        }
	

197.ActivityThread //Android应用的主线程

成员
:1.mActivities
:2.mServices
:3.mApplication
:4.mProviderMap流程
:1.main
>Looper.prepareMainLooper()
 ActivityThread thread = new ActivityThread()
 if (sMainThreadHandler == null) {
   sMainThreadHandler =thread.getHandler();//mH
 }
 ...
 Looper.loop()
ActivityInfo //封装了所有在AndroidManifest.xml解析出的关于Activity、receiver的信息ActivityClientRecord
a).intent

mAction=“android.intent.action.MAIN”
mComponent={mClass=“com.pill.interview.annotation.Home”}
b).activityInfo
taskAffinity=“com.pill.interview”
processName=“com.pill.interview”

>>public static void main(String[] args)
  {
    Looper.prepareMainLooper()		//1.新建looper,并放置于ThreadLocal中 2.赋值在Looper的sMainLooper
    ActivityThread thread=new ActivityThread()//1.初始化成员变量mH,mH=new H()2.初始化ApplicationThread
    …
    sMainThreadHandler = thread.getHandler();	//将mH赋值给sMainThreadHandler
    Looper.loop()
  }
>>private class H extends Handler{
    public void handleMessage(Message msg)//包含: 对Activity、Service、Application的 *** 作
    {
	switch(msg.what)
	{
	  a).case LAUNCH_ACTIVITY:
	     handleLaunchActivity(r,Intent customIntent(null), "LAUNCH_ACTIVITY") ->
	     >performLaunchActivity(r,customIntent)//通过Instrumentation反射得到Activity对象,新建Application
		>检查r.packageInfo	//无效的话通过r.applicationInfo去创建
 		>检查r.intent.mComponent//无效的话通过r.intent.resolveActivity去创建
		> activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
			//(Activity)cl.loadClass(className).newInstance() -> 反射创建Activity
		>Application app = r.packageInfo.makeApplication(false, mInstrumentation)
  		>Context appContext= createBaseContextForActivity(r, activity)//创建Context
		>CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager())//设置标题
		>activity.attach(appContext…)
		>mInstrumentation.callActivityOnCreate(activity, r.state);
			//进入Activity的onCreate回调,设置ActionBar和恢复Fragments的状态
		>activity.performStart()	//调用Activity的onStart()回调
		>mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state)
			//进入Activity的onRestoreInstanceState回调
		>r.paused = true 		//代表当前Activity的状态是pause
	  b).case RESUME_ACTIVITY:	//当进入Resume后
	     handleResumeActivity(IBinder token,boolean clearHide,boolean isForward)->
	     >ActivityClientRecord r = mActivities.get(token)
			//mActivities -> ArrayMap
	     >r = performResumeActivity(token, clearHide, reason)	
		>if(r.pendingIntents != null) {
                  deliverNewIntents(r, r.pendingIntents)
			//mInstrumentation.callActivityOnNewIntent(r.activity, intent),进入onNewIntent回调
                  r.pendingIntents = null;
                }
		>r.activity.performResume()//进入onResume()
	  c).case PAUSE_ACTIVITY:
	     handlePauseActivity(IBinder token,boolean finished …) ->
	     >performPauseActivity(ActivityClientRecord r,boolean finished,..)
		> 检查r.paused	//1)r.paused==true,检查r.activity.mFinished是否为true,否则报异常
		> if (r.paused &&r.activity.mFinished) {return null}
		> if(r.paused){RuntimeExceptio e}
		> 检查finished	//if(finished) -> r.activity.mFinished=true
		> if (!r.activity.mFinished && saveState) {	//如果需要saveState
	           mInstrumentation.callActivityOnSaveInstanceState(r.activity,r.state)
			//进入Activity的onSaveInstanceState回调
        	  }
		> performPauseActivityIfNeeded(r,reason)	
		  if(r.paused){return ;}
		  mInstrumentation.callActivityOnPause(r.activity);	//进入onPause回调
	  d).case STOP_ACTIVITY_SHOW:
	     handleStopActivity(IBinder token,boolean show) ->
	     >performStopActivityInner(ActivityClientRecord r,StopInfo info,show…)
		>performPauseActivityIfNeeded(r,reason)
		>if (!r.activity.mFinished && saveState) {
                  if (r.state == null) {
                    callCallActivityOnSaveInstanceState(r);	//进入Activity的onSaveInstanceState回调
                  }
                }
	  e).case DESTROY_ACTIVITY:
	     handleDestroyActivity(IBinder token,boolean finishing…) ->
	     >performDestroyActivity(token, finishing,configChanges, getNonConfigInstance)
		>performPauseActivityIfNeeded	//如果必要,使Activity进入mPaused==true的状态

	}    

    }
  }
>>private class ApplicationThread{
    a).public final void scheduleLaunchActivity
       {
	  ActivityClientRecord r = new ActivityClientRecord()sendMessage(H.LAUNCH_ACTIVITY, r)

       }
  }
  

198.CountDownLatch 线程同步
199.retrofit

>>建立retrofit对象
  :1.Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fy.iciba.com/") //http://fy.iciba.com/
                .addConverterFactory(GsonConverterFactory.create())
                .build();
  :2.动态代理
   Public<T> T create(final Class<T> service){
     return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {	
           @Override public Object invoke(Object proxy,Method method,Object[] args)	
	   {
	      if(method.getDeclaringClass()==Object.class)
	      	return method.invoke(this, args)
	   }
 	})
   }
>>建立ServiceMethod
  :1.建立CallAdapter
   >retrofit.callAdapter(returnType,annotations)

200.ClassLoader 类加载器

JVM
:1.Bootstrap ClassLoader /jre/lib,用于加载java虚拟机所需要的系统类,java.lang.*
:2.Ext ClassLoader /jre/lib/ext
:3.App ClassLoaderART
:1.BootClassLoader ->加载常用类
:2.PathClassLoader ->extends DexClassLoader,加载系统类和应用程序的类dex文件、apk等
:3.DexClassLoader ->以加载dex文件以及包含dex的apk文件或jar文件,也支持从SD卡进行加载

201.RxJava

创建Observable
  :1.create(ObservableOnSubscribe<T> source)
     {
       RxJavaPlugins.onAssembly(new ObservableCreate<T>(source)) //this.source = source
       
     }
ActionFunctionmap *** 作符

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/992070.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存