如何在Android中使用后台线程保存文件

时间:2013-11-19 09:28:43

标签: android multithreading android-asynctask xmlserializer

我目前创建了一个使用XmlSerializer从对象创建XML文件的函数。我一直在研究使用不同形式的多线程,以便在GUI仍然可用且仍在更新的同时将文件保存在后台。我看过使用AsyncTask来做这件事,但我不确定实现它的最佳方法是什么。请任何人帮助我,并提前感谢你。

这是我到目前为止的代码:

private String fileName;
private DataObjects dataObjects;

public SetCachedValuesFile() 
{

}

public void setFileName(String refFileName)
{
    fileName = refFileName;
}

public void setDataObjects(DataObjects refDataObjects)
{
    dataObjects = refDataObjects;
}

public String getFileName()
{
    return fileName;
}

public DataObjects getDataObjects()
{
    return dataObjects;
}

public void updateValues()
{
    ArrayList<DataObject> arrayListDataObject = dataObjects.getDataObjects();
    try 
    {
        /* Creates a new file and its directory. */
        File directory = new File(Environment.getExternalStorageDirectory() + "/XML_FILES/");
        directory.mkdirs();
        File newFile = new File(directory, fileName + ".xml");
        FileOutputStream fos = new FileOutputStream(newFile);

        /* Creates a new XML serializer which creates the structure of the XML file. */
        XmlSerializer serializer = Xml.newSerializer();
        serializer.setOutput(fos, "UTF-8");
        serializer.startDocument(null, true);
        serializer.startTag("", "CachedValues");
        for(DataObject dataObject : arrayListDataObject)
        {
            if(dataObject.getClass().equals(StringDataObject.class))
            {
                StringDataObject stringDataObject = (StringDataObject) dataObject;
                String address = HexFunctions.toString(stringDataObject.getAddress());
                String value = stringDataObject.getValue();

                serializer.startTag("", "DataObject");
                serializer.startTag("", "Address");
                serializer.text(address);
                serializer.endTag("", "Address");
                serializer.startTag("", "Value");
                serializer.text(value);
                serializer.endTag("", "Value");
                serializer.endTag("", "DataObject");

                System.out.println("String data object added to file.");
            }
            else if(dataObject.getClass().equals(IntDataObject.class))
            {
                IntDataObject intDataObject = (IntDataObject) dataObject;
                String address = HexFunctions.toString(intDataObject.getAddress());
                String value = Integer.toString(intDataObject.getValue());

                serializer.startTag("", "DataObject");
                serializer.startTag("", "Address");
                serializer.text(address);
                serializer.endTag("", "Address");
                serializer.startTag("", "Value");
                serializer.text(value);
                serializer.endTag("", "Value");
                serializer.endTag("", "DataObject");

                System.out.println("Int data object added to file.");
            }
            else if(dataObject.getClass().equals(FloatDataObject.class))
            {
                FloatDataObject floatDataObject = (FloatDataObject) dataObject;
                String address = HexFunctions.toString(floatDataObject.getAddress());
                String value = Float.toString(floatDataObject.getValue());

                serializer.startTag("", "DataObject");
                serializer.startTag("", "Address");
                serializer.text(address);
                serializer.endTag("", "Address");
                serializer.startTag("", "Value");
                serializer.text(value);
                serializer.endTag("", "Value");
                serializer.endTag("", "DataObject");

                System.out.println("Float data object added to file.");
            }
            else if(dataObject.getClass().equals(DoubleDataObject.class))
            {
                DoubleDataObject doubleDataObject = (DoubleDataObject) dataObject;
                String address = HexFunctions.toString(doubleDataObject.getAddress());
                String value = Double.toString(doubleDataObject.getValue());

                serializer.startTag("", "DataObject");
                serializer.startTag("", "Address");
                serializer.text(address);
                serializer.endTag("", "Address");
                serializer.startTag("", "Value");
                serializer.text(value);
                serializer.endTag("", "Value");
                serializer.endTag("", "DataObject");

                System.out.println("Double data object added to file.");
            }
        }
        serializer.endTag("", "CachedValues");
        serializer.endDocument();
        serializer.flush();
        fos.close();

        System.out.println("File created");
        System.out.println("File name: " + newFile.getAbsolutePath());
    } 
    catch (IllegalArgumentException e) 
    {
        e.printStackTrace();
    } 
    catch (IllegalStateException e) 
    {
        e.printStackTrace();
    }
    catch (IOException e) 
    {
        e.printStackTrace();
    }
}

2 个答案:

答案 0 :(得分:11)

AsyncTask类实现了一种最佳实践模式,用于将耗时(但短暂的)处理移动到后台线程并同步回UI线程,以便在完成时将更新应用于UI。请注意,此类任务不会在重新启动活动时保留,因此,例如,如果设备的方向发生更改,则会取消这些任务。

但是,如果您不需要将UI更新为后台任务的一部分(这里似乎就是这种情况),那么只需使用通常更简单的Thread类(编辑:添加的代码)从后台线程更新UI):

Handler handler = new Handler();  //Optional. Define as a variable in your activity.

Runnable r = new Runnable()
{
    @Override
    public void run()
    {
        // your code here
        handler.post(new Runnable()  //If you want to update the UI, queue the code on the UI thread
        {
            public void run()
            {
                //Code to update the UI 
            }
        });
    }
};

Thread t = new Thread(r);
t.start();

请注意,这种类型的线程会在重新启动活动时保持不变,因此通常应该运行完成。

要将此作为AsyncTask(如果需要更新UI,这可能是更好的选择),可以通过以下方式实现:

在您的活动中,创建Async类的实例并执行。

SaveData save = new SaveData();
save.execute();

将AsyncTask子类作为活动中的私有类

private class SaveData extends AsyncTask<String, Void, Boolean>{

@Override
protected Boolean doInBackground(String... params) {
    // your background code here. Don't touch any UI components

    if(your code worked...)
        return true;                
    else
        return false;
}

protected void onPostExecute(Boolean result) {
     //This is run on the UI thread so you can do as you wish here
     if(result)
         Toast successful
     else
         Toast unsuccessful
 }
}

答案 1 :(得分:1)

要添加到NigelK的答案有一点是,如果您使用AsyncTask,则只能使用一次。所以你不能按如下方式调用它两次:

SaveData save = new SaveData();
save.execute();
//Later
save.execute();

相反,您需要执行以下操作:

SaveData save1 = new SaveData();
save1.execute();
//Later
SaveData save2 = new SaveData();
save2.execute();

此外,如果您需要重复运行任务,您可能需要使用处理程序并在runnable中调用它,如下所示:

Handler handler = new Handler();
Runnable runnable = new Runnable() {
    public void run() {
        SaveData save = new SaveData();
        save.execute();       
    }
};
handler.postDelayed(runnable, 500);

请参阅这些链接。 AsyncTask Threading Rule - Can it really only be used once? Call asynctask in handler