将文件加载到具有多个选择的ListFragment中

时间:2012-12-29 19:56:05

标签: android listview android-listview android-fragments android-listfragment

在Android中,如何将文本文件从Internet保存到SD卡,从SD卡加载文件并用逗号分隔文件的条目到ListView?

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

1 个答案:

答案 0 :(得分:2)

我认为你的问题是两个不同的问题,每个问题都有自己的解决方案和障碍,最终会聚在一起。我的示例都是针对API16(4.1 Jelly Bean)进行编译的,其中API11(3.0 Honeycomb)最少。 - 警告 - 大量文字传入。

从Internet加载

首先从互联网上加载似乎势不可挡,尽管最终很简单。首先,您要确保设备具有连接。为此,您需要创建一个名为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; examplefile-1.TXT; examplefile-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中的文本,您必须在Fragment中扩展PreviewFragment.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);
    }

}

可以找到片段的生命周期here 现在,您必须设置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();
        }
    }
}

这将返回String数组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_MULTIPLE更改为ListView.CHOICE_MODE_SINGLE并将android.R.layout.simple_list_item_activated_1更改为android.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);
}

字符串items是TextView中显示的内容,selectionsArrayList<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();类的接收器的onReceive方法中执行DownloadFile.java。我还建议在check()方法中放置相同的代码行,特别是在没有连接的情况下调用的部分,在这种情况下,它将加载先前下载到目录的文件。祝你好运,快乐编码和永远记住... 01101000011101000111010001110000011100110011101000101111001011110111011101110111011101110010111001111001011011110111010101110100011101010110001001100101001011100110001101101111011011010010111101110111011000010111010001100011011010000011111101110110001111010110100101110101011000100100101000101101010110000101001101001100001110010110011101101111