摇一摇,很简单

从微信使用摇一摇功能开始,大家就一直喜欢这个简单又刺激的功能,无数个单身男女只要摇摇手中的机子,说不定就能找到终身或一晚的伴侣,这是多奇妙的事呀。

不过摇一摇可不止可以用来搜索同时摇晃手机的人,你还能摇一摇转帐打电话发短信,只要想要。

那摇一摇这个功能是怎么实现的呢?

下面就来看看我用摇一摇实现给默认联系人发送短信,其实只要判断手机晃动速度达到一定的程度就会触发相应的事件,然后作操作就可以拉。

import java.util.ArrayList;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

/**
 * 这这个是检测摇一摇的类
 * @author asdzheng
 */
public class ShakeSensorManager implements SensorEventListener {

    private static final int DEFAULT_THRESHOLD_ACCELERATION = 15;
    private static final int INTERVAL = 400;

    private static SensorManager mSensorManager;
    private static ShakeSensorManager mSensorEventListener;

    private OnShakeListener mShakeListener;
    private Object mLock;
    private float mThresholdAcceleration;

    private ArrayList<SensorBundle> mSensorBundles;

    //回调接口
    public static interface OnShakeListener {
        /**
         * 当检测到摇一摇时调用此方法
         */
        public void OnShake();
    }

    //初始化类
    public static boolean create(Context context, OnShakeListener listener) {
        if (context == null) {
            throw new IllegalArgumentException("Context must not be null");
        }

        if (mSensorManager == null) {
            mSensorManager = (SensorManager) context.getSystemService(
                                                        Context.SENSOR_SERVICE);
        }
        mSensorEventListener = new ShakeSensorManager(listener);

        return true;
    }

    //初始化
    private ShakeSensorManager(OnShakeListener listener) {
        if (listener == null) {
            throw new IllegalArgumentException("Shake listener must not be null");
        }

        mSensorBundles = new ArrayList<SensorBundle>();

        mShakeListener = listener;
        mLock = new Object();
        mThresholdAcceleration = DEFAULT_THRESHOLD_ACCELERATION;
    }

    //注册监听器,registerListener最后一个参数是触发后,多久回调函数,我这里选择的是快速
    public static boolean start() {
        if (mSensorManager != null && mSensorEventListener != null) {
            return .registerListener(mSensorEventListener,
                    mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_FASTEST);
        }
        return false;
    }

    //撤销监听器
    public static void stop() {
        if (mSensorManager != null) {
            mSensorManager.unregisterListener(mSensorEventListener);
        }
    }

    /**
     * 释放所有之前用到的类
     */
    public static void destroy() {
        mSensorManager = null;
        mSensorEventListener = null;
    }

    //更新检测摇晃手机的敏感度,越大越不敏感
    public static void updateConfiguration(int sensibility) {
        mThresholdAcceleration = sensibility;
    }

    //这个类是传感器检测到摇晃手机时调用的方法,并把数据sensorEvent里
    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
       SensorBundle sensorBundle = new SensorBundle(sensorEvent.values[0],
                sensorEvent.values[1],
                sensorEvent.values[2],
                sensorEvent.timestamp);

        synchronized (mLock) {
            if (mSensorBundles.size() == 0) {
                mSensorBundles.add(sensorBundle);
            } else if (
                sensorBundle.getTimestamp()
                    - mSensorBundles.get(mSensorBundles.size() - 1).getTimestamp() > INTERVAL) {
                //这个判断是防止摇晃手机时多次调用此方法
                performCheck(sensorBundle);
            }
        }

    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {
        //这个方法是当换掉感应器时才会触发,基本不会调用
    }

    //判断是否执行摇晃之后的操作
    private void performCheck(SensorBundle sensorBundle) {
        synchronized (mLock) {
            if (Math.abs(sensorBundle.getXAcc()) > mThresholdAcceleration
                    || Math.abs(sensorBundle.getYAcc()) > mThresholdAcceleration
                    || Math.abs(sensorBundle.getZAcc()) > mThresholdAcceleration) {
                mShakeListener.OnShake();
            }
        }
    }

