Android傳感器開發(fā)(上)

Android傳感器簡介

最近單位項(xiàng)目遇到了搖一搖功能,正好把以前的筆記翻出來,整合到一起,發(fā)個(gè)文章,來吧,互相傷害吧.
<br />
本文代碼已上傳至Github:https://github.com/Xxxxxxyk/SensorDev
<br />
你真的了解我們?nèi)粘J褂玫氖謾C(jī)么? 平常你在玩微信搖一搖,手電筒,計(jì)步器的時(shí)候有沒有想過這些是怎么實(shí)現(xiàn)的呢?其實(shí)這些都?xì)w功于手機(jī)內(nèi)部的各種硬件傳感器.

image.png

認(rèn)識傳感器

在我們開始玩?zhèn)鞲衅髦?我們先來看下我們的手機(jī)中都有什么傳感器.

//獲取手機(jī)基本狀態(tài)及所有傳感器
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hardlist);
        TextView tv_brand = (TextView) findViewById(R.id.tv_brand);

        //手機(jī)號碼不一定能獲取到
        TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
        tv_brand.setText("品牌: " + Build.BRAND + "\n" + "型號: " + Build.MODEL + "\n" + "Android版本: "
                + android.os.Build.VERSION.RELEASE + "\n" + "IMEI: " + tm.getDeviceId()
                + "\n" + "IMSI: " + tm.getSubscriberId() + "\n" + "手機(jī)號碼: " + tm.getLine1Number() + "\n"
                + "運(yùn)營商: " + tm.getSimOperatorName() + "\n");

        sm = (SensorManager) getSystemService(SENSOR_SERVICE);
        List<Sensor> allSensors = sm.getSensorList(Sensor.TYPE_ALL);// 獲得傳感器列表
        RecyclerView rl_list = (RecyclerView) findViewById(R.id.rv_list);
        rl_list.setLayoutManager(new LinearLayoutManager(this));
        rl_list.setAdapter(new SensorAdapter(this,allSensors));
    }

適配器:

public class SensorAdapter extends RecyclerView.Adapter<SensorAdapter.SensorViewHolder> {

    private final Context context;
    private final List<Sensor> sensors;

    public SensorAdapter(Context context, List<Sensor> sensors) {
        this.context = context;
        this.sensors = sensors;
    }

    @Override
    public SensorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        SensorViewHolder viewHolder = new SensorViewHolder(LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, null));
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(SensorViewHolder holder, int position) {
        holder.mTv_text.setText("類型:" + getChineseName(sensors.get(position).getType()) + "\n" + "設(shè)備名稱:" + sensors.get(position).getName() + "\n設(shè)備版本" + sensors.get(position).getVersion() + "\n");
    }

    @Override
    public int getItemCount() {
        return sensors == null ? 0 : sensors.size();
    }

    class SensorViewHolder extends RecyclerView.ViewHolder {

        private final TextView mTv_text;

        public SensorViewHolder(View itemView) {
            super(itemView);
            mTv_text = (TextView) itemView.findViewById(android.R.id.text1);
        }
    }

    public String getChineseName(int type) {
        switch (type) {
            case Sensor.TYPE_ACCELEROMETER:
                return "加速度傳感器";
            case Sensor.TYPE_GYROSCOPE:
                return "陀螺儀傳感器";
            case Sensor.TYPE_LIGHT:
                return "環(huán)境光線傳感器";
            case Sensor.TYPE_MAGNETIC_FIELD:
                return "電磁場傳感器";
            case Sensor.TYPE_ORIENTATION:
                return "方向傳感器";
            case Sensor.TYPE_PRESSURE:
                return "壓力傳感器";
            case Sensor.TYPE_PROXIMITY:
                return "距離傳感器";
            case Sensor.TYPE_TEMPERATURE:
                return "溫度傳感器";
            case Sensor.TYPE_GRAVITY:
                return "重場傳感器";
            case Sensor.TYPE_LINEAR_ACCELERATION:
                return "線性加速度傳感器";
            case Sensor.TYPE_ROTATION_VECTOR:
                return "旋轉(zhuǎn)矢量傳感器";
            case Sensor.TYPE_RELATIVE_HUMIDITY:
                return "濕度傳感器";
            case Sensor.TYPE_AMBIENT_TEMPERATURE:
                return "溫度傳感器";
            case Sensor.TYPE_GAME_ROTATION_VECTOR:
                return "游戲旋轉(zhuǎn)矢量傳感器";
            case Sensor.TYPE_STEP_COUNTER:
                return "計(jì)步器";
            case Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR:
                return "地磁旋轉(zhuǎn)矢量傳感器";
            case Sensor.TYPE_SIGNIFICANT_MOTION:
                return "特殊動作觸發(fā)傳感器";
            default:
                return "未知傳感器";
        }
    }
}

