Sparky


  • 首页

  • 归档

未命名

发表于 2019-05-06

HTTP和HTTPS的区别

HTTP 超文本传输协议

HTTPS 安全套接字超文本传输协议

未命名

发表于 2019-05-06

常见的gradle命令

./gradlew -v
./gradlew clean
./gradlew build

./gradlew assembleDebug
./gradlew assembleRelease

./gradlew installRelease
./gradlew uninstallRelease

./gradlew –stop

未命名

发表于 2019-05-06

Glide源码解读(参考郭霖博客)

郭霖blog

没看懂—-待续

Camera2应用开发

发表于 2019-05-06

Camera2应用开发

1. 打开相机,开启预览

在布局文件中加入TextureView,然后对其进行监听

textureview = (TextureView) findViewById(R.id.textureView);

textureview.setSurfaceTextureListener(surfaceTextureListener);

当Textureview准备好,会回调surfacetexturelistener的onSurfaceAvailabale(),我们在预览之前给相机设置参数,然后打开相机

TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
    //当SurefaceTexture可用的时候,设置相机参数并打开相机
    setupCamera(width, height);
    openCamera();
}
};

设置相机参数,主要是根据textureview的尺寸设置预览尺寸。

private void setupCamera(int width, int height) {
    //获取摄像头的管理者CameraManager
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
    //遍历所有摄像头
    for (String cameraId: manager.getCameraIdList()) {
        CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
        //默认打开后置摄像头
        if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT)
            continue;
        //获取StreamConfigurationMap,它是管理摄像头支持的所有输出格式和尺寸
        StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        //根据TextureView的尺寸设置预览尺寸
        mPreviewSize = getOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height);
        mCameraId = cameraId;
        break;
    }
} catch (CameraAccessException e) {
    e.printStackTrace();
}
}

打开相机,通过cameramanager打开相机,在状态回调中打开相机预览。

private void openCamera() {
//获取摄像头的管理者CameraManager
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
//检查权限
try {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    //打开相机,第一个参数指示打开哪个摄像头,第二个参数stateCallback为相机的状态回调接口,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行
    manager.openCamera(mCameraId, stateCallback, null);
} catch (CameraAccessException e) {
    e.printStackTrace();
}
}

private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
    mCameraDevice = camera;
    //开启预览
    startPreview();
}
}

通过textureview显示相机预览数据,camera2的拍照数据和预览数据都是通过cameracapturesession实现的。

private void startPreview() {
SurfaceTexture mSurfaceTexture = mTextureView.getSurfaceTexture();
//设置TextureView的缓冲区大小
mSurfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
//获取Surface显示预览数据
Surface mSurface = new Surface(mSurfaceTexture);
try {
    //创建CaptureRequestBuilder,TEMPLATE_PREVIEW比表示预览请求
    mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    //设置Surface作为预览数据的显示界面
    mCaptureRequestBuilder.addTarget(mSurface);
    //创建相机捕获会话,第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession的状态回调接口,当它创建好后会回调onConfigured方法,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行
    mCameraDevice.createCaptureSession(Arrays.asList(mSurface), new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(CameraCaptureSession session) {
            try {
                    //创建捕获请求
                    mCaptureRequest = mCaptureRequestBuilder.build();
                    mPreviewSession = session;
                    //设置反复捕获数据的请求,这样预览界面就会一直有数据显示
                    mPreviewSession.setRepeatingRequest(mCaptureRequest, mSessionCaptureCallback, null);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }

        @Override
        public void onConfigureFailed(CameraCaptureSession session) {

        }
    }, null);
} catch (CameraAccessException e) {
    e.printStackTrace();
}
}