    //这个是手机传感器的回调回来的数据
    private class SensorBundle {

        // x轴方向的重力加速度,向右为正
        // y轴方向的重力加速度,向前为正
        // z轴方向的重力加速度,向上为正

        /**
         * The acceleration on X axis.
         */
        private final float mXAcc;
        /**
         * The acceleration on Y axis.
         */
        private final float mYAcc;
        /**
         * The acceleration on Z axis.
         */
        private final float mZAcc;
        /**
         * The timestamp when to record was captured.
         */
        private final long mTimestamp;

        public SensorBundle(float XAcc, float YAcc, float ZAcc, long timestamp) {
            mXAcc = XAcc;
            mYAcc = YAcc;
            mZAcc = ZAcc;
            mTimestamp = timestamp;
        }

        public float getXAcc() {
            return mXAcc;
        }

        public float getYAcc() {
            return mYAcc;
        }

        public float getZAcc() {
            return mZAcc;
        }

        public long getTimestamp() {
            return mTimestamp;
        }

    }
}

下面这个类是主页面,也是唯一页面,先来看它的截图。

下面再来看主页面的代码:

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.db.ShakeSqliteHelper;
/**
 * asdzheng 这是界面
 */
public class MainActivity extends Activity {

    private String telnum = "";

    private SQLiteDatabase dbWriter;// 获得数据库可写操作的对象
    private SQLiteDatabase dbReader;
    private ShakeSqliteHelper mySqlite;// 声明继承自SQLiteOpenHelper类的MySqklite

    private ImageView iv_head;
    private TextView tv_name;
    private TextView tv_num;
    private Button btn_pick;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mySqlite = new ShakeSqliteHelper(this);// 实例化MySqklite对象
        dbWriter = mySqlite.getWritableDatabase();// 获得数据库可写操作权限
        dbReader = mySqlite.getReadableDatabase();
        initView();

        //检测到摇一摇是在服务里,这样即使退出这个界面,依旧可以检测到摇一摇
        startService(new Intent(this, ShakeService.class));
    }

    private void initView() {
        iv_head = (ImageView) findViewById(R.id.iv_head);
        tv_name = (TextView) findViewById(R.id.tv_name);
        tv_num = (TextView) findViewById(R.id.tv_telnum);
        btn_pick = (Button) findViewById(R.id.btn_pick);
        btn_pick.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_PICK,
                        ContactsContract.Contacts.CONTENT_URI);
                startActivityForResult(intent, 1);
            }
        });
        getUserInfoFromDB();
    }

    //先从数据库里面取出看是否有以及设置默认联系人
    private void getUserInfoFromDB() {
        String name = "";
        String imagePath = "";
        // 游标存储数据
        Cursor cursor = dbReader.query(ShakeSqliteHelper.USER_TABLE, null,
                null, null, null, null, null);

        while (cursor.moveToNext()) {// 判断游标的移动
            telnum = cursor.getString(cursor
                    .getColumnIndex(ShakeSqliteHelper.COLUMN_NUM));
            name = cursor.getString(cursor
                    .getColumnIndex(ShakeSqliteHelper.COLUMN_NAME));
            imagePath = cursor.getString(cursor
                    .getColumnIndex(ShakeSqliteHelper.COLUMN_PATH));
        }

        setUserInfo(name, imagePath);
    }

    //如果有的话就设置进界面
    private void setUserInfo(String name, String imagePath) {
        tv_name.setText(name);
        tv_num.setText(telnum);

        if (imagePath == null || imagePath.isEmpty()) {
            iv_head.setImageResource(R.drawable.ic_launcher);
        } else {
            iv_head.setImageURI(Uri.parse(imagePath));
        }
    }

    //这是选择联系人后取得返回来的姓名和电话头像图片路径信息
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
            Uri contactData = data.getData();
            Cursor cursor = getContentResolver().query(contactData, null, null,
                    null, null);
            if (cursor.moveToFirst()) {
                String id = cursor.getString(
                    cursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID)
                );
                String hasPhone = cursor.getString(
                    cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)
                );

                if (hasPhone.equalsIgnoreCase("1")) {
                    Cursor phones = getContentResolver().query(
                            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                            null,
                            ContactsContract.CommonDataKinds.Phone.CONTACT_ID+ " = " + id,
                            null, null);
                    phones.moveToFirst();
                    telnum = phones.getString(phones.getColumnIndex("data1"));
                }
                String name = cursor.getString(
                    cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
                );
                String imagePath = cursor.getString(
                    cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_URI)
                );

                setUserInfo(name, imagePath);
                addUserToDB(name, imagePath);
            }
        }
    }

    //成功获取联系人数据后将数据插入数据库
    private void addUserToDB(String name, String imagePath) {
        String[] args = { "1", name, telnum, imagePath == null ? "" : imagePath };

        dbWriter.execSQL("INSERT OR REPLACE INTO "
                + ShakeSqliteHelper.USER_TABLE + " ("
                + ShakeSqliteHelper.COLUNN_ID + ","
                + ShakeSqliteHelper.COLUMN_NAME + ", "
                + ShakeSqliteHelper.COLUMN_NUM + ","
                + ShakeSqliteHelper.COLUMN_PATH + ") VALUES (?, ?, ?, ?)", args);

    }
}