寫好之后我們來運(yùn)行試一下:

Screenshot_2017-06-27-16-07-52.jpg

樓主用自己手機(jī)進(jìn)行測試的,華為榮耀8(吐槽一句,真難用),基本所有的傳感器都被識別了,沒有識別的兩個(gè)一個(gè)是霍爾傳感器(HALL),另一個(gè)是電話傳感器(PhoneCall).

傳感器開發(fā)

震動傳感器

官方文檔:https://developer.android.google.cn/reference/android/os/Vibrator.html
震動傳感器,顧名思義,手機(jī)振動全靠它,那么我們?nèi)绾慰刂莆覀兊氖謾C(jī)震動呢,上代碼:

public class VibratorUtils {

    private final Vibrator mVibrator;

    //震動傳感器
    public VibratorUtils(Context context){
        //獲取系統(tǒng)服務(wù)
        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
    }

    //震動,time為震動時(shí)間
    public void shock(long time){
        mVibrator.vibrate(time);
    }
}

很簡單,兩句代碼搞定,調(diào)用時(shí)只需要傳入時(shí)間即可,單位是s.(如果我們把時(shí)間調(diào)成好多好多秒,會不會有什么神奇的事情發(fā)生呢,我這么純潔肯定不知道)

image.png
閃光燈

官方文檔:https://developer.android.google.cn/reference/android/hardware/camera2/CameraManager.html
好了好了,不開車,接下來我們看看我們平常使用的手電筒是怎么實(shí)現(xiàn)的,需要注意的是,以下代碼只運(yùn)行在API21以上,并且你有閃光燈:

public class FlashLampUtils {

    //閃光燈
    private final CameraManager mSystemService;

    public FlashLampUtils(Context context) {
        //獲取系統(tǒng)服務(wù)
        mSystemService = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
    }

    @TargetApi(Build.VERSION_CODES.M)
    public void openLamp(){
        if(!isLOLLIPOP()){
            return;
        }
        try {
            mSystemService.setTorchMode("0", true);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @TargetApi(Build.VERSION_CODES.M)
    public void closeLamp(){
        if(!isLOLLIPOP()){
            return;
        }
        try {
            mSystemService.setTorchMode("0", false);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 判斷Android系統(tǒng)版本
     *
     * @return boolean
     */
    private boolean isLOLLIPOP() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return true;
        } else {
            return false;
        }
    }
}

只需要調(diào)用,閃光燈就可以亮起來了,除此之外,很多手機(jī)中都有手電筒的SOS功能,其實(shí)也非常簡單,大家可以自行嘗試.

image.png
指紋傳感器

官方文檔:https://developer.android.google.cn/reference/android/support/v4/hardware/fingerprint/package-summary.html
Google在API 23之后在官方API中加入了指紋API,方便用戶進(jìn)行指紋的一系列操作,那么我們怎么給我們自己的APP加入指紋功能呢,代碼如下:

public class FingerPrintUtils {

    //指紋傳感器
    public static final String TAG = "惜夢哥哥_";
    private final FingerprintManagerCompat mManagerCompat;

    public FingerPrintUtils(Context context) {
        mManagerCompat = FingerprintManagerCompat.from(context);
    }

    public void checkFingerPrint(){
        /**
         * 檢查是否支持指紋識別
         */
        if(mManagerCompat.hasEnrolledFingerprints()){
            mManagerCompat.authenticate(null, 0, null, new FingerprintManagerCompat.AuthenticationCallback() {
                /**
                 *  出現(xiàn)錯(cuò)誤回調(diào),多次嘗試失敗也會調(diào)用
                 */
                @Override
                public void onAuthenticationError(int errMsgId, CharSequence errString) {
                    Log.e(TAG,errMsgId + "--------" + errString.toString());
                }

                /**
                 *  錯(cuò)誤信息提示
                 */
                @Override
                public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
                    Log.e(TAG,helpMsgId + "--------" + helpString.toString());
                }

                /**
                 *  當(dāng)驗(yàn)證的指紋成功時(shí)會回調(diào)此函數(shù)包警,然后取消監(jiān)聽
                 */
                @Override
                public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
                    Log.e(TAG,"驗(yàn)證成功");
                }

                /**
                 * 指紋驗(yàn)證失敗
                 */
                @Override
                public void onAuthenticationFailed() {
                    Log.e(TAG,"驗(yàn)證失敗");;
                }
            }, null);
        };
    }
}

