【问题标题】:Loading File into ListFragment with Multiple Choice使用多项选择将文件加载到 ListFragment
【发布时间】:2012-12-29 19:56:05
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

    我将您的问题视为 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 中的文本,您必须扩展 PreviewFragment.java 中的 Fragment 类,扩展视图并设置 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();
            }
        }
    }
    

    这将返回字符串数组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 中显示的内容,selections 是一个ArrayList&lt;Integer&gt;,用于在方向更改时恢复状态。通常,您会在AndroidManifest.xml 文件中的&lt;activity &gt; 标记下指定android:configChanges="orientation",但在纵向或横向使用单独布局时会出现问题。如果您允许 Manifest 处理方向更改,则在更改方向时不会更改布局,因为不会像在正常情况下那样创建新活动。因此,您创建 static ArrayList&lt;Integer&gt; 包含包含所选项目的位置。
    最后要做的是在单击 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();
            }
        }
    }
    

    结论

    我希望这能解决您的问题。我知道它很长,但它很彻底,经过测试并且效果很好。为此,您可以在DownloadFile.java 类中接收器的onReceive 方法中执行Intent intent = new Intent(getBaseContext(), MainActivity.class); startActivity(intent); finish();。我还建议将这些相同的代码行放在check() 方法中,特别是在没有连接时调用的部分,在这种情况下,它将加载先前下载到目录中的文件。祝你好运,快乐编码始终记得...... 01101000011101000111010001110000011100110011101000101111001011110111011101110111011101110010111001111001011011110111010101110100011101010110001001100101001011100110001101101111011011010010111101110111011000010111010001100011011010000011111101110110001111010110100101110101011000100100101000101101010110000101001101001100001110010110011101101111 P>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-17
      • 2015-11-24
      • 1970-01-01
      • 2012-10-12
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多