DiegoAPP–機器人設置,及選擇

1.App有兩個Activity

RobotChooser, 作爲APP運行起來的Activity,配置爲Main Action, 爲用戶呈現一個新增機器人,配置配置機器人的界面
ControlApp,在連接到Robot後的主界面,執行控制任務,及Ros Topic數據的接收,並顯示在界面上

我們需要在項目的 文件中配置兩個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();
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章