0

在 Android 中,如何将互联网上的文本文件保存到 sdcard、从 sdcard 加载文件并用逗号将文件的条目分隔到 ListView 中?

重要的是可以一次选择 ListView 中的多个条目。片段的使用也很好,因为它可以更容易地用于不同的屏幕尺寸,例如手机和平板电脑。

4

1 回答 1

2

我将您的问题视为 2 个不同的问题,每个问题都有自己的解决方案和障碍,最终结合在一起。我的示例都是针对 API16(4.1 Jelly Bean)编译的,至少有 API11(3.0 Honeycomb)。- 警告 -大量文本传入。

从互联网加载

起初从互联网加载似乎势不可挡,尽管最终很简单。首先,您要确保设备具有连接。为此,您创建一个名为getConnectivityStatus如下所示的方法:

public boolean getConnectivityStatus() {
    ConnectivityManager cm = (ConnectivityManager) this
            .getSystemService(CONNECTIVITY_SERVICE);
    NetworkInfo info = cm.getActiveNetworkInfo();
    if (info != null)
        return info.isConnected();
    else
        return false;
}

如果存在连接,您将需要创建一个目录来保存文件并使用 DownloadManager 类下载文件。为此,只需说:

File directory = new File(Environment.getExternalStorageDirectory(), "ExampleDirectory");
if (!directory.exists())
        directory.mkdir();

接下来,您需要使用 方法下载文件downloadFile(String),并传入您想要的文件名。如果您在任何给定时间只想要文件的一个副本,则必须在下载前删除旧文件(如果它存在),否则您将拥有多个文件,例如 examplefile.txt;示例文件-1.txt;示例文件-2.txt;将第一部分代码放在您要开始下载的方法中,例如onClick

String FILE_NAME = "examplefile.txt",
File examplefile = new File(Environment.getExternalStorageDirectory()
        + "/ExampleDirectory", FILE_NAME);
if (examplefile.exists()) {
    boolean deleted = examplefile.delete();
    if (deleted) {
        if (getConnectivityStatus())
            downloadFile(FILE_NAME);
    }
}

downloadFile(String)方法:

public void downloadFile(String FILE_NAME) {
    String url = "http://www.example.com/filetobedownloaded.txt";
    DownloadManager.Request request = new DownloadManager.Request(
            Uri.parse(url));
    request.setDescription("Example file to be displayed.");
    request.setTitle(FILE_NAME);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        request.allowScanningByMediaScanner();
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
    }
    request.setDestinationInExternalPublicDir("ExampleDirectory", FILE_NAME);

    DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    manager.enqueue(request);
}

您还可以注册一个接收器以在下载完成时返回回调。为此,只需在onCreate方法中注册接收器,如下所示:registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));并将以下方法放在您的类中:

BroadcastReceiver onComplete = new BroadcastReceiver() {
    public void onReceive(Context ctxt, Intent intent) {
        if (!started) {
            started = true;
            // perform action upon completion
        }
    }
};

这是最后一DownloadFile.java堂课:

public class DownloadFile extends Activity {

boolean started = false;
String url = "http://www.example.com/filetobedownloaded.txt";
String FILE_NAME = "examplefile.txt",
File directory = new File(Environment.getExternalStorageDirectory(), "ExampleDirectory");
File examplefile = new File(Environment.getExternalStorageDirectory()
        + "/ExampleDirectory", FILE_NAME);

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_downloadfile);
    registerReceiver(onComplete, new IntentFilter(
            DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    check();
}

public void check {
    if (!directory.exists())
        directory.mkdir();
    if (!getConnectivityStatus()) {
        if (!started) {
            started = true;
            // perform action if no connection
        }
    }
    if (examplefile.exists()) {
        boolean deleted = examplefile.delete();
            if (deleted && !started) {
                if (getConnectivityStatus())
                    downloadFile(FILE_NAME);
            }
    }
}

public boolean getConnectivityStatus() {
    ConnectivityManager cm = (ConnectivityManager) this
            .getSystemService(CONNECTIVITY_SERVICE);
    NetworkInfo info = cm.getActiveNetworkInfo();
    if (info != null)
        return info.isConnected();
    else
        return false;
}

public void downloadFile(String FILE_NAME) {
    String url = "http://www.example.com/filetobedownloaded.txt";
    DownloadManager.Request request = new DownloadManager.Request(
            Uri.parse(url));
    request.setDescription("Example file to be displayed.");
    request.setTitle(FILE_NAME);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        request.allowScanningByMediaScanner();
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
    }
    request.setDestinationInExternalPublicDir("ExampleDirectory", FILE_NAME);

    DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    manager.enqueue(request);
}

