陈明亮的 Blog


  • 首页

  • 关于

  • 标签

  • 归档

kotlin 安全性

发表于 2019-09-02

这篇讨论的仅仅是kotlin的安全性

1.简洁

这个从直观上很容易看到.

简洁就意味着实现相同的功能,kotlin 可以用更少的代码.因为 java 的语法相对来说比较负责,所以说编写更长的代码更容易出现更多的错误

2.null 安全

阅读全文 »

Android-AIDL的简单使用

发表于 2019-03-19


### 目的

这篇文章主要是 Android 中 AIDL 的简单使用,算是为了下一篇 Android IPC 做一个铺垫

### 背景

Android 中的 AIDL 主要是用来做 Android IPC(进程间的通信)的.可以说是系统帮我们封装好的一个工具.

1.多进程的实现

既然是进程间的通信肯定就要有两个进程.

这里为了方便两个进程在同一个 app 中来实现,其本质和两个 app 是一样一样的.

要想在 app 中启用多线程,只有一种方式,那就是为 Android 的四大组件指定 process属性.

process的属性值要怎么写呢?

只有图中的两种方式

1.冒号+单词(字母也可以)

2.包名+点(英文中的句号)+单词(字母也可以)
2.序列化

在 Android 中实现序列化有两种方式

2.1 Serializable (java 中的序列化方式)

看一个典型的例子

可以看到非常简单,只需要实现 Serializable 接口就可以了.

那么怎么序列化和反序列化呢?

也非常简单

Book book = new Book("1", "Android");
try {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("android.txt"));
        out.writeObject(book);
        out.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("android.txt"));
        Book newBook = (Book) in.readObject();
        in.close();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

上面的代码是以本地文件为媒介实现的序列化和反序列化.

但是有一点需要注意

虽然 book 和 newbook 的内容完全一样,但是两者并不是同一个对象了.

这里还有一个要提一下,可能有眼尖的童鞋已经发现了.就是 serialVersionUID 是干什么呢.

serialVersionUID 即使不指定也是可以实现序列化的.那还写它干什么呢?

且听我慢慢道来

从AsyncTask开始来看Android中的线程和线程池

发表于 2019-02-26

这篇文章是从 AsyncTask 的角度进入,从而分析线程和线程池的文章.

涉及到一下内容.

  • AsyncTask 的使用
  • AsyncTask 的源码分析
  • 线程
  • Thread
  • Runnable
  • Callable
  • FutureTask
  • Future
  • 线程池Executor
  • ThreadPoolExecutor
  • FixedThreadPool
  • CachedThreadPool
  • ScheduledThreadPool
  • SingleThreadPool
1. AsyncTask 的简单使用

通过一个模拟下载文件的例子来看.

String url = "";
//Params,Progress,Result
new AsyncTask<String,Integer,File>(){

    //下载任务开始之前调用--主线程
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    //实际的下载--分线程
    @Override
    protected File doInBackground(String... params) {
        String fileUrl = params[0];
        // download file
        publishProgress(50);
        return new File("");
    }

    //任务的进度--主线程
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

    }

    //最后的结果--主线程
    @Override
    protected void onPostExecute(File s) {
        super.onPostExecute(s);
    }
}.execute(url);

其实 AsyncTask 的使用无外乎就四个方法而已.

onPreExecute() 在任务开始之前调用–主线程

doInBackground(String... params) 实际的任务–分线程

onProgressUpdate(Integer... values) 任务的进度–主线程

onPostExecute(File s) 最后的结果–主线程

至于 AsyncTask的三个泛型参数

第一个是传入的参数类型

第二个是进度的类型

第三个是结果得类型

通过一个图看明白这三个参数

阅读全文 »

Android根据资源名获取资源Id

发表于 2019-02-21
如果是只需要代码的话,看 解决方法 位置!

一般情况下我们都是直接使用资源 Id 来获取资源的,简单而又方便.

例如:

imageView.setImageResource(R.drawable.ic_launcher_background)

但是有些情况下,这种方式就显的有点复杂了.

例如这么一种情况 :

要根据 type 的值来选择对应的图片.

type : 取值范围是0…9

对应的图片为: iconvip0, iconvip1 …. iconvip9.

这时候如果用资源 id 的方式来取图片的话,代码是这样的:

阅读全文 »

Android 消息机制

发表于 2019-01-10

本文目的:

    • 详细梳理一下 Android 的消息机制.其实说白了就是 Handler 的使用和原理剖析

我们都知道 Handler.并且日常使用也是非常的频繁.

那么随之而来的几个问题

#1.Handler 到底是什么呢?

    • 这个问题,呃…还是放到最后来总结一下吧.总不能说 Handler 就是一个类而已(就跟问你 Android到底是什么呢?)

