Android进阶之光 读书笔记

第一章,

Android 5.6.7新特性

 


1、RecycleView的自定义分割线

public class DividerItemDecoration extends RecycleView.ItemDecoration {

}

2、自定义点击事件

3、CardView

4、运行时权限问题

Normal Permissions 不涉及用户隐私,在androidMainfest.xml中申明就好

,无需每次使用的时候都检查权限,且用户不可以取消权限;

Dangerous Permission 涉及用户隐私,需要用户授权

 

checkSelfPermission 

onRequestPermissionResult

PermissionsDispatcher


第4章 多线程编程

 

实现线程的方式

1、thread\runnable

2、再写一遍callable接口的写法

public static class MyCallable implements Callable {

     public String call() {

   ....

}

}

在main方法中

ExecutorService service = Executors.newSingleThreadPool();

Future future = service.submit(new MyCallable()) ;

try {

futurer.get();

}catch() {

}

 

注意 类变量放在方法区(静态变量,类的共有信息),成员变量放在堆内存上, 局部变量放在栈内存上

3、Volatile 和synchronized关键字的区别

Volatile是可以让多个线程感知这个值的变化,这个值放在主存当中

Synchronized则是锁主这个变量,只有拥有锁的这个线程可以访问,其他线程将被阻塞

Volatile不能保证原子性,不可以用作多线程的自增;

 

4、重入锁和条件对象

重入锁和不可以重入锁的区别

不可以重入锁是指当前线程在某个方法中已经获取到锁的时候,没有释放前,在其他方法中是没办法再次获取到锁的

重入锁指的是对某个资源可以进行重复加锁

public void count() {

    lock.lock();

    doadd();

    lock.unlock();

}

 

public void doadd() {

    lock.lock();

     //dosomething;

   lock.unlock();

}

 

在do add方法中就没办法再次获取到锁

 

条件对象是指获取到锁后,需要满足的条件,比如支付转账,获取到锁后,因为当前用户余额不满足转账的金额(条件对象),则会阻塞其他线程

所以我们会new Reentantlock().newCondition()l;获取到条件对象,当当前用户余额不满足转账的金额(条件对象)的时候,condition.await();阻塞当前线程。并且放弃锁;当执行完转账操作的时候,则condition.signalAll();唤醒其他线程;

 

5、阻塞队列

LinkedBlockQueue  先进先出,生产者往队列中放入一个数据后,边返回

6、线程池

ThreadPoolExecutor executor = new ThreadPoolExecutor(

//1. 第一个参数是核心的线程数目   , CORE_POOL_SIZE,

//2.第二个参数 是线程池的最大数目, MAX_POOL_SIZE,

//3.第三个参数是非核心线程等待新任务的时长 KEEP_LIVE;

//4.第4个参数是阻塞队列。blockQueue

//5.第5个参数是线程工厂 ThreadFactory

);

线程池的 处理流程:

7、AsyncTask源码分析:

public AsyncTask(@Nullable Looper callbackLooper) {
        //代表的是否是主线程的looper
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    //
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

上面是构造函数,通常我们在继承AsyncTask的时候,在主线程使用AsyncTask,确实也没必须要在子线程使用啊

new MyAsyncTask(this) 

可以看到

WorkerRunnable 实现了callable接口

mFuture实现了futureTask 。mWork作为参数传递给了mFuture,当执行mFuture的run方法的时候会调用到mWorker的call方法(那么什么时候会调用到mFuture的run方法呢??后面会说),然后执行

result = doInBackground(mParams);//此处的doInBackGrong方法是抽象方法由用户实现;
 

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

postResult传递结果给InternalHandler,执行完成后,执行finsh方法,否则执行onProgressUpdate方法(用户可以重载)

    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
onPostExecute方法用户可重载
    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

到此,大家看到了熟悉的

doInBackground

onPostExecute

onProgressUpdate

 

但是

onPreExecute方法呢???AsyncTask的execute方法呢???

  //TODO 必须要在主线程执行,Params就是传入的参数
    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

如下,当用户调用execute方法的时候,会调用executeOnExecutor方法

 @MainThread
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING;
        //执行前要做的事情
        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

到这里我们看到了OnPreExecute方法,这里的exec就是传入的sDefaultExecutors;

r.run执行了我们刚才遗留的问题,会调用到mWorker中的call投递结果

//这里的sDefaultExecutors = new SerialExecutor串行的线程池 
private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        //这里的r就是mFuture
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        //此处执行mFuture run最终会执行mWorker的call方法投递结果
                        r.run();
                    } finally {
                        //执行完了使用线程池调度下一个
                        scheduleNext();
                    }
                }
            });   
            //当前没有任务
            if (mActive == null) {
                scheduleNext();
            }
        }
    
        //如果执行完或者没有任务就会调用线程池执行下一个
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

