DiegoAPP–机器人设置,及选择

34 篇文章 11 订阅
17 篇文章 0 订阅

更多创客作品,请关注笔者网站园丁鸟,搜集全球极具创意,且有价值的创客作品
ROS机器人知识请关注,diegorobot
业余时间完成的一款在线统计过程分析工具SPC,及SPC知识分享网站qdo


1.App有两个Activity

RobotChooser, 作为APP运行起来的Activity,配置为Main Action, 为用户呈现一个新增机器人,配置配置机器人的界面
ControlApp,在连接到Robot后的主界面,执行控制任务,及Ros Topic数据的接收,并显示在界面上,有兴趣的同学可以到https://www.diegorobot.com下载试用。

我们需要在项目的 文件中配置两个Activity,并吧RobotChooser配置为Main,如下图所示:
在这里插入图片描述
2. RobotChooser功能说明
RobotChooser为用户进入APP的第一个页面,主要提供如下功能
在这里插入图片描述

新增Robot,用户可以通过右上角的加号按钮来添加Robot,一个Robot代表一个Ros Master
Robot 列表,用户可以添加多个Robot Master,并列表显示
Robot 编辑,用户点击修改按钮,即可进入Robot信息的编辑页面,可以修改Master ip,及topic的名称
Robot 删除,用户也可以点击删除按钮删除Robot
Robot在线状态,Robot 列表中的信号图标如果是灰色,则表明Robot不在线,否则说明Robot是在线状态,可以连接
连接到Robot,当Robot处于在线状态的情况下,可以点击Robot项,直接连接到Robot,后跳转到控制页面

  1. RobotChooser 代码主要逻辑说明

    RobotChooser继承自AppCompatActivity,并实现了相应的接口,代码如下:

public class RobotChooser extends AppCompatActivity implements AddEditRobotDialogFragment.DialogListener,
        ConfirmDeleteDialogFragment.DialogListener, ListView.OnItemClickListener {

    /** Key for whether this is the first time the app has been launched */
    public static final String FIRST_TIME_LAUNCH_KEY = "FIRST_TIME_LAUNCH";

    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;

    private ShowcaseView showcaseView;
    private Toolbar mToolbar;

    private ActionBarDrawerToggle mDrawerToggle;

    // Variables for keeping track of Fragments
    private Fragment fragment = null;
    private FragmentManager fragmentManager;
    private int fragmentsCreatedCounter = 0;

    // Log tag String
    private static final String TAG = "RobotChooser";

在RobotChooser变量声明部分,两个主要的变量是:

mRecyclerView, 这个是主要操作的界面视图类
mAdapter,这个类是Robot工具item,删除,编辑,连接到Robot的主要功能实现,对应的文件是Core/RobotInfoAdapter
showcaseView, 使用ShowcaseView实现在Robot列表中还没有添加Robot的情况下,实现操作引导界面
在这里插入图片描述
Android APP Activity的初始化代码一般放在onCreate(), RobotChooser的代码如下:

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        try {
            this.setContentView(R.layout.robot_chooser);
        }
        catch(Exception e){}
        mRecyclerView = (RecyclerView) findViewById(R.id.robot_recycler_view);

        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        mRecyclerView.setLayoutManager(mLayoutManager);

        mToolbar = (Toolbar) findViewById(R.id.robot_chooser_toolbar);
        setSupportActionBar(mToolbar);

        RobotStorage.load(this);

        if (getActionBar() != null) {
            getActionBar().setDisplayHomeAsUpEnabled(true);
            getActionBar().setHomeButtonEnabled(true);
        }

        // Adapter for creating the list of Robot options
        mAdapter = new RobotInfoAdapter(this, RobotStorage.getRobots());

        mRecyclerView.setAdapter(mAdapter);

        ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();

        // Check whether this is the first time the app has been launched on this device
        final boolean isFirstLaunch = PreferenceManager
                .getDefaultSharedPreferences(this)
                .getBoolean(FIRST_TIME_LAUNCH_KEY, true);

        // Delay the initial tutorial a little bit
        // This makes sure the view gets a good reference to the UI layout positions
        Runnable task = new Runnable() {
            public void run() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    try {
                        if (RobotStorage.getRobots().size() == 0 && isFirstLaunch) {
                            //Show initial tutorial message
                            showcaseView = new ShowcaseView.Builder(RobotChooser.this)
                                .setTarget(new ToolbarActionItemTarget(mToolbar, R.id.action_add_robot))
                                .setStyle(R.style.CustomShowcaseTheme2)
                                .hideOnTouchOutside()
                                .blockAllTouches()
                                //.singleShot(0) Can use this instead of manually saving in preferences
                                .setContentTitle(R.string.splash_add_robot_title)
                                .setContentText(R.string.splash_add_robot_text)
                                .build();

                            //Get ready to show tutorial message when user adds a robot
                            setupNextTutorialMessage();
                        }
                    } catch (Exception ignore) {}
                }
            });
            }
        };

        worker.schedule(task, 1, TimeUnit.SECONDS);
    }

在这段代码中首先指定了Activity对应的res id,初始化了mRecyclerView 等变量,这里需要关注的是RobotStorage.load(this)载入了已经配置好的Robot信息,返回一个Robot列表,并显示在主界面上。

isFirstLaunch 变量定义了用户是不是第一次打开APP,同时通过runOnUiThread运行一个独立的线程来执行ShowCaseView,实现功能引导,显示功能引导界面的条件是用户第一次使用,或者Robot list中没有Robot。

