视频驱动V4L2子系统驱动架构 - ioctl

文章系列

视频驱动V4L2子系统驱动架构 - 驱动框架
视频驱动V4L2子系统驱动架构 - ioctl

基于linux4.6.3,最后会附上一张ioctl调用总图,分析代码还是要用图来说明,这样更清晰一点,我就是这么分析的,不过平时分析的图很随便,而且很大,所以就不能在这里呈现,我在这里会贴出一个简略图

ioctl详解

进入ioctl都是从cdev->ops->ioctl进入的,一般的驱动cdev都是驱动自己初始化的,在v4l2架构中,cdev都已经初始化完成,不需要驱动开发者来初始化,下面是v4l2的cdev->ops结构体v4l2_fops :

static const struct file_operations v4l2_fops = {
    .owner = THIS_MODULE,
    .read = v4l2_read,
    .write = v4l2_write,
    .open = v4l2_open,
    .get_unmapped_area = v4l2_get_unmapped_area,
    .mmap = v4l2_mmap,
    .unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl = v4l2_compat_ioctl32,
#endif
    .release = v4l2_release,
    .poll = v4l2_poll,
    .llseek = no_llseek,
};

可以看到ioctl有两个,一个unlocked_ioctl,另一个是compat_ioctl 兼容性的,其中的区别这里不多说,我们来看函数v4l2_ioctl:

static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    struct video_device *vdev = video_devdata(filp);
    int ret = -ENODEV;

    if (vdev->fops->unlocked_ioctl) {
        struct mutex *lock = v4l2_ioctl_get_lock(vdev, cmd);

        if (lock && mutex_lock_interruptible(lock))
            return -ERESTARTSYS;
        if (video_is_registered(vdev))
            ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);--正常进入函数|video_device->fops
        if (lock)
            mutex_unlock(lock);
    } else
        ret = -ENOTTY;

    return ret;
}

从上可以看到要调用vdev->fops->unlocked_ioctl(filp, cmd, arg);具体驱动实现不同,以davinci平台为例来介绍,在vpfe_capture.c文件中,初始化过程中有

        vfd->fops       = &vpfe_fops;
static const struct v4l2_file_operations vpfe_fops = {
    .owner = THIS_MODULE,
    .open = vpfe_open,
    .release = vpfe_release,
    .unlocked_ioctl = video_ioctl2,
    .mmap = vpfe_mmap,
    .poll = vpfe_poll
};

那么是要调用video_ioctl2:

long video_ioctl2(struct file *file,
           unsigned int cmd, unsigned long arg)
{
    return video_usercopy(file, cmd, arg, __video_do_ioctl);--这个函数最终是要调用__video_do_ioctl,当然他会做其他事,有兴趣的可以去了解
}
static long __video_do_ioctl(struct file *file,
        unsigned int cmd, void *arg)
{
    struct video_device *vfd = video_devdata(file);
    const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;----|video_device->ioctl_ops(注意              video_device这几个函数的调用,要明白他们的作用)
    bool write_only = false;
    struct v4l2_ioctl_info default_info;
    const struct v4l2_ioctl_info *info;
    void *fh = file->private_data;
    struct v4l2_fh *vfh = NULL;
    int dev_debug = vfd->dev_debug;
    long ret = -ENOTTY;

    if (ops == NULL) {
        pr_warn("%s: has no ioctl_ops.\n",
                video_device_node_name(vfd));
        return ret;
    }

    if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags))
        vfh = file->private_data;

    if (v4l2_is_known_ioctl(cmd)) {------------------------检查命令是否可用
        info = &v4l2_ioctls[_IOC_NR(cmd)];

        if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) &&
            !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler))
            goto done;

        if (vfh && (info->flags & INFO_FL_PRIO)) {
            ret = v4l2_prio_check(vfd->prio, vfh->prio);
            if (ret)
                goto done;
        }
    } else {
        default_info.ioctl = cmd;
        default_info.flags = 0;
        default_info.debug = v4l_print_default;
        info = &default_info;
    }

    write_only = _IOC_DIR(cmd) == _IOC_WRITE;
    if (info->flags & INFO_FL_STD) {-----进入正题,这几个if会判断cmd的类型,然后调用不同的函数,这里留个尾巴,详情见下一节
        typedef int (*vidioc_op)(struct file *file, void *fh, void *p);
        const void *p = vfd->ioctl_ops;
        const vidioc_op *vidioc = p + info->u.offset;
    /*调用驱动自定义的函数*/
        ret = (*vidioc)(file, fh, arg);------------调用video_device->ioctl_ops
    } else if (info->flags & INFO_FL_FUNC) {
    /*调用架构定义的函数ops,ops最终还是要调用驱动自定义的函数*/
        ret = info->u.func(ops, file, fh, arg);----调用video_device->ioctl_ops
    } else if (!ops->vidioc_default) {
        ret = -ENOTTY;
    } else {
        ret = ops->vidioc_default(file, fh,
            vfh ? v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0,
            cmd, arg);----调用video_device->ioctl_ops->vidioc_default
    }