小小的总结一下AsyncTask的分析吧: 创建了一个串行执行的线程池,当用户在主线程执行new AsyncTask.execute(params)方法的时候,会从当前的线程池中取出一个线程去执行,先可以看到我们的onPreExecute方法,然后线程池中的线程会调用mWorker.call方法,这个方法里封装了用户要复写的ondoingbackground方法,并且最终就结果投递出去,在finsh方法中我们可以看到onPostExecute方法,将状态机置为finish,到此结束

 

第5章 Retrofit源码分析

5.1 Retrofit 使用举例

1、访问的例子

  /**
     * 普通GET请求
     */
    private void getIpInformation() {
        String url = "http://ip.taobao.com/service/";
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        IpService ipService = retrofit.create(IpService.class);
        Call<IpModel> call = ipService.getIpMsg();
        
        call.enqueue(new Callback<IpModel>() {
            @Override
            public void onResponse(Call<IpModel> call, Response<IpModel> response) {
                Log.e(TAG, "### nResponse: ");
                String country = response.body().getData().getCountry();
                Log.i(TAG, "### country" + country);
                Toast.makeText(getApplicationContext(), country, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<IpModel> call, Throwable t) {
                Log.e(TAG, "### onFailure: ");
            }
        });
    }

特性要注意一个事情,我调试了好久


public interface IpService {
    @Headers({
            "Accept-Encoding: application/json",
            "User-Agent: xiaoyubo"
    })
    @GET("getIpInfo.php?ip=59.108.54.37")
    Call<IpModel> getIpMsg();
}

如果使用模拟器进行调测的话请加上上述的请求头!!!!!!!!!

否则请求不到数据,注意当使用其他虚拟机请求的时候,使用fillder抓包看下有没有这个user-Agent的字段,因为有的服务器会拦截这个请求;

 

再来看下工建造者模式的写法: 以后就不要再写很多的构造函数啦

package com.whut.android_andvaced_light.retrofit;

public class NutritionFacts {

    private final int servingSize; //TODO 必须的
    private final int servings; //TODO 必须的
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    //一个内部类
    //以后维护的时候,添加新参数的时候也很方便
    public static class Builder {
        // Required parameters
        private final int servingSize;
        private final int servings;

        // Optional parameters - initialized to default values
        private int calories = 0;
        private int fat = 0;
        private int carbohydrate = 0;
        private int sodium = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder calories(int val) {
            calories = val;
            return this;
        }

        public Builder fat(int val) {
            fat = val;
            return this;
        }

        public Builder carbohydrate(int val) {
            carbohydrate = val;
            return this;
        }

        public Builder sodium(int val) {
            sodium = val;
            return this;
        }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    //构造函数需要传builder
    //可以使用单个builder构建多个对象
    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }

    public static void main(String[] args) {
        //具有安全性和可读性
        //build的时候才会验证参数是否正确
        NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
                .calories(100).sodium(35).carbohydrate(27).build();
    }
}

 

第8章 函数响应式编程

异步操作

说道异步操作我们通常是想到 handler + asyncTask的框架,然而随着代码逻辑的复杂程度和请求数量越来越多,不像RXJAVA可以保持很清晰的逻辑,如同流水线一样,RXJAVA一步步将所需要的内容进行加工,最终形成你想要的成品,然后发射给subscribe进行处理。

想想我们的线程切换。通常在先要开启子线程,然后异步请求完成后,通过handler切换到主线程然后再刷新UI

 

Retrofit retrofit1 = new Retrofit.Builder().baseUrl("/").addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
final GetRequest_Interface getRequest_interface = retrofit1.create(GetRequest_Interface.class);
getRequest_interface.getCall().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Translation_1>() {
    @Override
    public void accept(Translation_1 translation_1) throws Exception {
        
    }
});