RobotChooser其他部分代码主要是正对Robot的增删改操作,及一些消息的传递,这里不在讲解。

  1. RobotInfoAdapter 代码主要逻辑讲解

    在Robot chooser界面针对当Robot的操作都是在RobotInfoAdapter中实现的,此文件位于Core文件夹下。其中内嵌了类ViewHolder来指定res,同时实现操作,其代码如下:

 public ViewHolder(View v) {
            super(v);
            v.setClickable(true);
            v.setOnClickListener(this);
            mRobotNameTextView = (TextView) v.findViewById(R.id.robot_name_text_view);
            mMasterUriTextView = (TextView) v.findViewById(R.id.master_uri_text_view);

            mEditButton = (ImageButton) v.findViewById(R.id.robot_edit_button);
            mEditButton.setOnClickListener(this);

            mDeleteButton = (ImageButton) v.findViewById(R.id.robot_delete_button);
            mDeleteButton.setOnClickListener(this);

            mImageView = (ImageView) v.findViewById(R.id.robot_wifi_image);
            mImageView.setImageResource(R.mipmap.wifi_0);

            Timer t = new Timer();

            t.scheduleAtFixedRate(new TimerTask() {

                @Override
                public void run() {
                    try {
                        int position = getAdapterPosition();
                        final RobotInfo info = mDataset.get(position);
                        //mImageView.setLayoutParams(new ActionBar.LayoutParams(mEditButton.getHeight(), mEditButton.getHeight()));

                        if (isPortOpen(info.getUri().getHost(), info.getUri().getPort(), 10000)) {
                            activity.runOnUiThread(new Runnable() {

                                @Override
                                public void run() {
                                    mImageView.setImageResource(R.mipmap.wifi_4);
                                }
                            });
                        } else {
                            activity.runOnUiThread(new Runnable() {

                                @Override
                                public void run() {
                                    mImageView.setImageResource(R.mipmap.wifi_0);
                                }
                            });
                        }

                        Thread.sleep(10000);
                    } catch (Exception ignore) {

                    }
                }
            }, 1000, 15000);
        }

        /**
         * Handles clicks on the RobotInfoAdapter.ViewHolder.
         *
         * @param v The clicked View. Can be either the edit button, delete button, or the adapter itself,
         *          in which case a connection is initiated to the RobotInfo contained in this Adapter
         */
        @Override
        public void onClick(View v) {
            int position = getAdapterPosition();
            Bundle bundle;
            final RobotInfo info = mDataset.get(position);

            switch (v.getId()) {
                case R.id.robot_edit_button:
                    AddEditRobotDialogFragment editRobotDialogFragment = new AddEditRobotDialogFragment();
                    bundle = new Bundle();
                    info.save(bundle);
                    bundle.putInt(AddEditRobotDialogFragment.POSITION_KEY, position);
                    editRobotDialogFragment.setArguments(bundle);

                    editRobotDialogFragment.show(activity.getSupportFragmentManager(), "editrobotialog");
                    break;

                case R.id.robot_delete_button:
                    ConfirmDeleteDialogFragment confirmDeleteDialogFragment = new ConfirmDeleteDialogFragment();
                    bundle = new Bundle();

                    bundle.putInt(ConfirmDeleteDialogFragment.POSITION_KEY, position);
                    bundle.putString(ConfirmDeleteDialogFragment.NAME_KEY, info.getName());
                    confirmDeleteDialogFragment.setArguments(bundle);

                    confirmDeleteDialogFragment.show(activity.getSupportFragmentManager(), "deleterobotdialog");
                    break;

                default:

                    FragmentManager fragmentManager = activity.getFragmentManager();
                    ConnectionProgressDialogFragment f = new ConnectionProgressDialogFragment(info);
                    f.show(fragmentManager, "ConnectionProgressDialog");

                    break;
            }
        }
    }

在此类中,除了在开头部分指定了资源,主要有两部功能:

启动一个定时器任务,每10000毫秒检查一次Robot的在线状态,并同时更新界面的在线状态图标
处理onClick事件,根据用户点击的按钮执行相应的操作,当用户点击的是整个Robot的item时,则通过RobotinforAdapter的run函数跳转到ControlApp Action,界面切换为Robot的控制界面。

private void run()
        {
            thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        if(!isPortOpen(INFO.getUri().getHost(), INFO.getUri().getPort(), 10000)){
                            throw new Exception(getActivity().getString(R.string.cannot_connect_ros));
                        }

                        final Intent intent = new Intent(activity, ControlApp.class);

                        // !!!---- EVIL USE OF STATIC VARIABLE ----!! //
                        // Should not be doing this but there is no other way that I can see -Michael
                        ControlApp.ROBOT_INFO = INFO;

                        dismiss();

                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                activity.startActivity(intent);
                            }
                        });
                    }
                    catch (final NetworkOnMainThreadException e){
                        dismiss();

                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(activity, "Invalid Master URI", Toast.LENGTH_LONG).show();
                            }
                        });
                    }
                    catch (InterruptedException e)
                    {
                        // Ignore
                        Log.d(TAG, "interrupted");
                    }
                    catch (final Exception e) {

                        if (ConnectionProgressDialogFragment.this.getFragmentManager() != null)
                            dismiss();

                        activity.runOnUiThread(new Runnable() {
                                @Override
            public void run() {
                            Toast.makeText(activity, e.getMessage(), Toast.LENGTH_LONG).show();
                                }
                        });
                    }
                }
            });

            thread.start();
        }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DiegoRobot

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值