BroadcastReceiver onComplete = new BroadcastReceiver() {
    public void onReceive(Context ctxt, Intent intent) {
        if (!started) {
            started = true;
            // perform action upon completion
        }
    }
};


加载到 ListFragment

为了将文件加载到 ListFragment 中,并稍后显示所选项目,您必须在布局目录中创建 3 个类和 2 个 xml 文件。在我的示例中,我将使用MainActivity.javaPreviewFragment.javaSelectionFragment.javaactivity_main.xmlfragment_preview.xml。我们将从 xml 开始。第一个 xml 文件是您正在查看的文件,其中包含我们正在使用的两个片段:ListFragment 和 PreviewFragment。设置相当简单;您指定两个片段、它们的 id 和约束以及它们各自的类。这里是activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

<fragment
    android:id="@+id/fragmentSelection"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="2"
    class="com.smarticle.catering.update.SelectionFragment" />

<fragment
    android:id="@+id/fragmentPreview"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1"
    class="com.smarticle.catering.update.PreviewFragment" />
</LinearLayout>

上述布局针对横向模式下的平板电脑进行了优化。如果您愿意,可以调整安排。
接下来,您必须在 xml 中指定 PreviewFragment,这也相当简单,因为它只是一个水平和垂直居中的 TextView,最终将显示所选项目。这里是fragment_preview.xml

<?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="match_parent" >

<TextView
    android:id="@+id/tvPreview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:text="@string/app_name"
    android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>

ListFragment 将在运行时创建,因此它不需要自己的 xml 文件。
为了在屏幕上显示片段,您必须activity_main.xml在活动中加载布局。这是一项非常简单的任务,因为它看起来就像其他所有活动一样。这是MainActivity.java

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

就是这样,认真的。但现在继续。为了更改 PreviewFragment 中的文本,您必须在 中扩展FragmentPreviewFragment.java,膨胀视图并设置 setText 方法。类PreviewFragment.java如下图所示:

public class PreviewFragment extends Fragment {

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

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

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

    public void setText(String item) {
        TextView tvPreview = (TextView) getView().findViewById(R.id.tvPreview);
        tvPreview.setText(item);
    }

}

片段的生命周期可以在这里找到。
现在您必须设置 ListFragment。这将在ListFragment.java课堂上完成。在该onActivityCreated()方法中,您需要加载文件,确保它实际下载并位于该load(String)方法的正确目录中。此时,您还将通过文件的分隔符将文件分隔为一个数组。这是load(String)方法:

public void load(String FILE_NAME) {
String[] list;
String FILE_NAME = "examplefile.txt",
File directory = new File(Environment.getExternalStorageDirectory(), "ExampleDirectory");
File examplefile = new File(Environment.getExternalStorageDirectory()
    + "/ExampleDirectory", FILE_NAME);
if (examplefile.exists()) {
    try {
        File myFile = new File(directory + "/" + FILE_NAME);
        FileInputStream fIn = new FileInputStream(myFile);
        BufferedReader myReader = new BufferedReader(new InputStreamReader(
                fIn));
        String aDataRow = "";
        String aBuffer = "";
        while ((aDataRow = myReader.readLine()) != null) {
            aBuffer += aDataRow;
            aBuffer = aBuffer.trim();
            list = aBuffer.split(",");
        }
        myReader.close();
        if (!loaded)
            Toast.makeText(getActivity(),
                    "Done reading '" + FILE_NAME + "'.", Toast.LENGTH_SHORT)
                    .show();
        loaded = true;
        if (!selections.equals("")) {
            for (int i = 0; i < selections.size(); i++) {
                getListView().setItemChecked(selections.get(i), true);
            }
        }
    } catch (Exception e) {
        Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT)
                .show();
        }
    }
}

这将返回字符串数组list,其中 examplefile.txt 的内容用逗号分隔。只要 aBuffer.split(String delimiter) 的表达式与文本文件中的分隔符一致,您就可以将逗号替换为您想要的任何分隔符。布尔值loaded只是为了确保每次重新创建活动时都不会出现新的 Toast,例如在方向更改时。
load(String)方法中,也是设置 ListFragment 的适配器和模式的好时机。您需要选择一个允许多选的 textViewResourceId,除非您想要单选。这可以通过简单地插入以下行在 while 语句之后顺利完成:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                getActivity(),
                android.R.layout.simple_list_item_activated_1, list);