在MainActivity需要中需要销毁activity的时候就要取消请求

在onStop中


    @Override
    protected void onStop() {
        LogUtil.d(TAG, "====>onStop");
        super.onStop();
        if ((null != mDispose) && (!mDispose.isDisposed())) {
            mDispose.dispose();
        }
    }

RxJava的源码解析

1、RxJava的订阅流程

第一步,首先要创建一个被观察者Observable,有很多方法。just\fromArray\Create

  @Test
    public void TestRxJava() {
    // 创建一个消费者,也叫观察者,用来消费注册的事件
        Consumer<String> consumer = o -> {
            if (!o.isEmpty()) {
                System.out.println(o);
            }
        };

        // 被观察者注册一个消费的事件
        Observable.just("1").subscribe(consumer);
    }
 Consumer<String> successObserver = new Consumer<String>() {
            @Override
            public void accept(String o) throws Exception {
                if (!o.isEmpty()) {
                    System.out.println(o);
                }
            }
        };

        Consumer<Throwable> failObserver = new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {

            }
        };
        subscribe = Observable.just("1").subscribe(successObserver, failObserver);

 

 Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {
                observableEmitter.onNext("1");
            }
        }).doOnNext(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                System.out.println(s + "do on next");
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable disposable) {

            }

            @Override
            public void onNext(String s) {
                System.out.println(s);
            }

            @Override
            public void onError(Throwable throwable) {

            }

            @Override
            public void onComplete() {

            }
        });

第二步,创建一个观察者,也就是Consumer

第三步,观察者订阅事件

 

2、RxJava的线程切换流程

在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)。

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

3、RxJava的变换

flatMap & Map

4、RxJava+Retrofit

getUser(userId)
    .doOnNext(new Action1<User>() {
        @Override
        public void call(User user) {
            processUser(user);
        })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<User>() {
        @Override
        public void onNext(User user) {
            userView.setUser(user);
        }

        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable error) {
            // Error handling
            ...
        }
    });

5、RxJava+RxBinding

6、RxJava+RxBus

 

 

 

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

过了个年哈,,继续读书笔记Android进阶解密

第一章 Android 系统架构

1、app 应用层(launcher、dialer、carmera、calendar);

2、framework层(为应用包含系统应用提供api接口 包含view System\Content Providers\Manger(Window Manager、PackageManager、acitivityManager))

3、系统运行层(Native 层 (C++程序库 + AndroidRuntime(coreLibrary)))

4、HAL层,硬件抽象层(wifi bluetooth audio)

5、linux kernel

 

 

第二章 Android系统启动

/system/core/init         init 进程是Andoird系统启动的第一个进程

按下电源后,首先系统会加载引导程序bootloader,引导程序启动linux 内核,linixu内核加载完成后,在系统文件中寻找init.rc 文件,启动init进程

init进程又会启动zygote进程;

1、init 进程的入口函数:

init.rc文件会创建init进程,在init进程的main函数中会去解析init.rc的service

这里会启动zygote进程,service是Android init language语句、init进程拉起一个名字为zygote的进程,位于/system/bin/app_process64位置,