done:
    if (dev_debug & (V4L2_DEV_DEBUG_IOCTL | V4L2_DEV_DEBUG_IOCTL_ARG)) {
        if (!(dev_debug & V4L2_DEV_DEBUG_STREAMING) &&
            (cmd == VIDIOC_QBUF || cmd == VIDIOC_DQBUF))
            return ret;

        v4l_printk_ioctl(video_device_node_name(vfd), cmd);
        if (ret < 0)
            pr_cont(": error %ld", ret);
        if (!(dev_debug & V4L2_DEV_DEBUG_IOCTL_ARG))
            pr_cont("\n");
        else if (_IOC_DIR(cmd) == _IOC_NONE)
            info->debug(arg, write_only);
        else {
            pr_cont(": ");
            info->debug(arg, write_only);
        }
    }

    return ret;
}

ioctl命令分类

ioctl命令在文件v4l2-ioctl.c文件中实现,上面分析的函数__video_do_ioctl就在此文件中,在分析这个函数的过程中留了个尾巴,下面来分析一下

从上面的分析过程可以看出最终都是要调用video_device->ioctl_ops,而且调用时还需判断是INFO_FL_STD还是INFO_FL_FUNC,怎么判断呢,v4l2-ioctl.c有定义:

IOCTL_INFO_FNC(命令, 实现函数, 打印信息(debug使用), flag),同样
IOCTL_INFO_STD(命令, 实现函数, 打印信息(debug使用), flag)