這里驗(yàn)證的指紋就是你在系統(tǒng)中設(shè)置的指紋,可以在回調(diào)中進(jìn)行不同操作.

image.png
光線傳感器

官方文檔:https://developer.android.google.cn/reference/android/hardware/Sensor.html#TYPE_LIGHT
光線傳感器是用來感應(yīng)手機(jī)周圍的亮度的,我們的手機(jī)上的自動調(diào)整亮度功能離不開這個(gè)傳感器,讓我們來看下你的周圍的亮度有多少吧

public class LightUtils {
    private final Sensor mDefaultSensor;
    private final SensorManager mSystemService;

    //光線傳感器

    public LightUtils(Context context) {
        mSystemService = (SensorManager) context.getSystemService(SENSOR_SERVICE);
        mDefaultSensor = mSystemService.getDefaultSensor(Sensor.TYPE_LIGHT);

    }

    public void getLightNum(SensorEventListener sensorEventListener) {
        mSystemService.registerListener(sensorEventListener, mDefaultSensor, SensorManager.SENSOR_DELAY_UI);
    }
}

調(diào)用時(shí)需要傳入SensorEventListener 對象,這個(gè)對象中有兩個(gè)方法,當(dāng)傳感器的值發(fā)生變化時(shí),會調(diào)用onSensorChanged方法,當(dāng)傳感器的精度發(fā)生變化時(shí),會調(diào)用onAccuracyChanged,這里我們只需要在onSensorChanged方法中處理我們的操作就可以

 @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        mBtn_light.setText("當(dāng)前亮度" + sensorEvent.values[0]);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }
image.png
加速傳感器

官方文檔:https://developer.android.google.cn/reference/android/hardware/Sensor.html#TYPE_ACCELEROMETER
加速傳感器,就是我們平常進(jìn)行搖(YUE)一(PAO)搖時(shí)采用的傳感器,手動臉紅.

//SensorManager代表了各類傳感器的集合
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
if (mSensorManager != null) {
    //加速傳感器
    mMSensorManagerDefaultSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    if (mMSensorManagerDefaultSensor != null) {
        mSensorManager.registerListener(this, mMSensorManagerDefaultSensor, SensorManager.SENSOR_DELAY_UI);
    }
}

加載完成傳感器之后在回調(diào)方法中進(jìn)行操作

private static final int UPTATE_INTERVAL_TIME = 50;
//靈敏度調(diào)節(jié)
private static final int SPEED_SHRESHOLD = 30;
private long lastUpdateTime;
private float lastX;
private float lastY;
private float lastZ;

........