1 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
2    class main
3    priority -20
4    user root
5    group root readproc reserved_disk
6    socket zygote stream 660 root system
7    onrestart write /sys/android_power/request_state wake
8    onrestart write /sys/power/state on
9    onrestart restart audioserver
10    onrestart restart cameraserver
11    onrestart restart media
12    onrestart restart netd
13    onrestart restart wificond
14    writepid /dev/cpuset/foreground/tasks

2、init进程是如何启动zygote进程的 app_main.cpp函数中的main函数:

349    if (zygote) {
350        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
351    } else if (className) {
352        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
353    } else {
354        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
355        app_usage();
356        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
357    }

此时启动zygote进程;

3、属性服务

 

init进程的启动总结:

1、挂在启动所需要的文件目录;

2、初始化和启动属性服务;

3、解析init.rx配置文件并且启动zygote进程;

 

2、Zygote进程

zygote进程创建了DVM ART 应用进程程序、运行系统的关键服务systemServer;

在init进程中通过AndoridRuntime的start函数 做了如下几个事情;

a、 startVM 开启java虚拟机

b、startJniRegist 注册jni函数

c、找到zygoteinit.java文件的main方法;在1138处执行;由此调用到java层;通过jni调用到了zygoteinit的java层的main函数;

1132    char* slashClassName = toSlashClassName(className != NULL ? className : "");
1133    jclass startClass = env->FindClass(slashClassName);
1134    if (startClass == NULL) {
1135        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
1136        /* keep going */
1137    } else {
1138        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
1139            "([Ljava/lang/String;)V");
1140        if (startMeth == NULL) {
1141            ALOGE("JavaVM unable to find main() in '%s'\n", className);
1142            /* keep going */
1143        } else {
1144            env->CallStaticVoidMethod(startClass, startMeth, strArray);
1145

zygote进程总结:

创建appRuntime,调用start方法创建zygote进程;

启动jvm 并且注册jni方法;

启动systemServer;

通过jni调用zygoteInit的main函数进入zygote的java层;

等待AMS请求创建新的应用进程;

3、SystemServer进程

用来创建引导服务、核心服务 、其他服务;

如下代码片段;在SystemServer.java文件中

  Installer installer = mSystemServiceManager.startService(Installer.class);
549        traceEnd();
550
551        // In some cases after launching an app we need to access device identifiers,
552        // therefore register the device identifier policy before the activity manager.
553        traceBeginAndSlog("DeviceIdentifiersPolicyService");
554        mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
555        traceEnd();
556
557        // Activity manager runs the show.
558        traceBeginAndSlog("StartActivityManager");
559        mActivityManagerService = mSystemServiceManager.startService(
560                ActivityManagerService.Lifecycle.class).getService();
561        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
562        mActivityManagerService.setInstaller(installer);
563        traceEnd();
564
565        // Power manager needs to be started early because other services need it.
566        // Native daemons may be watching for it to be registered so it must be ready
567        // to handle incoming binder calls immediately (including being able to verify
568        // the permissions for those calls).
569        traceBeginAndSlog("StartPowerManager");
570        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
571        traceEnd();

SystemServer进程总结;

启动binder线程池可以与其他进程通信;

启动系统服务;

 

4、launcher的启动

由AMS启动;

AMS由SystemServer启动,SystemServer由Zygote进程启动,zygote由Init进程启动,init由init_rc脚本启动;

 

 

第17章 内存优化

内存泄露是指本应该在生命周期结束的时候,被GC回收,但是此时它还在被引用,所以致内存泄漏。随着泄漏的累积,app将消耗完内存。

1、常见的内存泄露的情况:

1、在单例中持有Context对象

如下代码片段中,单利模式是他的生命周期和我们的应用是一样长的,当持有Activity的强引用的时候,Acitivy的context不会被回收,造成内存泄露;

public class Singleton {


    private static Singleton singleton;
    private Context mContext;

    private Singleton(Context context) {
        this.mContext = context;
    }

    public Singleton getInstance(Context context) {
        if (singleton == null) {
            synchronized (Singleton.class){
                if (singleton == null) {
                    singleton = new Singleton(context);
                }
            }
        }
        return singleton;
    }
}

正确的做法应该是持有ApplicationContext;

 

再比如如下代码,当子线程持有主线程的引用的时候,子线程未结束前,主线程的activity都不会被回收,但是ondesoty会被执行;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e(TAG, "==== onCreate: ====");
        new Thread(new Runnable() {
            private  Context context;
            @Override
            public void run() {
                Log.e(TAG, "====run: ===");
                SystemClock.sleep(5 * 1000);
                context = MainActivity.this;
                Log.e(TAG, "run: end");
            }
        }).start();
        
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        Log.e(TAG, "======== onDestroy: ========");
    }

 