setListAdapter(adapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

如果需要单选,请更改ListView.CHOICE_MODE_MULTIPLEListView.CHOICE_MODE_SINGLE并更改android.R.layout.simple_list_item_activated_1android.R.layout.simple_list_item_1。或者,如果您想要检查而不是突出显示,请更改为android.R.layout.simple_list_item_checked.
在这个类中,您还必须初始化您的 PreviewFragment,onActivityCreated方法如下:fragment = (PreviewFragment) getFragmentManager().findFragmentById( R.id.fragmentPreview);
最后,您必须能够读取 ListFragment 中选择了哪些项目并将它们显示在 PreviewFragment 上。我使用getSelectedItems()如下所示的方法执行此操作:

public void getSelectedItems() {
    cntChoice = getListView().getCount();
    items = "";
    selections.clear();
    SparseBooleanArray sparseBooleanArray = getListView()
            .getCheckedItemPositions();
    for (int i = 0; i < cntChoice; i++) {
        if (sparseBooleanArray.get(i) == true) {
            items += getListView().getItemAtPosition(i).toString()
                    + ";\n";
            selections.add(i);
        }
    }
    if (fragment != null && fragment.isInLayout())
        fragment.setText(items);
}

Stringitems是 TextView 中显示的selections内容,ArrayList<Integer>用于在方向更改时恢复状态。android:configChanges="orientation"通常,您会在标签下的AndroidManifest.xml文件中指定一个<activity >,但是当为纵向或横向使用单独的布局时会出现问题。如果您允许 Manifest 处理方向更改,则在更改方向时不会更改布局,因为不会像在正常情况下那样创建新活动。因此,您创建static ArrayList<Integer>包含包含所选项目的位置。
最后要做的是在单击 ListItem 时读取并调用该getSelectedItems方法,这是一项相当简单的任务。将其插入到您的课程中的任何位置:

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);
    getItems();
}

你完了!现在把它们放在一起。这是ListFragment.java课程:

public class ListFragment extends ListFragment {

    String FILE_NAME = "examplefile.txt", items = "";
    String[] list;
    static ArrayList<Integer> selections = new ArrayList<Integer>();
    int cntChoice, position;
    static boolean loaded = false;
    File directory = new File(Environment.getExternalStorageDirectory(), "ExampleDirectory");
    File examplefile = new File(Environment.getExternalStorageDirectory()
            + "/ExampleDirectory", FILE_NAME);
    PreviewFragment fragment;

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

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        fragment = (PreviewFragment) getFragmentManager().findFragmentById(
                R.id.fragmentPreview);
        check();
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        getSelectedItems();
    }

    public void getSelectedItems() {
        cntChoice = getListView().getCount();
        items = "";
        selections.clear();
        SparseBooleanArray sparseBooleanArray = getListView()
                .getCheckedItemPositions();
        for (int i = 0; i < cntChoice; i++) {
            if (sparseBooleanArray.get(i) == true) {
                items += getListView().getItemAtPosition(i).toString()
                        + ";\n";
                selections.add(i);
            }
        }
        if (fragment != null && fragment.isInLayout())
            fragment.setText(items);
    }

    public void check() {
        if (examplefile.exists())
            load(FILE_NAME);
    }

    public void load(String FILE_NAME) {
        try {
            File myFile = new File(directory + "/" + FILE_NAME);
            FileInputStream fIn = new FileInputStream(myFile);
            BufferedReader myReader = new BufferedReader(new InputStreamReader(
                    fIn));
            String aDataRow = "";
            String aBuffer = "";
            while ((aDataRow = myReader.readLine()) != null) {
                aBuffer += aDataRow;
                aBuffer = aBuffer.trim();
                list = aBuffer.split(",");
            }
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                    getActivity(),
                    android.R.layout.simple_list_item_activated_1,     list);
            setListAdapter(adapter);
            getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
            myReader.close();
            if (!loaded)
                Toast.makeText(getActivity(),
                        "Done reading '" + FILE_NAME + "'.",     Toast.LENGTH_SHORT)
                        .show();
            loaded = true;
            if (!selections.equals("")) {
                for (int i = 0; i < selections.size(); i++) {
                    getListView().setItemChecked(selections.get(i),     true);
                }
                getSelectedItems();
            }
        } catch (Exception e) {
            Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT)
                    .show();
        }
    }
}

结论

我希望这能解决你的问题。我知道它很长,但它很彻底,经过测试并且效果很好。要开始这个,你可以在类的接收者Intent intent = new Intent(getBaseContext(), MainActivity.class); startActivity(intent); finish();的方法中做一个。我还建议在方法中放置相同的代码行,特别是在没有连接时调用的部分,在这种情况下,它将加载先前下载到目录中的文件。Good luck, happy coding and always remember... 01101000011101000111010001110000011100110011101000101111001011110111011101110111011101110010111001111001011011110111010101110100011101010110001001100101001011100110001101101111011011010010111101110111011000010111010001100011011010000011111101110110001111010110100101110101011000100100101000101101010110000101001101001100001110010110011101101111onReceiveDownloadFile.javacheck()

于 2012-12-29T19:56:05.030 回答