Android蓝牙开发(二)---界面设计

前言


在上一篇博文中,针对Android的蓝牙基础知识作了一个简单的梳理。在正式的APP开发过程中,知识转换成成用户能够看得见、摸得着的才能生产力最大化。本章主要针对蓝牙设备的搜索界面作简要的设计、开发。


一、蓝牙搜索界面


通常在APP内的蓝牙搜索中,选择Dialog+listview的方式来显示蓝牙设备的搜索即简洁又美观。常用的Dialog、Listview无法满足需求,因此需要客制化自行封装,以后也可以将这些方法作为一个简易的封装类供其他的项目或者代码参考。


蓝牙搜索界面

1.1 MyDialog封装


Dialog的封装主要包含两个方面,style和尺寸的封装。

  1. style
    style的封装主要是对Dialog的显示作简要的修改,在res\values\styles.xml中添加以下代码:
    <style name="my_dialog" parent="android:Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowBackground">@color/white</item>
    </style>
  1. list item
    btDevice_list_item.xml主要用于Dialog中的Listview的item布局,每一个item共有三种属性:name,address,bonded,即蓝牙设备名,蓝牙地址,是否绑定。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/bt_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="蓝牙名称"
        android:layout_marginStart="43dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true" />

    <TextView
        android:id="@+id/bt_addr"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="蓝牙地址"
        android:layout_alignParentTop="true"
        android:layout_alignStart="@+id/bt_name"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="5dp"/>

    <TextView
        android:id="@+id/bt_bonded"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="已绑定"
        android:layout_marginEnd="23dp"
        android:layout_centerVertical="true"
        android:layout_alignParentEnd="true" />
</RelativeLayout>
  1. MyDialog封装
    此自定义的Dialog可以作为后续的其他项目或者其他类型的Dialog类的封装,根据不同的需求,设定其theme即可。
public class MyDialog extends Dialog{
    // 这种适合通用
    public MyDialog(Context context) {
        super(context);
    }
    // 自定义提醒框样式
    public MyDialog(Context context, int themeResId) {
        super(context, themeResId);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}
  1. MyDialog的尺寸大小
    自定义一个合适的尺寸,满足需求即可,用户或者爱好者可以根据自己的需求及喜好自定义类似的Dialog框图大小及样式。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:background="@color/white"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:textColor="@color/aliceblue"
        android:text="蓝牙设备"
        android:textSize="20sp"
        android:textStyle="bold"
        android:background="@color/purple"/>
    <ListView
        android:id="@+id/bt_device_list"
        android:divider="@color/blue"
        android:dividerHeight="0.5dp"
        android:padding="10dp"
        android:clickable="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/bt_dialog_cancel"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="取消"
        android:textColor="@color/aliceblue"
        android:background="@color/purple"
        android:textStyle="bold"
        android:textSize="20sp"
        android:gravity="center"/>
</LinearLayout>

至此,显示界面已经完成。


二、蓝牙设备搜索


2.1 蓝牙设备的适配器

因添加Listview类,对listview的添加、点击、构建、移除等数据都需要绑定适配器,因此首要的任务根据业务需求自定义适配器。

public class BTDeviceAdapter extends BaseAdapter{
    private static final String TAG = "first";
    private Context context;
    private LayoutInflater mInflater;
    private List<BluetoothDevice> list;
    private BluetoothDevice device;

    private static class ViewHolder{
        TextView btNameView;
        TextView btAddrView;
        TextView btBondedView;
    }

    //构造函数
    public BTDeviceAdapter(final Context context, final List<BluetoothDevice> list){
        super();
        this.context = context;
        this.list = list;
        mInflater = LayoutInflater.from(context);
    }
    //device list大小
    @Override
    public int getCount() {
        return list.size();
    }
    //device在list中的位置
    @Override
    public Object getItem(int position) {
        return list.get(position);
    }
    //device在list中的id
    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        //设备是否已经绑定
        device = list.get(position);
        //如果缓存convertView为空,则需要创建View
        if (convertView == null) {
            // view创建
            convertView = mInflater.inflate(R.layout.btdevice_list_item, null);
            holder = new ViewHolder();

            holder.btNameView = (TextView) convertView.findViewById(R.id.bt_name);
            holder.btAddrView = (TextView) convertView.findViewById(R.id.bt_addr);
            holder.btBondedView = (TextView) convertView.findViewById(R.id.bt_bonded);

            convertView.setTag(holder);
        }else {
            holder = (ViewHolder) convertView.getTag();
        }
        //view属性设置
        holder.btNameView.setText(device.getName());
        holder.btAddrView.setText(device.getAddress());

        if (device.getBondState() == BluetoothDevice.BOND_BONDED){
            Log.i(TAG, "设备:" + device.getName() + "已绑定");
            holder.btBondedView.setVisibility(View.VISIBLE);
            holder.btBondedView.setTextColor(Color.RED);
        }else {
            holder.btBondedView.setVisibility(View.INVISIBLE);
        }
        return convertView;
    }
}