2、handler引起的内存泄露

public class HandlerActivity extends Activity{
	//可能引起内存泄漏的方法
	private final Handler mHandler = new Handler(){
		@Override
		public void handlerMessage(Message msg){
		//...
		}
	}
	@Override
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);

		//延迟5分钟发送消息
		mHandler.postDelayed(new Runnable(){
			@Override
			public void run(){
				...
			}
		},1000*60*5)
	}
}

 

非静态的匿名内部类,持有外部类的引用,当Acitivty消失的时候,此时的MessageQueue里的消息还没有被取走,导致handler仍然被引用,且handler是非静态的匿名内部类,持有外部类的引用,故此时Aciticy消失的时候不会被销毁,导致内存泄露;

 

3、匿名内部类runnable2此时持有了Acitivy的引用,造成runnable2未结束时,activity被销毁但是不会回收;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_inner_bad);

        Runnable runnable1 = new MyRunnable();
        Runnable runnable2 = new Runnable() {
            @Override
            public void run() {

            }
        };
    }

    private static class MyRunnable implements Runnable{

        @Override
        public void run() {

        }
    }
}

 

4、集合中的对象要被清理

 

5、bitmap对象要被回收;

 

2、内存泄露的相关分析工具

MemtoryMonitor 可以查看内存的使用情况,内存抖动(频繁的分配内存&回收内存,导致绘制线程受阻),是否有频繁的gc.

使用leakCany

1、引入依赖项

debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
  releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
  testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'

public class MyApplication extends Application {
    private static final String TAG = MyApplication.class.getSimpleName();
    private RefWatcher refWatcher;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "===== MyApplication onCreate: =====");
        refWatcher = setupLeakCanary();
    }


    private RefWatcher setupLeakCanary() {
        if (LeakCanary.isInAnalyzerProcess(this)) {
            return RefWatcher.DISABLED;
        }
        return LeakCanary.install(this);
    }

    public static RefWatcher getRefWatch(Context context) {
        MyApplication myApplication = (MyApplication) context.getApplicationContext();
        return myApplication.refWatcher;
    }

}

第16 章绘制优化

1、绘制原理

View的绘制包含 measure,layout,draw

60fps(1秒钟60帧)让人感受不到卡顿,当低于60fps之后则明显感觉卡顿,

影响卡顿的原因:

布局layout复杂,无法再10ms内完成绘制;

UI线程做了好事操作

GC回收时间过长或者频繁GC

 

工具:

Systrace:

不咋好用点击DDMS中的start Method profilng,看到耗时的方法

 

 

 

 

2、点击hierarchy View查看视图的层级

1、嵌套层级需要合理的减少

2、使用include标签来进行布局的复用

3、用 merge标签来去除多余层级

比入根布局是linearlayout ,linearlayout中有recycleview 每个item有嵌套linearlayout,则 可以使用merge标签,减少嵌套层级

有一个问题就是merge标签最好是用于替代布局方向一致的布局

4、使用viewstub来加高加载速度

viewstub用来替代布局中不需要显示出来的view,在对于viewstub使用inflate房钱前,他是不占布局看下控件和资源的

viewstub,inlate ; viewstub,setvisiabilty(Visiavble) viewStub操作的是布局文件

 

避免过度绘制就是移除不需要的background

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值