本篇内容比较快捷短小。属于快问快答形式。大家可以下载下来,每天一遍。
记住,答案只是引导,在回答完后发散自己的引导思维。去引申。
create table table2 as select * from table1
102.SQLite
try{
mSqliteDatabase.beginTransaction()
...
mSqliteDatabase.execSQL(....)
...
mSqliteDatabase.setTransactionSuccessful()
}catch(Exception e)
{
e.printStackTrace()
}finally{
mSqliteDatabase.endTransaction()
}
mSqliteDatabase.execSQL("create table temp as select ... from student")
mSqliteDatabase.execSQL("drop table if exists student")
mSqliteDatabase.execSQL("alter table temp rename to student")
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()
- 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)
{
}
}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)
{
}else{
}
}
}
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>
TelephonyManager tm =(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)
switch(tm.getCallState())
{
case TelephonyManager.CALL_STATE_RINGING:
break;
case TelephonyManager.CALL_STATE_IDLE:
break;
}
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)
}
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()
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();
}
});
InputStream is=getResources().openRawResource(R.raw.xxx)
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)
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,属于帧动画
<?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.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
.ofInt(mSkyView,"backgroundColor",mBlueSkyColor,mRedSkyColor)
.setDuration(3000)
.setEvaluator(new ArgbEvaluator())
.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>(){
@Override
public PointF evaluate(float fraction, PointF startValue,
PointF endValue)
{
Log.e(TAG, fraction * 3 + "");
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)
<?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>
- 放置在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)
<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>
<resources>
<style name="customText" parent="@style/Text">
<item name="android:textSize">20sp</item>
<item name="android:textColor">#008</item>
</style>
</resources>
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);
}
return i + params[0].intValue() + "";
}
@Override
protected void onProgressUpdate(Integer... values) {
int vlaue = values[0];
progressBar.setProgress(vlaue);
}
@Override
protected void onPreExecute() {
textView.setText("开始执行异步线程");
}
@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 mThread=new HandlerThread("xx");
mThread.start();
handler = new Handler( myHandlerThread.getLooper() ){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
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
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);
measureChildren(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();
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
> 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()
Response response=chain.proceed(request)
return response
}
源码
:1.创建OkHttpClient
> public OkHttpClient() {
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);
return url(parsed)
}
}
: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 );
}
...
}
> 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{
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线程池
>
private int maxRequests = 64;
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) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
:5.Interceptor
>BridgeInterceptor -> 添加Content-Type、Content-Length、User-Agent等协议头
>ConnectInterceptor -> ....
>CallServerInterceptor -> 实际发送网络请求
149.ButterKnife //源码阅读
初始化
:1.定义处理器
`java
public class MyProcessor extends AbstractProcessor {
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> annotataions = new LinkedHashSet<String>();
annotataions.add("com.example.MyAnnotation");
return annotataions;
}
@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
...for(Element element:env.getElementsAnnotatedWith(BindView.class)
try{
parseBindView(element, Map<TypeElement,BindingSet.Builder>builderMap,...)
....enclosingElement=(TypeElement)element.getEnclosingElement()
TypeMirror elementType = element.asType()
if (elementType.getKind() == TypeKind.TYPEVAR) {
TypeVariable typeVariable = (TypeVariable) elementType
elementType = typeVariable.getUpperBound()
}
if (!isSubtypeOfType(elementType, VIEW_TYPE) && !isInterface(elementType)) {
throw Error
}
int id = element.getAnnotation(BindView.class).value()
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)
builder.addField(resourceId, new FieldViewBinding(name, type, required))
... new FieldViewBinding(name, type, required)
... viewId=new ViewBinding.Builder(id)
viewIdMap.put(id,viewId)
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.Builder result = TypeSpec.classBuilder(bindingClassName.simpleName())
.addModifiers(PUBLIC);
if (parentBinding != null) {
result.superclass(parentBinding.bindingClassName);
} else {
result.addSuperinterface(UNBINDER);
}
if (hasTargetField()) {
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");
result.addMethod(createBindingConstructor(sdk, debuggable, useAndroidX))
... if (hasViewBindings()) {
for (ViewBinding binding : viewBindings) {
addViewBinding(constructor, binding, debuggable)
-> FieldViewBinding fieldBinding = binding.getFieldBinding()
}
}
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();
}
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;
}
}
int id = element.getAnnotation(BindView.class).value();
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 {
bindingClass = getOrCreateTargetClass(targetClassMap, enclosingElement);
}
String name = element.getSimpleName().toString();
TypeName type = TypeName.get(elementType);
FieldViewBinding binding = new FieldViewBinding(name, type, required)
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文件
>
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 = processingEnv.getFiler();
}
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement element : annotations) {
if (element.getQualifiedName().toString().equals(JPHelloWorld.class.getCanonicalName())) {
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();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
try {
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);
- bind
:1.public static Unbinder bind(Activity target){
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()
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 Heap
- Bitmap来标记引用情况
: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在之后的过程中,弹出Mark Stack的对象,并标记在Bitamap之中,并将该对象的引用也压入Mark Stack
151.ART垃圾回收
- Image Space、Zygote Space、Allocation Space、Large Object Space、Card Table
- Bitmap=Live Bitmap +Mark Bitmap
- mod_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
- 类的静态成员
-
方法区重的常量引用对象
-
采用HashMap进行实现,值为new出的Object
-
采用HashMap的put进行不重复性的保证
-
对称加密
a).当通过浏览器向服务器请求安全网页时(https://…)
b).服务器同时把证书和公钥发送过来
c).浏览器检查证书是不是由信赖机构颁发的
d).浏览器随机生成对称密钥,并采用服务器发送的公钥加密自身的公钥,同时采用公钥加密请求,一并发送至服务器
e).服务器用自己的私钥解密了发过来的密钥,并用该密钥解析加密后的请求
f).服务器用收到的密钥加密返回的数据
G).浏览器用自身的私钥解密服务器返回的加密消息
//那么中间人有没有可能解密出信息呢,关注点主要在客户端发来的信息
//从d步骤开始检测,中间人截取到了被加密的浏览器密钥,但是无法猜测对应服务器的公钥,故无法解密
// a)假设中间人清除目标服务器,首先获取了服务器的公钥,但是只有私钥才能解密被该公钥加密后的信息,故也无法解密 -
当使用内部类(包括匿名类)来创建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为静态类 -
JVM对于volatile所提供的内存屏障 //内存屏障的作用 -> 阻止屏障2侧的指令重排
a).Load Barrier //在指令前插入Load Barrier,可以让高速缓存的数据失效,强制从主存加载
b).Store Barrier //在指令后插入Store Barrier,强制写回主存
c).在每个volatile写操作前插入StoreStore屏障,在写操作后插入StoreLoad屏障
在每个volatile读操作前插入LoadLoad屏障,在读操作后插入LoadStore屏障 - 多线程工作时,线程对于特定变量采取对主存读取后拷贝到自身内存区的办法进行操作
- volatile保证该变量是通过共享内存进行同步的
-
volatile不能替代synchronized,因为不能保证原子性操作
-
成员
:1.subscriptionsByEventType:HashMap //subscription = subscriber+subscriberMethod
:2.typesBySubscriber
:3.subscriberMethodFinder
:4.METHOD_CACHE:HashMap - 流程
: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))
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()
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)
...
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)
{
....
}
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 = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
:4.获取注解以及注解的值
private void findUsingReflectionInSingleClass(FindState findState){
Method[] methods
try{
methods=findState.clazz.getDeclaredMethods()
}
catch(Throwable th){}
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();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType,
threadMode,
subscribeAnnotation.priority(),
subscribeAnnotation.sticky()));
}
}
}
}
}
- Subscription //封装注册信息
a).Object subscriber
b).SubscriberMethod subscriberMethod - SubscriberMethod
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 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);
}
}
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;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber)
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if(subscriberMethod.sticky){
if(eventInheritance)
{}
else{
Object stickyEvent = stickyEvents.get(eventType)
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()
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);
} 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) {
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);
}
post(event)
}
>>executorService = Executors.newCachedThreadPool()
>>eventTypesCache
a).
当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加
b)Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象
c)使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象
d)使用包含变量的表达式来创建String对象,会在堆栈创建新的
>>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();
}
}
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时弹出对话框(类似对话框,将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
c).private static final int INITIAL_CAPCITY=16
d).ThreadLocalMap(ThreadLocal<?> firstKey,Object firstValue)
{
table=new Entry[INITIAL_CAPACITY]
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1)
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)
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
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{
int h= k.threadLocalHashCode()&(len-1)
if(h!=i)
{
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)
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:
mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
break;
}
}
a.recycle();
mPaint = new Paint();
mPaint.setTextSize(mTitleTextSize);
mBound = new Rect();
mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);
}
c).重写onMeasure //非必需
>>@Override
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}
d).重写onDraw
>>@Override
protected void onDraw(Canvas canvas)
{
mPaint.setColor(Color.YELLOW);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
}
>>final Semaphore semaphore=new Semaphore(1)
semaphore.acquire()
semaphore.release()
>>例子
final Semaphore sema = new Semaphore(3);
for (int index = 1; index < 10; index++) {
new Thread(new Runnable(){
@Override
public void run (){
sema.acquire()
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 //创建一个可以定时或者周期性执行任务的线程池
>>
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);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
}
>>public void onSaveInstanceState(Bundle outState)
{
outState.put("index",3);
}
>>public void onCreate(Bundle saveInstanceState){
int curIndex=saveInstanceState.get("index",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
>>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
>><intent-filter>
:1.<action android:name="..."/>
:2.<category android:name="..."/>
:3.<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:mimeType="string"/>
>>预查询能匹配的Activity
a)getPackageManager().queryIntentActivities(intent,0)
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");
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支持的数据类型 -> 基本数据类型、String和CharSequence、ArrayList、HashMap、Parcelable、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);
}
>>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();
>>@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
>>natural join
>>outer join
190.Spinner
>>setOnItemSelectedListener
>>setAdapter
191.RelativeLayout 源代码
- sortChildren()
a).DependGraph,形成依赖图和依赖子图
b).findRoots返回当前没有依赖的view结点集合roots
c).通过roots集合采用bfs遍历所有view结点,具体是访问某个view时去除该view的相邻边,sorted[index++]=view - getLayoutDirection() //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;
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(frontOriginal: https://blog.csdn.net/qq_29966203/article/details/123984877
Author: 李一恩
Title: 耗时整整3个月,我梳理了200道Android面试基础(下)【面试必考,全网最全,每天一遍】
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/815910/
转载文章受原作者版权保护。转载请注明原作者出处!