@Override
public void onSensorChanged(SensorEvent sensorEvent) {
    long currentUpdateTime = System.currentTimeMillis();
    long timeInterval = currentUpdateTime - lastUpdateTime;
    if (timeInterval < UPTATE_INTERVAL_TIME) {
        return;
    }
    lastUpdateTime = currentUpdateTime;
    // 傳感器信息改變時(shí)執(zhí)行該方法
    float[] values = sensorEvent.values;
    float x = values[0]; // x軸方向的重力加速度,向右為正
    float y = values[1]; // y軸方向的重力加速度诞挨,向前為正
    float z = values[2]; // z軸方向的重力加速度莉撇,向上為正
    float deltaX = x - lastX;
    float deltaY = y - lastY;
    float deltaZ = z - lastZ;

    lastX = x;
    lastY = y;
    lastZ = z;
    double speed = (Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / timeInterval) * 100;
    if (speed >= SPEED_SHRESHOLD) {
        mVibrator.vibrate(300);
        Toast.makeText(this, "搖一搖震動", Toast.LENGTH_SHORT).show();
    }
}

@Override
public void onAccuracyChanged(Sensor sensor, int i) {

}

這里有個(gè)坑,大家要注意啦:

注冊監(jiān)聽器的時(shí)候需要在onStart方法中注冊,取消監(jiān)聽器需在onPause方法中取消,原因是因?yàn)锳ctivity的生命周期問題,避免按Home鍵之后感應(yīng)依舊存在,造成不必要的Bug.
@Override
protected void onStart() {
    super.onStart();
    shake();
}

@Override
protected void onPause() {
    if (mSensorManager != null) {
        mSensorManager.unregisterListener(this);
    }
    super.onPause();
}
image.png

結(jié)尾

好了,本次就介紹這個(gè)5個(gè)傳感器吧,希望大家可以嘗試一下,因?yàn)檫@個(gè)真的很好玩喲.最后再推薦一首歌,英文歌,但是真的很好聽:

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市惶傻,隨后出現(xiàn)的幾起案子棍郎,更是在濱河造成了極大的恐慌,老刑警劉巖银室,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涂佃,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜈敢,警方通過查閱死者的電腦和手機(jī)辜荠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抓狭,“玉大人伯病,你說我怎么就攤上這事》觯” “怎么了狱从?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叠纹。 經(jīng)常有香客問我季研,道長,這世上最難降的妖魔是什么誉察? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任与涡,我火速辦了婚禮,結(jié)果婚禮上持偏,老公的妹妹穿的比我還像新娘驼卖。我一直安慰自己,他們只是感情好鸿秆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布酌畜。 她就那樣靜靜地躺著,像睡著了一般卿叽。 火紅的嫁衣襯著肌膚如雪桥胞。 梳的紋絲不亂的頭發(fā)上恳守,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音贩虾,去河邊找鬼催烘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛缎罢,可吹牛的內(nèi)容都是我干的伊群。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼策精,長吁一口氣:“原來是場噩夢啊……” “哼舰始!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蛮寂,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蔽午,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后酬蹋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體及老,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年范抓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了骄恶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡匕垫,死狀恐怖僧鲁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情象泵,我是刑警寧澤寞秃,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站偶惠,受9級特大地震影響春寿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜忽孽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一绑改、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兄一,春花似錦厘线、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至骂束,卻和暖如春耳璧,著一層夾襖步出監(jiān)牢的瞬間硝全,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工楞抡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人析藕。 一個(gè)月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓召廷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親账胧。 傳聞我的和親對象是個(gè)殘疾皇子竞慢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評論 25 707
  • afinalAfinal是一個(gè)android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,429評論 2 45
  • JQuery源碼分析 我們通過對jQuery1.4.2版本的分析治泥,了解jQuery原理 最外層 將代碼放到匿名函數(shù)...
    whitsats閱讀 1,667評論 0 2
  • 我曾在林中送走夕陽筹煮, 卻不曾在花間迎你; 今天我看了白雪紛紛居夹, 卻感受不到你的冷暖败潦。 柔軟的雪地, 我寫下你准脂, 共...
    納人閱讀 627評論 13 17
  • 昨天從家出發(fā)的時(shí)候劫扒,我與父親在外邊等車,父親在囑咐我一些事情狸膏,明顯可以感覺到他心里的不舍沟饥。他說一年到頭才回來,沒錢...
    語書閱讀 144評論 0 2