#2.Handler 是用来干什么的?

    • 本质就是将多线程转换成单线程.

      举个例子:
  • 在 Android 我们常常在子线程做一些操作之后(如:下载图片),要回到主线程去 ui,通常使用的就有 Handler.因为如果每个线程都可以更新 ui 的情况下,界面就变的不可控了.如果加锁的话,那性能就成一个问题了 . so Handler 的作用就是将多线程变成单线程,从而使界面 ui 按照我们预期的效果更新.

#3.Handler 的使用(对此熟悉的可直接跳过)

阅读全文 »

ipc

发表于 2018-07-20

Binder

从以下几个方面来看 binder

Android : 中的一个类,实现了 IBinder 接口

IPC : 是 Android 中跨进程通信的一种方式

Framework:Binder 是 ServiceManager 连接各种 Manager(ActivityManager WindowManager …)和相应 ManagerService 的桥梁

Android 应用层:Binder 是客户端和服务端进行通信的媒介,当bindService 的时候,服务端会返回一个包含了服务端业务调用的 Binder 对象,通过这个 Binder 对象,客户端就可以获取服务端提供的服务(包括普通服务和 AIDL 服务)或者数据

设备: 可以理解为一种虚拟的物理设备,设备驱动是/dev/binder,该通信方式在 Linux 中没有

通过 AIDL来看 Binder 的工作机制

先看示例类在包中的位置

示例类

Book.aidl

package com.cml.cmlapplication.ipc;
parcelable Book;

IBookManager.aidl

package com.cml.cmlapplication.ipc;
import com.cml.cmlapplication.ipc.Book;
interface IBookManager {
    List<Book> getBookList();
    void addBook(in Book book);
}

Book.java

import android.os.Parcel;
import android.os.Parcelable;

public class Book implements Parcelable {

private int bookId;
private String bookName;

public Book(int bookId, String bookName) {
    this.bookId = bookId;
    this.bookName = bookName;
}

protected Book(Parcel in) {
    bookId = in.readInt();
    bookName = in.readString();
}

public static final Creator<Book> CREATOR = new Creator<Book>() {
    @Override
    public Book createFromParcel(Parcel in) {
        return new Book(in);
    }

    @Override
    public Book[] newArray(int size) {
        return new Book[size];
    }
};

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeInt(bookId);
    dest.writeString(bookName);
}
}

然后编译后,系统会自动生成一个类,位于: build/generated/source/aidl/…/IBookManager.java

我们就分析这个类基本就可了解 Binder上层工作机制.

这个类如下

IBookManager.java

public interface IBookManager extends android.os.IInterface {

//stub 是一个 binder
public static abstract class Stub extends android.os.Binder implements com.cml.cmlapplication.ipc.IBookManager{

    //binder 的唯一标识
    private static final java.lang.String DESCRIPTOR = "com.cml.cmlapplication.ipc.IBookManager";

    public Stub(){
        this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * 用于将服务端的 Binder 对象转换成客户端所需的 AIDL接口类型对象
     * 同进程:     服务端对象本身
     * 不同进程:   系统封装后的 Stub.proxy
     */
    public static com.cml.cmlapplication.ipc.IBookManager asInterface(android.os.IBinder obj) {
        if ((obj==null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin!=null)&&(iin instanceof com.cml.cmlapplication.ipc.IBookManager))) {
            return ((com.cml.cmlapplication.ipc.IBookManager)iin);
        }
        return new com.cml.cmlapplication.ipc.IBookManager.Stub.Proxy(obj);
    }

    /**
     * 提供 Binder 对象
     */
    @Override public android.os.IBinder asBinder() {
        return this;
    }