static struct v4l2_ioctl_info v4l2_ioctls[] = {
    IOCTL_INFO_FNC(VIDIOC_QUERYCAP, v4l_querycap, v4l_print_querycap, 0),
    IOCTL_INFO_FNC(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, INFO_FL_CLEAR(v4l2_fmtdesc, type)),
    IOCTL_INFO_FNC(VIDIOC_G_FMT, v4l_g_fmt, v4l_print_format, 0),
    IOCTL_INFO_FNC(VIDIOC_S_FMT, v4l_s_fmt, v4l_print_format, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_REQBUFS, v4l_reqbufs, v4l_print_requestbuffers, INFO_FL_PRIO | INFO_FL_QUEUE),
    IOCTL_INFO_FNC(VIDIOC_QUERYBUF, v4l_querybuf, v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)),
    IOCTL_INFO_STD(VIDIOC_G_FBUF, vidioc_g_fbuf, v4l_print_framebuffer, 0),
    IOCTL_INFO_STD(VIDIOC_S_FBUF, vidioc_s_fbuf, v4l_print_framebuffer, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_OVERLAY, v4l_overlay, v4l_print_u32, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_QBUF, v4l_qbuf, v4l_print_buffer, INFO_FL_QUEUE),
    IOCTL_INFO_STD(VIDIOC_EXPBUF, vidioc_expbuf, v4l_print_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)),
    IOCTL_INFO_FNC(VIDIOC_DQBUF, v4l_dqbuf, v4l_print_buffer, INFO_FL_QUEUE),
    IOCTL_INFO_FNC(VIDIOC_STREAMON, v4l_streamon, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE),
    IOCTL_INFO_FNC(VIDIOC_STREAMOFF, v4l_streamoff, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE),
    IOCTL_INFO_FNC(VIDIOC_G_PARM, v4l_g_parm, v4l_print_streamparm, INFO_FL_CLEAR(v4l2_streamparm, type)),
    IOCTL_INFO_FNC(VIDIOC_S_PARM, v4l_s_parm, v4l_print_streamparm, INFO_FL_PRIO),
    IOCTL_INFO_STD(VIDIOC_G_STD, vidioc_g_std, v4l_print_std, 0),
    IOCTL_INFO_FNC(VIDIOC_S_STD, v4l_s_std, v4l_print_std, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_ENUMSTD, v4l_enumstd, v4l_print_standard, INFO_FL_CLEAR(v4l2_standard, index)),
    IOCTL_INFO_FNC(VIDIOC_ENUMINPUT, v4l_enuminput, v4l_print_enuminput, INFO_FL_CLEAR(v4l2_input, index)),
    IOCTL_INFO_FNC(VIDIOC_G_CTRL, v4l_g_ctrl, v4l_print_control, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_control, id)),
    IOCTL_INFO_FNC(VIDIOC_S_CTRL, v4l_s_ctrl, v4l_print_control, INFO_FL_PRIO | INFO_FL_CTRL),
    IOCTL_INFO_FNC(VIDIOC_G_TUNER, v4l_g_tuner, v4l_print_tuner, INFO_FL_CLEAR(v4l2_tuner, index)),
    IOCTL_INFO_FNC(VIDIOC_S_TUNER, v4l_s_tuner, v4l_print_tuner, INFO_FL_PRIO),
    IOCTL_INFO_STD(VIDIOC_G_AUDIO, vidioc_g_audio, v4l_print_audio, 0),
    IOCTL_INFO_STD(VIDIOC_S_AUDIO, vidioc_s_audio, v4l_print_audio, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_QUERYCTRL, v4l_queryctrl, v4l_print_queryctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_queryctrl, id)),
    IOCTL_INFO_FNC(VIDIOC_QUERYMENU, v4l_querymenu, v4l_print_querymenu, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)),
    IOCTL_INFO_STD(VIDIOC_G_INPUT, vidioc_g_input, v4l_print_u32, 0),
    IOCTL_INFO_FNC(VIDIOC_S_INPUT, v4l_s_input, v4l_print_u32, INFO_FL_PRIO),
    IOCTL_INFO_STD(VIDIOC_G_EDID, vidioc_g_edid, v4l_print_edid, 0),
    IOCTL_INFO_STD(VIDIOC_S_EDID, vidioc_s_edid, v4l_print_edid, INFO_FL_PRIO),
    IOCTL_INFO_STD(VIDIOC_G_OUTPUT, vidioc_g_output, v4l_print_u32, 0),
    IOCTL_INFO_FNC(VIDIOC_S_OUTPUT, v4l_s_output, v4l_print_u32, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_ENUMOUTPUT, v4l_enumoutput, v4l_print_enumoutput, INFO_FL_CLEAR(v4l2_output, index)),
    IOCTL_INFO_STD(VIDIOC_G_AUDOUT, vidioc_g_audout, v4l_print_audioout, 0),
    IOCTL_INFO_STD(VIDIOC_S_AUDOUT, vidioc_s_audout, v4l_print_audioout, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_G_MODULATOR, v4l_g_modulator, v4l_print_modulator, INFO_FL_CLEAR(v4l2_modulator, index)),
    IOCTL_INFO_FNC(VIDIOC_S_MODULATOR, v4l_s_modulator, v4l_print_modulator, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_G_FREQUENCY, v4l_g_frequency, v4l_print_frequency, INFO_FL_CLEAR(v4l2_frequency, tuner)),
    IOCTL_INFO_FNC(VIDIOC_S_FREQUENCY, v4l_s_frequency, v4l_print_frequency, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_CROPCAP, v4l_cropcap, v4l_print_cropcap, INFO_FL_CLEAR(v4l2_cropcap, type)),
    IOCTL_INFO_FNC(VIDIOC_G_CROP, v4l_g_crop, v4l_print_crop, INFO_FL_CLEAR(v4l2_crop, type)),
    IOCTL_INFO_FNC(VIDIOC_S_CROP, v4l_s_crop, v4l_print_crop, INFO_FL_PRIO),
    IOCTL_INFO_STD(VIDIOC_G_SELECTION, vidioc_g_selection, v4l_print_selection, INFO_FL_CLEAR(v4l2_selection, r)),
    IOCTL_INFO_STD(VIDIOC_S_SELECTION, vidioc_s_selection, v4l_print_selection, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_selection, r)),
    IOCTL_INFO_STD(VIDIOC_G_JPEGCOMP, vidioc_g_jpegcomp, v4l_print_jpegcompression, 0),
    IOCTL_INFO_STD(VIDIOC_S_JPEGCOMP, vidioc_s_jpegcomp, v4l_print_jpegcompression, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_QUERYSTD, v4l_querystd, v4l_print_std, 0),
    IOCTL_INFO_FNC(VIDIOC_TRY_FMT, v4l_try_fmt, v4l_print_format, 0),
    IOCTL_INFO_STD(VIDIOC_ENUMAUDIO, vidioc_enumaudio, v4l_print_audio, INFO_FL_CLEAR(v4l2_audio, index)),
    IOCTL_INFO_STD(VIDIOC_ENUMAUDOUT, vidioc_enumaudout, v4l_print_audioout, INFO_FL_CLEAR(v4l2_audioout, index)),
    IOCTL_INFO_FNC(VIDIOC_G_PRIORITY, v4l_g_priority, v4l_print_u32, 0),
    IOCTL_INFO_FNC(VIDIOC_S_PRIORITY, v4l_s_priority, v4l_print_u32, INFO_FL_PRIO),
    IOCTL_INFO_FNC(VIDIOC_G_SLICED_VBI_CAP, v4l_g_sliced_vbi_cap, v4l_print_sliced_vbi_cap, INFO_FL_CLEAR(v4l2_sliced_vbi_cap, type)),
    IOCTL_INFO_FNC(VIDIOC_LOG_STATUS, v4l_log_status, v4l_print_newline, 0),
    IOCTL_INFO_FNC(VIDIOC_G_EXT_CTRLS, v4l_g_ext_ctrls, v4l_print_ext_controls, INFO_FL_CTRL),
    IOCTL_INFO_FNC(VIDIOC_S_EXT_CTRLS, v4l_s_ext_ctrls, v4l_print_ext_controls, INFO_FL_PRIO | INFO_FL_CTRL),
    IOCTL_INFO_FNC(VIDIOC_TRY_EXT_CTRLS, v4l_try_ext_ctrls, v4l_print_ext_controls, INFO_FL_CTRL),
    IOCTL_INFO_STD(VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes, v4l_print_frmsizeenum, INFO_FL_CLEAR(v4l2_frmsizeenum, pixel_format)),
    IOCTL_INFO_STD(VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals, v4l_print_frmivalenum, INFO_FL_CLEAR(v4l2_frmivalenum, height)),
    IOCTL_INFO_STD(VIDIOC_G_ENC_INDEX, vidioc_g_enc_index, v4l_print_enc_idx, 0),
    IOCTL_INFO_STD(VIDIOC_ENCODER_CMD, vidioc_encoder_cmd, v4l_print_encoder_cmd, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_encoder_cmd, flags)),
    IOCTL_INFO_STD(VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd, v4l_print_encoder_cmd, INFO_FL_CLEAR(v4l2_encoder_cmd, flags)),
    IOCTL_INFO_STD(VIDIOC_DECODER_CMD, vidioc_decoder_cmd, v4l_print_decoder_cmd, INFO_FL_PRIO),
    IOCTL_INFO_STD(VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd, v4l_print_decoder_cmd, 0),
    IOCTL_INFO_FNC(VIDIOC_DBG_S_REGISTER, v4l_dbg_s_register, v4l_print_dbg_register, 0),
    IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0),
    IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO),
    IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO),
    IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0),
    IOCTL_INFO_FNC(VIDIOC_DQEVENT, v4l_dqevent, v4l_print_event, 0),
    IOCTL_INFO_FNC(VIDIOC_SUBSCRIBE_EVENT, v4l_subscribe_event, v4l_print_event_subscription, 0),
    IOCTL_INFO_FNC(VIDIOC_UNSUBSCRIBE_EVENT, v4l_unsubscribe_event, v4l_print_event_subscription, 0),
    IOCTL_INFO_FNC(VIDIOC_CREATE_BUFS, v4l_create_bufs, v4l_print_create_buffers, INFO_FL_PRIO | INFO_FL_QUEUE),
    IOCTL_INFO_FNC(VIDIOC_PREPARE_BUF, v4l_prepare_buf, v4l_print_buffer, INFO_FL_QUEUE),
    IOCTL_INFO_STD(VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings, v4l_print_enum_dv_timings, 0),
    IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0),
    IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)),
    IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
    IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
    IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
};