现在就到了检测摇一摇事件,并给默认联系人发短信的服务啦

import android.app.Service;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.IBinder;
import android.os.Vibrator;
import android.widget.Toast;

import com.example.db.ShakeSqliteHelper;
import com.example.lib.ShakeSensorManager;
import com.example.lib.ShakeSensorManager.OnShakeListener;

/**
 * @author asdzheng
 */
public class ShakeService extends Service implements OnShakeListener {
    //这是实现震动的vibrator
    private Vibrator vibrator;
    //这是设置检测摇一摇的敏感度
    private static final int SENSOR_SHAKE = 17;

    private SQLiteDatabase dbReader;// 获得数据库可写操作的对象

    @Override
    public void onCreate() {
        //初始化服务
        vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
        if (ShakeSensorManager.create(this, this)) {
            ShakeSensorManager.updateConfiguration(SENSOR_SHAKE);
        }
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //注册监听器
        ShakeSensorManager.start();
        dbReader = new ShakeSqliteHelper(this).getReadableDatabase();
        Toast.makeText(ShakeService.this, "Service Start", Toast.LENGTH_SHORT).show();

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        //注销检测器
        ShakeSensorManager.stop();
        ShakeSensorManager.destroy();
        Toast.makeText(ShakeService.this, "Service Destory", Toast.LENGTH_SHORT).show();
        super.onDestroy();
    }

    //检测到摇一摇后的回调函数,震动并发送短信
    @Override
    public void OnShake() {
        vibrator.vibrate(200);
        跳到发送界面短信
        sendMsg();
    }