Camera1 流程

  • 添加相机相关权限
  • 通过Camera.open(int)获得一个相机实例
  • 利用camera.getParameters()得到相机实例的默认设置Camera.Parameters
  • 如果需要的话,修改Camera.Parameters并调用camera.setParameters(Camera.Parameters)来修改相机设置
  • 调用camera.setDisplayOrientation(int)来设置正确的预览方向
  • 调用camera.setPreviewDisplay(SurfaceHolder)来设置预览,如果没有这一步,相机是无法开始预览的
  • 调用camera.startPreview()来开启预览,对于拍照,这一步是必须的
  • 在需要的时候调用camera.takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)来拍摄照片
  • 拍摄照片后,相机会停止预览,如果需要再次拍摄多张照片,需要再次调用camera.startPreview()来重新开始预览
  • 调用camera.stopPreview()来停止预览
  • 一定要在onPause()的时候调用camera.release()来释放camera,在onResume中重新开始camera

原理

camera2流程示意图

camera2中主要类

拍照流程图

参考

android.hardware.camera2使用指南

未命名

发表于 2019-05-06

电源管理(1)-基本概念

1. linux的电源状态

  • on >>> S0 - working
  • standby >>> S1 - cpu and ram are powered but not executed
  • suspend to ram >>> S3 - ram is powerd and the running content is saved to ram
  • suspend to disk >>> S4 - all content is saved to disk and power down

S3 挂起到内存,就是常说的待机。计算机将目前的运行状态等数据存放在内存,关闭硬盘、外设等设备,进入等待状态。此时内存仍然需要电力维持其数据,但整机耗电很少。恢复时计算机从内存读出数据,回到挂起前的状态,恢复速度较快。对DDR的耗电情况进行优化是S3性能的关键,大多数手持设备都是用S3待机。

S4 挂起到硬盘,就是常说的休眠。把运行状态等数据存放在硬盘上某个文件或者某个特定的区域,关闭硬盘、外设等设备,进入关机状态。此时计算机完全关闭,不耗电。恢复时计算机从休眠文件/分区中读出数据,回到休眠前的状态,恢复速度较慢。电子书项目中,见过一款索尼的电子书,没有定义关机状态,只定义了S4,从而提高开机速度。

2. 电源管理接口

linux把电源接口框架都纳入了设备模型中,通过power_kobj对象的属性文件提供操作电源策略的接口。

3. 电源状态的切换

linux的世界里,一切皆文件。通过state文件写入不同的值来让系统进入不同的电源状态,接收状态值的函数是state_store.

autosleep是Android内核为了跟主线内核兼容引入的,切换电源状态的入口函数是pm_suspend。针对嵌入式系统,s3是一种常见的节电状态,俗称待机。待机可以粗略分为5个阶段。

  1. 冻结用户态进程
  2. 设备挂起
  3. 针对soc相应的节电操作和为唤醒做准备
  4. smp中非启动cpu的挂起
  5. cpu core的挂起

未命名

发表于 2019-05-06

Android PowerManagerService分析

未命名

发表于 2019-05-06

组件化Application方案

前言

本人也是刚接触组件化不久,原项目是由几个分开的系统应用组成,目前做的只是将几个应用合并到同一项目下,将这几个应用拆分为几个模块并将其中通用的地方抽出来新建了几个基础组件和lib组件。

在这个过程中也踩了很多坑。总结下来主要是:

  1. 全局gradle配置
  2. 对于集成状态和组件状态的区别处理
  3. arouter的使用
  4. 一些第三方的特殊处理。我遇到的主要是butterknife。主要包括不使用apt改用anotationprocess,使用butterknife-gradle-plugin-8.4.0,全局修改R为R2,注意在R2下项目也可以作为application运行。
  5. 应用application