上面的分析中一直说到video_device->ioctl_ops,那么ioctl_ops有多少函数呢。。很多见下:
算了还是不粘贴了自己去代码中看吧,这里只粘一点:

struct v4l2_ioctl_ops {
    /* ioctl callbacks */

    /* VIDIOC_QUERYCAP handler */
    int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap);

    /* VIDIOC_ENUM_FMT handlers */
    int (*vidioc_enum_fmt_vid_cap)     (struct file *file, void *fh,
                        struct v4l2_fmtdesc *f);
    int (*vidioc_enum_fmt_vid_overlay) (struct file *file, void *fh,
                        struct v4l2_fmtdesc *f);
    int (*vidioc_enum_fmt_vid_out)     (struct file *file, void *fh,
                        struct v4l2_fmtdesc *f);
    int (*vidioc_enum_fmt_vid_cap_mplane)(struct file *file, void *fh,
                          struct v4l2_fmtdesc *f);
    int (*vidioc_enum_fmt_vid_out_mplane)(struct file *file, void *fh,
                          struct v4l2_fmtdesc *f);
    int (*vidioc_enum_fmt_sdr_cap)     (struct file *file, void *fh,
                        struct v4l2_fmtdesc *f);
    int (*vidioc_enum_fmt_sdr_out)     (struct file *file, void *fh,
                        struct v4l2_fmtdesc *f);
    。
    。
    。
        /* DV Timings IOCTLs */
    int (*vidioc_s_dv_timings) (struct file *file, void *fh,
                    struct v4l2_dv_timings *timings);
    int (*vidioc_g_dv_timings) (struct file *file, void *fh,
                    struct v4l2_dv_timings *timings);
    int (*vidioc_query_dv_timings) (struct file *file, void *fh,
                    struct v4l2_dv_timings *timings);
    int (*vidioc_enum_dv_timings) (struct file *file, void *fh,
                    struct v4l2_enum_dv_timings *timings);
    int (*vidioc_dv_timings_cap) (struct file *file, void *fh,
                    struct v4l2_dv_timings_cap *cap);
    int (*vidioc_g_edid) (struct file *file, void *fh, struct v4l2_edid *edid);
    int (*vidioc_s_edid) (struct file *file, void *fh, struct v4l2_edid *edid);

    int (*vidioc_subscribe_event)  (struct v4l2_fh *fh,
                    const struct v4l2_event_subscription *sub);
    int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh,
                    const struct v4l2_event_subscription *sub);

    /* For other private ioctls */
    long (*vidioc_default)         (struct file *file, void *fh,
                    bool valid_prio, unsigned int cmd, void *arg);
};