    /**
     * 运行位置:服务端的 Binder 线程池
     * 客户端发起跨进程的请求时,远程请求会通过底层封装后交由此方法处理。
     *
     * 方法内部通过 code 来确定客户端的请求目标方法
     * 从 data 中获取参数
     * 执行目标方法
     * 将返回值写入 reply 并返回
     */
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
        switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_getBookList: {
                data.enforceInterface(DESCRIPTOR);
                java.util.List<com.cml.cmlapplication.ipc.Book> _result = this.getBookList();
                reply.writeNoException();
                reply.writeTypedList(_result);
                return true;
            }
            case TRANSACTION_addBook: {
                data.enforceInterface(DESCRIPTOR);
                com.cml.cmlapplication.ipc.Book _arg0;
                if ((0!=data.readInt())) {
                    _arg0 = com.cml.cmlapplication.ipc.Book.CREATOR.createFromParcel(data);
                }
                else {
                    _arg0 = null;
                }
                this.addBook(_arg0);
                reply.writeNoException();
                return true;
            }
        }
        return super.onTransact(code, data, reply, flags);
    }

    private static class Proxy implements com.cml.cmlapplication.ipc.IBookManager {

        private android.os.IBinder mRemote;

        Proxy(android.os.IBinder remote) {
            mRemote = remote;
        }

        @Override public android.os.IBinder asBinder() {
            return mRemote;
        }

        public java.lang.String getInterfaceDescriptor() {
            return DESCRIPTOR;
        }

        /**
         * 运行位置:客户端
         *
         * 客户端远程调用此方法时,首先创建_data、_reply 和_result(List)
         * 然后将参数写入_data,随后调用 transact()发起远程调用请求并挂起当前线程,
         * 此时服务端的 onTransact()方法被调用,直到远程调用返回后,当前线程继续运行并从_reply 中获取返回结果,最后返回
         */
        @Override public java.util.List<com.cml.cmlapplication.ipc.Book> getBookList() throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            java.util.List<com.cml.cmlapplication.ipc.Book> _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                _reply.readException();
                _result = _reply.createTypedArrayList(com.cml.cmlapplication.ipc.Book.CREATOR);
            }
            finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }

        @Override public void addBook(com.cml.cmlapplication.ipc.Book book) throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                if ((book!=null)) {
                    _data.writeInt(1);
                    book.writeToParcel(_data, 0);
                }
                else {
                    _data.writeInt(0);
                }
                mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                _reply.readException();
            }
            finally {
                _reply.recycle();
                _data.recycle();
            }
        }
    }

    static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}

public java.util.List<com.cml.cmlapplication.ipc.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.cml.cmlapplication.ipc.Book book) throws android.os.RemoteException;
}

类中的注释比较详细了,这里说一下其整体的工作流程

首先客户端发起远程调用通过getBookList(),此方法内部会调用 transact() , 同时当前的线程挂起,等待返回结果,然后此远程调用请求通过系统底层的封装后会走到运行在服务端 Binder 线程池的方法 onTransact()此方法执行完之后会返回结果_reply,此时返回客户端,继续运行被挂起的线程,从_reply 中取出返回结果,并返回.远程调用过程结束.

一张图看 Binder 的工作机制 摘自 Android 开发艺术探索

Android 中的 IPC 方式

1.Bundle

Android 的四大组件中的三个组件:Activity/Service 和 BorderCastReceiver都支持在 Intent 中使用 Bundle 传递数据,因为 Bundle实现了 Parceable 接口所以可以方便的在进程之间传输.当然所要传输的数据必须可以被序列化才行.

2.使用文件共享

两个进程通过读/写同一个文件来交换数据

3.Messenger

信使,其底层实现也是 AIDL

4.AIDL

工作机制见上面的 Binder 工作机制分析

5.ContentProvider

是 Android 中专门用来不同应用之前交换数据的.其底层也是通过 Binder 来实现的.

6.Socket

观察者模式

发表于 2018-07-18

这一文来看看观察者模式

我们从一个警察和小偷的故事的角度来看.

那么很显然

警察:观察者

功能:能看到被观察的小偷的所有动作

小偷:被观察者

功能:

1.被安装监视器

2.发现监视器,扔掉监视器

3.没有发现监视器,一举一动被监视

好,我们来上代码

阅读全文 »

Android常见内存泄漏

发表于 2018-07-06

0.

其实很多时候的内存泄漏都是内部类导致的.因为非静态的内部类默认会持有外部类的引用

内存泄漏:某一块内存应该被回收,而由于种种原因无法被回收,也就无法再利用此块内存

内存溢出:(OOM)当程序需要分配一块内存来使用的时候,发现所有的内存都被占用,无法分配新的内存空间导致内存溢出(其实就是内存不够用了,因为在移动设备上每个 app 的内存是非常有限的)

1.Handler 引起的内存泄漏

阅读全文 »

Android Developer Learn Kotlin

发表于 2018-06-19

1.Kotlin 介绍

关于 Kotlin 的介绍,没有什么会比官网介绍的更权威了,

so. 这里就偷个懒把网址给出来了!

Kotlin 语言中文站

Kotlin 语言英文站

一切关于 kotlin 都可以从上面的网站获取哦!

2.Kotlin 数据类型

阅读全文 »

Android原生数据库和GreenDao的简单使用

发表于 2018-06-15

为什么要写这个文章呢,主要目的是做一个记录.

因为如果项目中如果用不到数据库的话,基本过段时间就忘记了.
当再需要用的时候,又得去查查查,浪费时间.

Android SQLite

1.创建SQLiteOpenHelper的子类

阅读全文 »
1234
cml

cml

32 日志
10 标签
© 2022 cml
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4