Android 正在解析 xml 并且 AsyncTask doInBackground 方法永远不会完成

Android parsing xml and AsyncTask doInBackground method never finish

我是 Android 开发的新手,我构建了一个简单的应用程序,可以通过蓝牙从我的计算机接收 xml 文件。现在我想解析那个 xml 文件,我想用 AsyncTask doInBackground 方法来做。所以首先在这里我 将字节写入 xml 文件

private void writeBytesToOutputStream(byte[] bytes, String path) {

        File file = new File(path);
        OutputStream out;
        try {
            if(file.exists()){
                file.delete();
            }
            file.createNewFile();

            out = new FileOutputStream(file);
            out.write(bytes);
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // method that sets file and later calls execute().
        xml.setFile(file);
    }

这是我的内部 AsyncTask class。

public class XmlParser extends AsyncTask<Void, Void, String> {

        private XmlPullParserFactory xmlFactoryObject;
        private XmlPullParser myParser;
        private File file;

        String value;

        public XmlParser() {
            try {
                xmlFactoryObject = XmlPullParserFactory.newInstance();
                myParser = xmlFactoryObject.newPullParser();

            } catch (XmlPullParserException e) {
                e.printStackTrace();
            }
        }

        public void setFile(File file1) {
            file = file1;
            execute();
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            FileInputStream fis = null;
            try {
                if(file == null){
                    Toast.makeText(getActivity(), "NULL", Toast.LENGTH_LONG).show();
                }else{
                    Toast.makeText(getActivity(), "NOT NULL " + file.getName(), Toast.LENGTH_LONG).show();
                    fis = new FileInputStream(file);
                    myParser.setInput(fis, null);
                    fis.close();
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            }
        }

        @Override
        protected String doInBackground(Void... params) {
            int event;
            try {
                event = myParser.getEventType();

                while (event != XmlPullParser.END_DOCUMENT) {
                    String name = myParser.getName();
                    switch (event) {
                        case XmlPullParser.START_TAG:

                            break;

                        case XmlPullParser.END_TAG:

                            if (name.equals("from")) {
                                value = myParser.getAttributeValue(null, "value");
                                System.out.println("JUST FOR TEST " + value);
                                event = XmlPullParser.END_DOCUMENT;
                            }
                            break;

                        default:
                            break;
                    }
                    try {
                        event = myParser.next();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }
            }catch (XmlPullParserException e) {
                e.printStackTrace();
            }
            return value;
        }

        @Override
        protected void onPostExecute(String aVoid) {
            super.onPostExecute(aVoid);
            System.out.println("myEND " + aVoid);
            Toast.makeText(getActivity(), "THE END!!! " + aVoid, Toast.LENGTH_LONG).show();
        }
    }

不知何故方法doInBackground()永远不会完成。我花了将近四个小时试图修复它,但我找不到问题所在。我还添加了我的完整代码

public class UiFragment extends Fragment {

    private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
    private static final int REQUEST_ENABLE_BT = 3;

    private String deviceName = null;

    private BluetoothAdapter adapter = null;

    //private ListView listViewConversation;
    //private ArrayAdapter<String> conversationAdapter;

    private Button onButton, offButton;

    private BluetoothConnection connection = null;

    ImageView im;

    private XmlParser xml;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_ui, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        //listViewConversation = (ListView) view.findViewById(R.id.in);
        onButton = (Button) view.findViewById(R.id.onButton);
        offButton = (Button) view.findViewById(R.id.offButton);

        im = (ImageView) view.findViewById(R.id.imageView);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);

        adapter = BluetoothAdapter.getDefaultAdapter();
        xml = new XmlParser();

        // If the adapter is null, then Bluetooth is not supported
        if (adapter == null) {
            FragmentActivity activity = getActivity();
            Toast.makeText(activity, "Bluetooth is not available", Toast.LENGTH_LONG).show();
            activity.finish();
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        // If BT is not on, request that it be enabled.
        // setupChat() will then be called during onActivityResult
        if (!adapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
            // Otherwise, setup the chat session
        } else if (connection == null) {
            setupChat();
        }
    }

    private void setupChat() {
        //conversationAdapter = new ArrayAdapter<String>(getActivity(), R.layout.message);

        //listViewConversation.setAdapter(conversationAdapter);

        onButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                sendCommand(1);
            }
        });

        offButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                sendCommand(0);
            }
        });

        // Initialize the BluetoothChatService to perform bluetooth connections
        connection = new BluetoothConnection(handler);
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_CONNECT_DEVICE_SECURE:
                // When DeviceListActivity returns with a device to connect
                if (resultCode == Activity.RESULT_OK) {
                    connectDevice(data);
                }
                break;
            case REQUEST_ENABLE_BT:
                // When the request to enable Bluetooth returns
                if (resultCode == Activity.RESULT_OK) {
                    // Bluetooth is now enabled, so set up a chat session
                    setupChat();
                } else {
                    // User did not enable Bluetooth or an error occurred
                    Toast.makeText(getActivity(), "Bluetooth not enable", Toast.LENGTH_SHORT).show();
                    getActivity().finish();
                }
        }
    }

    private void connectDevice(Intent data) {
        // Get the device MAC address
        String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
        // Get the BluetoothDevice object
        BluetoothDevice device = adapter.getRemoteDevice(address);
        // Attempt to connect to the device
        connection.connect(device);
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.secure_connect_scan: {
                // Launch the DeviceListActivity to see devices and do scan
                Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
                startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
                return true;
            }
        }
        return false;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_device_list, menu);
    }

    private void setStatus(CharSequence subTitle) {
        FragmentActivity activity = getActivity();
        if (null == activity) {
            return;
        }
        final ActionBar actionBar = activity.getActionBar();
        if (null == actionBar) {
            return;
        }
        actionBar.setSubtitle(subTitle);
    }

    private final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            FragmentActivity activity = getActivity();
            switch (msg.what) {
                case Constants.MESSAGE_STATE_CHANGE:
                    switch (msg.arg1) {
                        case BluetoothConnection.STATE_CONNECTED:
                            String name = getString(R.string.title_connected_to, deviceName);
                            setStatus(name);
                            break;
                        case BluetoothConnection.STATE_CONNECTING:
                            setStatus("Connecting...");
                            break;
                        case BluetoothConnection.STATE_NONE:
                            setStatus("Not connected");
                            break;
                        case BluetoothConnection.STATE_LISTEN:
                    }
                    break;
                case Constants.MESSAGE_DEVICE_NAME:
                    deviceName = msg.getData().getString(Constants.DEVICE_NAME);
                    if (activity != null) {
                        Toast.makeText(activity, "Connected to " + deviceName, Toast.LENGTH_SHORT).show();
                    }
                    break;
                case Constants.MESSAGE_TOAST:
                    if (null != activity) {
                        Toast.makeText(activity, msg.getData().getString(Constants.TOAST), Toast.LENGTH_SHORT).show();
                    }
                    break;
                case Constants.MESSAGE_READ:
                    byte[] readBuffer = (byte[]) msg.obj;

                    //Bitmap bmp = BitmapFactory.decodeByteArray(readBuffer, 0, msg.arg1);
                    //im.setImageBitmap(bmp);

                    String path = activity.getFilesDir() + "/mano.xml";

                    writeBytesToOutputStream(readBuffer, path);

                    break;
            }
        }
    };

    private void sendCommand(int command) {
        if (connection.getState() != BluetoothConnection.STATE_CONNECTED) {
            Toast.makeText(getActivity(), "You are not connected!", Toast.LENGTH_LONG).show();
            return;
        }

        byte[] bytes = ByteBuffer.allocate(4).putInt(command).array();
        connection.write(bytes);
    }

    private void writeBytesToOutputStream(byte[] bytes, String path) {

        File file = new File(path);
        OutputStream out;
        try {
            if(file.exists()){
                file.delete();
            }
            file.createNewFile();

            out = new FileOutputStream(file);
            out.write(bytes);
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        xml.setFile(file);
    }

    public class XmlParser extends AsyncTask<Void, Void, String> {

        private XmlPullParserFactory xmlFactoryObject;
        private XmlPullParser myParser;
        private File file;

        String value;

        public XmlParser() {
            try {
                xmlFactoryObject = XmlPullParserFactory.newInstance();
                myParser = xmlFactoryObject.newPullParser();

            } catch (XmlPullParserException e) {
                e.printStackTrace();
            }
        }

        public void setFile(File file1) {
            file = file1;
            execute();
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            FileInputStream fis = null;
            try {
                if(file == null){ // failas == null
                    Toast.makeText(getActivity(), "NULL", Toast.LENGTH_LONG).show();
                }else{
                    Toast.makeText(getActivity(), "NOT NULL " + file.getName(), Toast.LENGTH_LONG).show();
                    fis = new FileInputStream(file);
                    myParser.setInput(fis, null);
                    fis.close();
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            }
        }

        @Override
        protected String doInBackground(Void... params) {
            int event;
            try {
                event = myParser.getEventType();

                while (event != XmlPullParser.END_DOCUMENT) {
                    String name = myParser.getName();
                    switch (event) {
                        case XmlPullParser.START_TAG:

                            break;

                        case XmlPullParser.END_TAG:

                            if (name.equals("from")) {
                                value = myParser.getAttributeValue(null, "value");
                                System.out.println("JUST FOR TEST " + value);
                                event = XmlPullParser.END_DOCUMENT;
                            }
                            break;

                        default:
                            break;
                    }
                    try {
                        event = myParser.next();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }
            }catch (XmlPullParserException e) {
                e.printStackTrace();
            }
            return value;
        }

        @Override
        protected void onPostExecute(String aVoid) {
            super.onPostExecute(aVoid);
            System.out.println("myEND " + aVoid);
            Toast.makeText(getActivity(), "THE END!!! " + aVoid, Toast.LENGTH_LONG).show();
        }
    }
}

编辑

我的文档

<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

只是猜测,但这可能是你的问题

       try {
            event = myParser.next();
       } catch (IOException e) {
            e.printStackTrace();
       }

这是因为如果由于某种原因您的解析器无法移动到下一个元素 - 也许您的 xml 格式不正确? - 然后这个错误永远不会升级,从而让你陷入无限循环。

您可以改为调用 "break"。如果抛出异常。此外,使用 Log class 进行日志记录,如下所示:

       try {
            event = myParser.next();
       } catch (IOException e) {
            Log.d(TAG, e.getLocalizedMessage();
            break;
       }

试试这个:

while (myParser.getEventType() != XmlPullParser.END_DOCUMENT) {
        //code       
}

我想我找到了解决办法。我需要在 onPostExecute 而不是 onPreExecute 方法上关闭 FileInputStream