ioctl调用总图

TODO

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
杂谈 最近在研究gradle ,插件化~自己碰到的坑很多.今天先总结一下 以下这三个都研究过,原理都是一样的,区别就在于用哪个更方便. 在这里我会讲述一下,这里面的原理和自己爬的坑,以便大家理解,还有少爬坑~~ 原理是需要懂得~ 不然,你遇到错误不会解决,并且你始终会是初级工程师~ 首先,按照顺序,介绍下目前三种热修复的方式: 1.Nuwa (基于gradle写的脚本,操作起来比较麻烦,需要拷贝和运行命令行~) https://github.com/jasonross/Nuwa 2.andfix (看过~
题记——  难过了,悄悄走一走;         伤心了,默默睡一觉;         优雅不是训练出来的,而是一种阅历;         淡然不是伪装出来的,而是一种沉淀;         时间飞逝,老去的只是我们的容颜;         时间仿佛一颗灵魂,越来越动人; 1、简述:     在多线程的世界中,是那么的神奇 与 高效以及合理; 2、创建线程池实例     官方推荐使用Executors类工厂方法来创建线程池管理,Executors类是官方提供的一个工厂类,里面封装了好多功能不一样的线程池,
书接上回,我们已经了解了一些关于适配的一些相关概念,接下来我们会了解一下,在设置布局时我们应该注意的地方。 尽量不去设定具体的尺寸值。 为了确保布局适应各种尺寸的屏幕,在保证功能实现的前提下,最好不要写死一些尺寸,这样的硬编码,我们最好使用“match_parent”,”wrap_content”,”weight”这些不用指定具体的尺寸值的参数,这样视图就会根据自身需要的空间去充填。这样就可以让布局去适应各种屏幕的尺寸,当屏幕有旋转时也不会受到影响。 这里我们重点说一下“weight”,用过 LiearL