Application方案

  1. 创建base module。该module提供基础类库。
  2. 创建BaseApplication类,ModuleConfig类以及BaseApplicationImpl类。BaseApplication类的onCreate()方法中初始化一些全局配置并且初始化模块配置。BaseApplicationImpl类是一个接口类,需要各模块自己去实现各个模块的配置。这些配置的类是定义在ModuleConfig中,在初始化的时候会通过反射创建这些类。

    // ------------BaseApplication------------
    public class BaseApplication extends MultiDexApplication {
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            // 初始化全局配置
            initGlobalConfig();
    
            // 初始化模块配置
            initModuleConfit();
        }
    
        private void initGlobalConfig() {
            // 初始化ARouter
            initARouter();
        }
    
        private void initModuleConfit() {
            for (String modules : ModuleConfig.MODULELIST){
                try {
                    Class clz = Class.forName(modules);
                    Object obj = clz.newInstance();
                    if (obj instanceof BaseApplicationImp){
                        ((BaseApplicationImp) obj).onCreate(this);
                    }
    
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private void initARouter() {
            ARouter.openLog();
            ARouter.openDebug();
            ARouter.init(this);
        }
    }
    
    // ------------BaseApplicationImp------------
    public interface BaseApplicationImp{
        void onCreate(Application application);
    }
    
    // ------------ModuleConfig-------------
    public interface ModuleConfig {
    
        static final String MODULE_PDFREADER = "com.dou.sample.mupdf_demo.BaseApplication";
        static final String MODULE_LAUNCHER = "com.guowen.luncher.guowenreaderapp.app.AppContext";
    
        public static final String[] MODULELIST = {
                MODULE_LAUNCHER,
                MODULE_PDFREADER
        };
    }
    
  3. 在各个子module中实现BaseApplicationImpl,这个类可以提供模块化的配置以及application context对象。清单文件都设置为BaseApplication即可。

思路

原来的项目是每个应用都有一个application和baseapplication,现在baseapplication抽出来了,但是集成状态下只能用同一个application,组件状态下application也不同。

所以这里做了统一处理。不管是集成状态还是组件状态都设置application为baseapplication。baseapplication的oncreate方法主要有两个方法,加载全局配置和加载组件配置。加载全局配置比较简单,加载组件配置就是将组件的配置类在moduleconfig类中声明,然后通过遍历这些配置列表,通过反射加载baseapplicationimpl的实现类。如果是组件状态下直接会报找不到类异常也就不会加载别的module的配置。

因为之前项目的application类(单例模式)不仅会初始化配置还会提供一些静态成员和全局context,如果改动,项目代码也要修改很多。所以这里直接用这个类实现BaseApplicationImpl,将这个类的单例context设置baseapplication传递的对象。

未命名

发表于 2019-05-06

简历


> 联系方式

手机: 18236886950 Email: douyingnan@gmail.com
QQ: 42588451

> 个人信息
豆应楠/男
本科/河南理工大学/计算机科学与技术专业 工作年限: 3年
博客: http://www.jianshu.com/u/9b0d48b8fb94 GitHub: https://github.com/douyn
应聘职位: Android开发工程师 英语:四级
期望薪资: 12k-15k

> 职业技能

1. 熟练掌握android常用的系统控件,具备自定义控件的开发能力,能够利用系统控件及自定义控件完成常见UI界面的绘制
2. 熟悉Android的数据存储方式(File,SharedPrefrence,Sqlite,ContentProvider,Net),使用GreenDao或者SQLite进行数据库操作
3. 熟悉利用JSON方式进行数据交换,能利用Gson完成JSON数据的解析,配合retrofit对网络请求结果进行解析
4. 熟悉android中常用动画和组合动画的使用
5. 熟练使用Git版本控制工具对项目进行配置管理
6. 熟悉使用android最新控件,ConstraintLayout/CordinatorLayout等
7. 熟悉Material Design依赖库。TabLayout/NagevitionView/SnackBar/FloatingActionBar等。
8. 使用EventBus进行跨UI数据传递,使用JSON和GSON进行数据解析
9. 使用ImageLoader/Glide进行图片加载,使用LUBAN进行图片压缩
10. RxJava/Retrofit/greenDao/Butter Knife等最常用第三方类库
11. 使用高德地图和谷歌地图进行地图开发,使用个推和GCM/FCM推送服务
12. 熟练使用Eclipse和Android Studio双开发工具

> 工作经历

### 深圳国文阅读科技有限公司 (2017/09-至今)
主要职责:独立开发

负责根据现有其他平台阅读器,做Android端的软件的开发,以及阅读器模块的研发。

### 深圳奇沃智联科技股份有限公司 (2015/11-2017/09)
主要职责:独立开发

参与产品需求调研、需求分析、页面及项目设计、开发,参与项目技术文件的整理,形成自己项目的功能设计文档。

### 红鸟网络有限公司 (2014/09-2015/11)
主要职责:团队开发

和同事进行沟通,完成负责模块的任务,及后续产品的维护和优化工作,经常进行技术交流
> 项目经历

1. 国文阅读器Launcher以及阅读软件 (2017/09-至今)

#####
项目介绍
该项目是要根据现有Linux平台的产品,将ui和功能移植到Android平台。

项目是一个类似Kindle的电纸书设备,主要功能是电子书阅读,包括了书架,书城,个人中心,设置等模块。
##### 主要技术 适配(10721440与普通手机)(因为是e-ink屏幕所以减少刷新频率,使用一些少刷新的控件) 自定义view实现阅读器(pageview)及部分ui(搜索view,亮度调节view,开机动画等)
封装网络接口显示ui数据(没有给出接口的时候,事先封装好databean) NDK的调用(编译mupdf/koreader等开源项目so,修改部分c代码)
使用greendao实现本地数据库接口(launcher的书架数据库和阅读器的书签,笔记,书摘数据库) 其它(仿京东购买详情页,本地图书管理,第三方登录,第三方支付)

2. 智能儿童手表项目中文版及海外版APP (2015/12-2016/03)

##### 项目介绍
该项目是智能儿童手表的专用APP,必须要搭配智能儿童手表使用,家长通过儿童守护APP与佩戴在孩子手腕上的智能儿童手表连接,即可随时查看孩子所在的位置以及打电话给孩子,并实现丰富多彩的亲子互动功能。
特征:
1、实时定位 2、高清通话3、SOS一键报警4、运动计步。

#####
主要技术

自定义view实现身高体重选择,自定义view实现设置和展示运动目标情况 应用主页面框架是主页面中包括四个tab页面,是通过fragmenttabhost+viewpager+fragment实现的。fragmenttabhost中控制四个tab标签,viewpager+fragment实现tab标签对应的页面展示。
使用高德地图进行深度开发,添加历史轨迹点,添加历史轨迹路线,播放历史轨迹动画,实现地图扩散动画,熟悉其他高德地图api 查看通知消息时,对列表进行了数据库缓存,并且对列表使用分页加载,做了侧滑删除处理,优化了用户体验
封装图片选择,自定义popupwindow显示底部弹窗 使用google map/google paly service/google cloud message/google billing/google zxing等多种google包

3. 智能手表三合一项目APP (2016/07-2016/11)

##### 项目介绍
该项目是公司由于手表项目过多,各自用各自的app,不方便项目管理和后期迭代,所以就有了多款手表app集成到一个app上的需求,包括儿童手表,老人手表和宠物定位手表。
特征:
1、实时定位 2、高清通话 3、SOS一键报警 4、运动计步。

#####
主要技术

使用retrofit+okhttp+rxjava框架进行网络请求处理,使用gson对结果进行转换 ListView优化。对ListView进行优化,使用ViewHolder避免重复加载xml文件,使用convertView复用组件,使用ViewHolder标签类,减少查找控件时资源使用率,大大提高ListView性能,使其滑动流畅;
全局处理并收集异常。在Application设置全局异常处理类UncaughtExceptionHandler,保证在出现未知异常时,不会给用户弹出异常信息,Kill自身进程,写crash日志文件到本地同时提交异常信息给服务器; 使用toolbar+negavitionview实现侧滑菜单,使用fragmenttabhost+viewpager+tablayout实现双层标签嵌套
使用swipemenulistviw实现侧滑,swipelayout实现下拉刷新,cordinatorlayout+nestedscrollview实现标题栏下拉放大

4. 智能门铃项目APP (2016/12-1017/5)

#####
项目介绍
该项目是与硬件门铃使用远程链接保持实时通信的app,当游客前来,应用程序将收到实时推送。当没有游人,用户也可以主动观看视频门铃。

特征:
1.实时视频 2.邀请家庭圈 3.查看录像 4.访客通话

##### 使用的技术 使用Toolbar+negavitionview实现侧滑菜单,显示账号信息和设置菜单
使用recyclerview加载列表数据,并且设置viewtype对数据进行分组显示 由于应用中有许多后台耗时操作比如搜索蓝牙,p2p数据处理等,我创建了一个service并且通过与eventbus结合使用,来统一处理这些耗时操作。
使用ijkplayer播放视频,因为视频文件是.avi文件,因为很多手机不支持.avi格式的硬解码,最终决定使用第三方的ijkplayer实现视频播放

5. 红鸟电商 (2014/11-2015/3)

#####
项目介绍
公司自己的电商项目。项目分为首页、分类、购物车、我四个模块。

项目职责:团队开发

##### 主要技术 因为项目中大量用到与服务器刷新的界面,为了提高用户的体验,在与服务器交互的子线程未完成之前,先显示加载进度条,当成功获取服务器数据以后再显示数据。
查询商品时通过ListView的分批加载数据,优化了用户的体验。 从服务器下载的图片缓存到本地,在listview的适配器中服务convertview,建立一个静态类ViewHolder,在其类内声明各个View对象,以减少这些View的创建次数大大优化了listview性能。
轮播图的封装,可用于首页的轮播图进行自动轮播,也可用于商品详情 的商品展示部分;

> 开源项目和作品

#### 开源项目
enumlistDemos: 在项目中用到的很多东西都是在这里先demo出来再使用,以及很多业余时间写的小demo。例如: 仿探探的卡片布局swipe card view,标签选择flowlayout,android风格setting页面,视频播放使用ijkplayer和 jcvideoplayer,使用scheme进行应用内和应用外跳转等等
TTNews 一个流行的新闻客户端框架,基于MVP,Materail Design,Retrofit,Glide等,基本上涵盖当前流行的app框架。
#### 技术文章
Retrofit Https踩坑记录(http://www.jianshu.com/p/41bb549317ff)
* 【踩坑记录】Eclipse项目导入Android Studio注意事项(http://www.jianshu.com/p/d49bee8b6308)
> 致谢

感谢您花时间阅读我的简历,期待有机会和您共事。

未命名

发表于 2019-05-06

极简生活法则

前言

个人法则

爱情法则

亲友法则

社会法则

快乐法则

更多法则

未命名

发表于 2019-05-06

集成测试

集成测试主要针对不直接用用户交互的组件,比如service和contentprovider。

测试 service

  1. RunWith(AndroidJUnit4.class)并且指定AndroidJUnitRunner
  2. 创建ServiceTestRule通过@Rule注释
  3. 编写测试方法

    @Test
    public void testWithBoundService() throws TimeoutException {
        // Create the service Intent.
        Intent serviceIntent =
                new Intent(InstrumentationRegistry.getTargetContext(),
                    LocalService.class);
    
        // Data can be passed to the service via the Intent.
        serviceIntent.putExtra(LocalService.SEED_KEY, 42L);
    
        // Bind the service and grab a reference to the binder.
        IBinder binder = mServiceRule.bindService(serviceIntent);
    
        // Get the reference to the service, or you can call
        // public methods on the binder directly.
        LocalService service =
                ((LocalService.LocalBinder) binder).getService();
    
        // Verify that the service is working correctly.
        assertThat(service.getRandomInt(), is(any(Integer.class)));
    }
    

    测试 contentprovider

1…345…10
Sparky

Sparky

我是谁?我在做什么?我为什么要这么做?我想做什么?我要怎么做?

99 日志
© 2019 Sparky
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4