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

Android傳感器簡(jiǎn)介

最近單位項(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)識(shí)傳感器

在我們開始玩?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ī)號(hào)碼不一定能獲取到
        TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
        tv_brand.setText("品牌: " + Build.BRAND + "\n" + "型號(hào): " + Build.MODEL + "\n" + "Android版本: "
                + android.os.Build.VERSION.RELEASE + "\n" + "IMEI: " + tm.getDeviceId()
                + "\n" + "IMSI: " + tm.getSubscriberId() + "\n" + "手機(jī)號(hào)碼: " + tm.getLine1Number() + "\n"
                + "運(yùn)營(yíng)商: " + 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 "電磁場(chǎng)傳感器";
            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 "重場(chǎng)傳感器";
            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 "特殊動(dòng)作觸發(fā)傳感器";
            default:
                return "未知傳感器";
        }
    }
}

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

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

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

傳感器開發(fā)

震動(dòng)傳感器

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

public class VibratorUtils {

    private final Vibrator mVibrator;

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

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

很簡(jiǎn)單,兩句代碼搞定,調(diào)用時(shí)只需要傳入時(shí)間即可,單位是s.(如果我們把時(shí)間調(diào)成好多好多秒,會(huì)不會(huì)有什么神奇的事情發(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í)也非常簡(jiǎn)單,大家可以自行嘗試.

image.png
指紋傳感器

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

public class FingerPrintUtils {

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

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

    public void checkFingerPrint(){
        /**
         * 檢查是否支持指紋識(shí)別
         */
        if(mManagerCompat.hasEnrolledFingerprints()){
            mManagerCompat.authenticate(null, 0, null, new FingerprintManagerCompat.AuthenticationCallback() {
                /**
                 *  出現(xiàn)錯(cuò)誤回調(diào),多次嘗試失敗也會(huì)調(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í)會(huì)回調(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ī)上的自動(dòng)調(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 對(duì)象,這個(gè)對(duì)象中有兩個(gè)方法,當(dāng)傳感器的值發(fā)生變化時(shí),會(huì)調(diào)用onSensorChanged方法,當(dāng)傳感器的精度發(fā)生變化時(shí),會(huì)調(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í)采用的傳感器,手動(dòng)臉紅.

//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, "搖一搖震動(dòng)", Toast.LENGTH_SHORT).show();
    }
}

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

}

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

注冊(cè)監(jiān)聽器的時(shí)候需要在onStart方法中注冊(cè),取消監(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)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容