艺术般的波浪点击反馈效果 - 2016-07-24 17:07:27

Material Design之Rippledrawable 使用与简单封装(向下兼容至selector) 前言 Android 5.0问世以来,谷歌所推崇的Material Design得到业界的一致好评,其良好的UI规范与交互确实让界面交互友好和漂亮了不少,Rippledrawable便是其中之一,本博客今天着重讲如何将它运用到我们自己的项目中,并且封装得简单易用。 我们都知道,我们在之前做按钮或者布局的反馈效果,一般都用selector来实现,分别指定按下或正常状态的两种颜色即可,我们点击的效果也本
ubuntu环境 首先确定是否安装了Git管理工具 sudo apt-get install git 我选择SSH方式,比较安全方便,只需一次配置 1- 使用ssh命令连接github.com的SSH服务,登录名为git@github.com(所有GitHub用户共享此SSH用户名)。 wangxiong @Dell :~/Public/GitHubRepository/PaPaPlayer $ ssh - T git @github .com The authenticity of host 'gith
         每次看到iOS的远程消息推送,总是感觉很头大,即便后来项目都做完了,还是觉得摸不着远程推送的脉门,网上介绍的资料虽多,但不是写的太简单了,就是写的太详细了,不能一下抓住要点,今天终于能够抽出点时间,来扒一扒这其中究竟有怎样的奥秘。     根据苹果掌控一切的习惯,消息推送也当然不能例外,不论你在哪里推送,也不论你用什么方式推送,都必须首先把消息发给苹果的消息推送服务器APNs(Apple Push Notification Service),然后再由APNs发给指定的设备,也就是说消息推
Day02 Html、Css实战和WebView实现手机显示网页 1.html与css实战 1.1 程序猿小网页 先来看一下效果图 编程用图如下 实现代码如下 !DOCTYPE htmlhtml head meta charset="utf-8" title/title style #pic{ position: relative; float: left; } #text{ width: 400; height: 200; position: relative; float: left; font-si
前言 或许你知道了jni的简单调用,其实不算什么百度谷歌一大把,虽然这些jni绝大多数情况下都不会让我们安卓工程师来弄,毕竟还是有点难,但是我们还是得打破砂锅知道为什么这样干吧,至少也让我们知道调用流程和数据类型以及处理方法,或许你会有不一样的发现。 其实总的来说从java的角度来看.h文件就是java中的interface(插座),然后.c/.cpp文件呢就是实现类罢了,然后数据类型和java还是有点出入我们还是得了解下(妈蛋,天气真热不适合生存了)。 今天也给出一个JNI动态注册native方法的例子

Android渐变标题栏的实现 - 2016-07-24 14:07:56

Android4.4以上推出了Toolbar,改变程序的style属性就可以给手机的标题栏填充颜色,可以是你设置好的系统的主题色,也可以是自己填充的颜色,其实这个效果在iOS早就有了,但在Android中还是很少见的。在iOS中,最常见的Navigationbar的效果就是一个转场动画(多出现于两个界面切换的时候),一个就是随着手势滑动背景渐变(多出现于详情页)。今天我们就来实现下大多出现于详情页的这个渐变效果的标题栏。 具体效果见: 点击打开链接 接下来我们就来实现这个效果。 首先,我们要先把手机上面的
这一篇,承接地八话。使用高效的方式备份短信——xml序列化器。 存储短信,要以对象的方式存储。首先创建javabean: package com.itydl.createxml.domain;public class Message {private String body;private String date;private String address;private String type;public String getBody() {return body;}public void setB