    private void sendMsg() {
        String telnum = getTelNum();

        if (telnum.isEmpty()) {
            return;
        }

        Uri msgUri = Uri.fromParts("sms", telnum, null);
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.setData(msgUri);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

    //获取电话号码
    private String getTelNum() {
        String telnum = "";
        // 游标存储数据
        Cursor cursor = dbReader.query(ShakeSqliteHelper.USER_TABLE, null, null,
                            null, null, null, null);

        while (cursor.moveToNext()) {// 判断游标的移动
            telnum = cursor.getString(cursor.getColumnIndex("telnum"));
        }
        return telnum;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

}

最后别忘了设置震动和读取联系人信息的权限:

    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.READ_CONTACTS"/>

这样一个摇一摇发短信的Demo就差不多完成了,我想它这个应用场景是如果你经常给某一人发短信打电话发短信,想简单快速的达到这点,就可以用这个DEMO拉。

DEMO下载地址

时间: 2024-10-14 03:49:31

摇一摇,很简单的相关文章

一个简单的HTML5摇一摇实例

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/ DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type"

蓝牙Ibeacon室内定位和微信摇一摇周边原理分析

苹果推出Ibeacon室内定位技术是为了弥补GPS无法覆盖室内定位这种场景.苹果意味着创新,在其推动下,蓝牙Ibeacon得到了极大的应用.而腾讯则是利用蓝牙Ibeacon在场景体验方面进行了创新,实现了微信摇一摇周边的功能,这在O2O领域有巨大的潜力. 对苹果和腾讯来说,Ibeacon都是应用创新,而不是技术创新. 本文分析Ibeacon室内定位和微信摇一摇的原理. 一.无线测距原理 无线信号都有一个信号强度(RSSI),蓝牙BLE自然也有.根据蓝牙BLE自身的发射功率(假设能够获取这个功率值

HTML5 摇一摇加强版之一次失败的探索

最近在看设备传感器的API,当然也少不了研究一下让微信称神的“摇一摇”了.关于“摇一摇”的实现,网上很多资料所以不详细说了,但总是有布局.效果不全等各种问题,所以作为一名资深copypaster,代码肯定是要贴的: 源码在此 核心代码是这一段: this.deviceMotionHandler = function(eventData) { var acceleration = eventData.acceleration; var curTime = new Date().getTime();

央视春晚摇一摇最有可能颠覆哪些行业?

昨 晚,全国人民都在跟随着央视春晚摇动着手机.摇啊摇,有的摇出了红包,有的摇出了卡券.开玩笑的说,国家体育总局花了二十年没有搞起来的全民健身运动,微 信只花了一个晚上就达到目的了.其中22:30央视春晚摇一摇送红包这波,微信总摇一摇次数达72亿次,峰值高达一分钟8.1亿次(22:34),送出红 包1.2亿个,背后是牛逼的技术和强大的商业逻辑. 我 必须要为“春晚摇一摇”点32个赞.其一是升级了红包的概念,将微信红包从用户个人行为转向为企业营销行为,商业化才是最有前途的:其二是解放了摇一摇功 能,

Android加速度传感器的使用:摇一摇功能的实现

一.原理介绍: Android手机中摇一摇的功能已经很常见了,最近接触到了这个功能,原理很简单:使用加速度传感器,在晃动手机时,监听加速度在各个方向的变化,当加速度值超过设定的灵敏度时,则触发摇一摇功能. 二.使用到的类: SensorManager SensorEventListener 三.功能实现: 1.摇一摇功能:我将摇一摇功能封装成了一个类ShakeUtils,在使用时按照注释中的说明使用即可,ShakeUtils.java如下(差的包请CTRL+SHIFT+O导入): /** * 摇

微信企业号开发:微信考勤摇一摇考勤

看到网上又不好微信企业号的摇一摇考勤,自己也想做一个,但查遍了微信企业号文档,也没有看到摇一摇的相关API,本以为做不出来了,想不到再问了同事后,才知道其实很简单,摇一摇不需要微信企业号的文档,HTML5就有,摇一摇其实就是相当于点击了保存按钮而已. 其实获取地理位置HTML5也支持. HTML5 - 使用地理定位 <script> var x=document.getElementById("demo"); function getLocation() { if (nav

Android 微信摇一摇功能实现

开发之前 今天学习了一下传感器, 脑子里就蹦出了微信的摇一摇, 于是鼓了鼓勇气抽空写了出来, 本人菜鸟一枚, 希望大神们多多指点 开发环境 Android Studio 2.2.1 JDK1.7 API 24 Gradle 2.2.1 相关知识点 加速度传感器 补间动画 手机震动 (Vibrator) 较短 声音/音效 的播放 (SoundPool) 开始开发 案例预览 案例分析 我们接下来分析一下这个案例, 当用户晃动手机时, 会触发加速传感器, 此时加速传感器会调用相应接口供我们使用, 此时

摇一摇 iOS

//微信的摇一摇是怎么实现的~发现原来 ios本身就支持//在 UIResponder中存在这么一套方法 - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event __OSX_AV

微信摇一摇实现原理,视图展示

一: 实现原理 在 UIResponder中存在这么一套方法 - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event __OSX_AVAILABLE_STARTING(__MAC