2.2 蓝牙设备搜索

在所有的工作准备完成后,进入Activity或者fragment中进行蓝牙button的点击搜索工作。
手机蓝牙因为会保存之前已经配对的蓝牙设备,因此可以选择对这些已配对的设备添加到list中,下方附上主要部分的代码。

2.2.1 添加已配对的蓝牙设备

//将已经存在的配对设备先加入列表
 Set<BluetoothDevice> bondedDevices = adapter.getBondedDevices();
  Log.e(TAG, "已绑定设备数为:" + bondedDevices.size());

  if (bondedDevices.size() != 0) {
        Iterator<BluetoothDevice> iterator = bondedDevices.iterator();
         while (iterator.hasNext()) {
           mlist.add((BluetoothDevice) iterator.next());
      }
  }
 Log.e(TAG,"mlist:" + mlist);//搜索前先将手机以前配对的蓝牙设备列表打印

2.2.2 蓝牙设备搜索并添加

首先将dialog中的listview初始化,并关联适配器。

deviceAdapter = new BTDeviceAdapter(mActivity, mlist);
bt_device_list = (ListView) dialog.findViewById(R.id.bt_device_list);
bt_device_list.setAdapter(deviceAdapter);
adapter.startDiscovery();

2.2.3 蓝牙设备开启广播并添加蓝牙设备到listview

此过程是一个动态添加的过程,在此代码中包括搜索和完成的intent判断。

/**
     * 设置静态广播,主要用于接收蓝牙搜索的结果
     */
    @Override
    public void onResume() {
        super.onResume();
        //广播过滤
        filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        filter.setPriority(Integer.MAX_VALUE);//设置广播的优先级最大

        receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                try{
                    String action = intent.getAction();
                    Log.e(TAG,"接收到蓝牙广播!" + "action = " + action);
                    switch (action) {
                        case BluetoothDevice.ACTION_FOUND:
                            final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                            if (device.getName() != null && device != null) {
                                Log.i(TAG, "device Name: " + device.getName());
                                Log.i(TAG, "device Addr: " + device.getAddress());
                             
                                    mActivity.runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            Log.e(TAG, "开始添加设备!");
                                            addDevice(device);
                                        }
                                    });
                            }
                            break;
                        case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
                            System.out.println("ACTION_DISCOVERY_FINISHED");
                            Log.e(TAG, "扫描完成!");
                            if (mActivity instanceof Activity) {
                                mActivity.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        Log.e(TAG, "finished 开始添加设备!");
                                        Set<BluetoothDevice> paired = adapter.getBondedDevices();
                                        Log.e(TAG, "paired = " + paired);
                                        if (paired != null && paired.size() > 0) {
                                            for (BluetoothDevice bonded : paired) {
                                                if (mlist.indexOf(bonded) == -1) {
                                                    mlist.add(bonded);
                                                    deviceAdapter.notifyDataSetChanged();
                                                }
                                            }
                                        }
                                        Log.e(TAG, "扫描完成后的list: " + mlist);
                                    }
                                });
                            }
                            Log.e(TAG, "扫描完成后的list: " + mlist);
                            break;
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        };
        //注册蓝牙搜索结果的receiver
        mActivity.registerReceiver(receiver, filter);
    }

添加设备的关键代码

private void addDevice(final BluetoothDevice device) {
        boolean deviceFound = false;
        for (final BluetoothDevice listDev : mlist) {
            if (listDev.getAddress().equals(device.getAddress())) {               
                deviceFound = true;
                break;
            }
        }
        if (!deviceFound) {
            if (mlist.indexOf(device) == -1) { //判断设备是否存在list中,不存返回-1
                mlist.add(device);
                deviceAdapter.notifyDataSetChanged();
            }
        }
    }

2.3 蓝牙搜索结果

通过以上关键部分的代码及搜索过程,可以完成对于蓝牙设备的搜索及添加,当然可以根据个人的需求及爱好针对搜索过程中的一些客制化工作,如将搜索的结果放置在Activity中,dialog加入搜索状态,如正在搜索,搜索完成等,具体添加的位置在btdevice_list_item.xml和BTDeviceAdapter.class中添加状态的判断。
下图为蓝牙设备的搜索结果


蓝牙设备搜索结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,085评论 2 44
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,201评论 0 17
  • 不知是生活委屈了她,还是她委屈了生活,她的人生,四十才刚刚开始。
    楼顶那片海阅读 225评论 0 0
  • 第一,要有合伙人思维,一家公司不能一个人说了算。盛希泰认为,一个项目没有合伙人那就是没有未来,如果找不到合伙人那就...
    田园牧歌928阅读 167评论 0 0