带有导航抽屉的 Android 文件管理器
Posted
技术标签:
【中文标题】带有导航抽屉的 Android 文件管理器【英文标题】:Android File Manager with Navigation Drawer 【发布时间】:2013-11-25 07:31:07 【问题描述】:我正在尝试用导航抽屉实现一个简单的文件管理器。我正在使用自定义列表视图来显示 SDcard 的内容。这些是我的文件
activity_main_drawer.xml(主布局)
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_
android:layout_ >
<!-- The main content view -->
<FrameLayout
android:id="@+id/container"
android:layout_
android:layout_ >
</FrameLayout>
<!-- The navigation drawer -->
<ListView
android:id="@+id/drawer"
android:layout_
android:layout_
android:layout_gravity="start"
android:background="#F3F3F4"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp" />
file_view.xml(用作自定义列表视图)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_ android:orientation="vertical" android:layout_>
<ImageView
android:id="@+id/fd_Icon1"
android:layout_
android:layout_ >
</ImageView>
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_
android:layout_
android:singleLine="true"
android:textStyle="bold"
android:layout_toRightOf="@+id/fd_Icon1"
android:layout_marginTop="5dip"
android:layout_marginLeft="5dip">
</TextView>
<TextView android:text="@+id/TextView02"
android:id="@+id/TextView02"
android:layout_
android:layout_
android:layout_toRightOf="@+id/fd_Icon1"
android:layout_below="@+id/TextView01"
android:layout_marginLeft="10dip">
</TextView>
<TextView android:text="@+id/TextViewDate"
android:id="@+id/TextViewDate"
android:layout_
android:layout_
android:layout_below="@+id/TextView01"
android:layout_alignParentRight="true"
android:layout_marginLeft="5dip">
</TextView>
</RelativeLayout>
MainActivity.java
public class MainActivity extends FragmentActivity
private ListView mDrawerList;
private DrawerLayout mDrawer;
private CustomActionBarDrawerToggle mDrawerToggle;
private String[] menuItems;
private FileChooser filechooser;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_drawer);
//Gets the path of external storage
// enable ActionBar app icon to behave as action to toggle nav drawer
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
// set a custom shadow that overlays the main content when the drawer
// opens
mDrawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
_initMenu();
mDrawerToggle = new CustomActionBarDrawerToggle(this, mDrawer);
mDrawer.setDrawerListener(mDrawerToggle);
Fragment fragment = new FileChooser();
android.app.FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment).commit();
private void _initMenu()
NsMenuAdapter mAdapter = new NsMenuAdapter(this);
// Add Header
mAdapter.addHeader(R.string.ns_menu_main_header);
// Add first block
menuItems = getResources().getStringArray(R.array.ns_menu_items);
String[] menuItemsIcon = getResources().getStringArray(
R.array.ns_menu_items_icon);
int res = 0;
for (String item : menuItems)
int id_title = getResources().getIdentifier(item, "string",
this.getPackageName());
int id_icon = getResources().getIdentifier(menuItemsIcon[res],
"drawable", this.getPackageName());
NsMenuItemModel mItem = new NsMenuItemModel(id_title, id_icon);
if (res == 1)
mItem.counter = 12; // it is just an example...
if (res == 3)
mItem.counter = 3; // it is just an example...
mAdapter.addItem(mItem);
res++;
mAdapter.addHeader(R.string.ns_menu_main_header2);
//add second block
menuItems = getResources().getStringArray(R.array.ns_menu_items);
String[] menuItemsIcon1 = getResources().getStringArray(
R.array.ns_menu_items_icon);
int res1 = 0;
for (String item : menuItems)
int id_title = getResources().getIdentifier(item, "string",
this.getPackageName());
int id_icon = getResources().getIdentifier(menuItemsIcon1[res1],
"drawable", this.getPackageName());
NsMenuItemModel mItem = new NsMenuItemModel(id_title, id_icon);
if (res1 == 1)
mItem.counter = 12; // it is just an example...
if (res1 == 3)
mItem.counter = 3; // it is just an example...
mAdapter.addItem(mItem);
res1++;
mDrawerList = (ListView) findViewById(R.id.drawer);
if (mDrawerList != null)
mDrawerList.setAdapter(mAdapter);
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
@Override
protected void onPostCreate(Bundle savedInstanceState)
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
@Override
public void onConfigurationChanged(Configuration newConfig)
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
@Override
public boolean onCreateOptionsMenu(Menu menu)
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
/* Called whenever we call invalidateOptionsMenu() */
@Override
public boolean onPrepareOptionsMenu(Menu menu)
// If the nav drawer is open, hide action items related to the content
// view
boolean drawerOpen = mDrawer.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_save).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
@Override
public boolean onOptionsItemSelected(MenuItem item)
/*
* The action bar home/up should open or close the drawer.
* ActionBarDrawerToggle will take care of this.
*/
if (mDrawerToggle.onOptionsItemSelected(item))
return true;
// Handle your other action bar items...
return super.onOptionsItemSelected(item);
/*
* This is used to toggle the title on the action bar
*/
private class CustomActionBarDrawerToggle extends ActionBarDrawerToggle
public CustomActionBarDrawerToggle(Activity mActivity,
DrawerLayout mDrawerLayout)
super(mActivity, mDrawerLayout, R.drawable.ic_drawer,
R.string.ns_menu_open, R.string.ns_menu_close);
@Override
public void onDrawerClosed(View view)
getActionBar().setTitle(getString(R.string.ns_menu_close));
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
@Override
public void onDrawerOpened(View drawerView)
getActionBar().setTitle(getString(R.string.ns_menu_open));
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
/*
* Action to be performed when clicking item on the drawer
*/
private class DrawerItemClickListener implements
ListView.OnItemClickListener
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id)
// Highlight the selected item, update the title, and close the
// drawer
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
String text = "menu click... should be implemented";
Toast.makeText(MainActivity.this, text, Toast.LENGTH_LONG).show();
// You should reset item counter
mDrawer.closeDrawer(mDrawerList);
FileChooser.java
public class FileChooser extends Fragment
private File currentDir;
public FileChooser() ;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View rootView = inflater.inflate(R.layout.file_view, container, false);
currentDir = new File(Environment.getExternalStorageDirectory().getPath());
FileList flist = new FileList();
flist.fill(currentDir);
return rootView;
/*
* Method to fill the current layout with files and folders from the external directory
*
* @params: Path for the SD Card
*/
public class FileList extends ListActivity
private File currentDir;
private FileArrayAdapter adapter;
void fill(File f)
File[]dirs = f.listFiles();
this.setTitle(f.getName());
List<Item>dir = new ArrayList<Item>();
List<Item>fls = new ArrayList<Item>();
try
for(File ff: dirs)
Date lastModDate = new Date(ff.lastModified());
DateFormat formater = DateFormat.getDateTimeInstance();
String date_modify = formater.format(lastModDate);
if(ff.isDirectory())
File[] fbuf = ff.listFiles();
int buf = 0;
if(fbuf != null)
buf = fbuf.length;
else buf = 0;
String num_item = String.valueOf(buf);
if(buf == 0) num_item = num_item + " item";
else num_item = num_item + " items";
//String formated = lastModDate.toString();
dir.add(new Item(ff.getName(),num_item,date_modify,ff.getAbsolutePath(),"directory_icon"));
else
fls.add(new Item(ff.getName(),ff.length() + " Byte", date_modify, ff.getAbsolutePath(),"file_icon"));
catch(Exception e)
Collections.sort(dir);
Collections.sort(fls);
dir.addAll(fls);
if(!f.getName().equalsIgnoreCase(Environment.getExternalStorageDirectory().getName()))
dir.add(0,new Item("..","Parent Directory","",f.getParent(),"directory_up"));
adapter = new FileArrayAdapter(FileList.this,R.layout.file_view,dir);
this.setListAdapter(adapter);
@Override
protected void onListItemClick(ListView l, View v, int position, long id)
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
Item o = adapter.getItem(position);
if(o.getImage().equalsIgnoreCase("directory_icon")||o.getImage().equalsIgnoreCase("directory_up"))
currentDir = new File(o.getPath());
fill(currentDir);
else
onFileClick(o);
private void onFileClick(Item o)
Toast.makeText(this, "Folder Clicked: "+ currentDir, Toast.LENGTH_SHORT).show();
FileArrayAdapter.java
public class FileArrayAdapter extends ArrayAdapter<Item>
private Context c;
private int id;
private List<Item>items;
public FileArrayAdapter(Context context, int textViewResourceId,
List<Item> objects)
super(context, textViewResourceId, objects);
c = context;
id = textViewResourceId;
items = objects;
public Item getItem(int i)
return items.get(i);
@Override
public View getView(int position, View convertView, ViewGroup parent)
View v = convertView;
if (v == null)
LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
/* create a new view of my layout and inflate it in the row */
//convertView = ( RelativeLayout ) inflater.inflate( resource, null );
final Item o = items.get(position);
if (o != null)
TextView t1 = (TextView) v.findViewById(R.id.TextView01);
TextView t2 = (TextView) v.findViewById(R.id.TextView02);
TextView t3 = (TextView) v.findViewById(R.id.TextViewDate);
/* Take the ImageView from layout and set the city's image */
ImageView imageCity = (ImageView) v.findViewById(R.id.fd_Icon1);
String uri = "drawable/" + o.getImage();
int imageResource = c.getResources().getIdentifier(uri, null, c.getPackageName());
Drawable image = c.getResources().getDrawable(imageResource);
imageCity.setImageDrawable(image);
if(t1!=null)
t1.setText(o.getName());
if(t2!=null)
t2.setText(o.getData());
if(t3!=null)
t3.setText(o.getDate());
return v;
logcat
11-25 11:48:33.382: E/AndroidRuntime(8819): FATAL EXCEPTION: main
11-25 11:48:33.382: E/AndroidRuntime(8819): Process: it.gmariotti.android.example.navigationdrawer, PID: 8819
11-25 11:48:33.382: E/AndroidRuntime(8819): java.lang.RuntimeException: Unable to start activity ComponentInfoit.gmariotti.android.example.navigationdrawer/com.tdl.filemannavdrawer.MainActivity: java.lang.IllegalStateException: System services not available to Activities before onCreate()
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2176)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2226)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.ActivityThread.access$700(ActivityThread.java:135)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1397)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.os.Handler.dispatchMessage(Handler.java:102)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.os.Looper.loop(Looper.java:137)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.ActivityThread.main(ActivityThread.java:4998)
11-25 11:48:33.382: E/AndroidRuntime(8819): at java.lang.reflect.Method.invokeNative(Native Method)
11-25 11:48:33.382: E/AndroidRuntime(8819): at java.lang.reflect.Method.invoke(Method.java:515)
11-25 11:48:33.382: E/AndroidRuntime(8819): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
11-25 11:48:33.382: E/AndroidRuntime(8819): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
11-25 11:48:33.382: E/AndroidRuntime(8819): at dalvik.system.NativeStart.main(Native Method)
11-25 11:48:33.382: E/AndroidRuntime(8819): Caused by: java.lang.IllegalStateException: System services not available to Activities before onCreate()
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.Activity.getSystemService(Activity.java:4531)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.widget.ArrayAdapter.init(ArrayAdapter.java:310)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.widget.ArrayAdapter.<init>(ArrayAdapter.java:153)
11-25 11:48:33.382: E/AndroidRuntime(8819): at com.tdl.filemannavdrawer.FileArrayAdapter.<init>(FileArrayAdapter.java:25)
11-25 11:48:33.382: E/AndroidRuntime(8819): at com.tdl.filemannavdrawer.FileChooser$FileList.fill(FileChooser.java:89)
11-25 11:48:33.382: E/AndroidRuntime(8819): at com.tdl.filemannavdrawer.FileChooser.onCreateView(FileChooser.java:35)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.Fragment.performCreateView(Fragment.java:1700)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:890)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1062)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.BackStackRecord.run(BackStackRecord.java:684)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1447)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.Activity.performStart(Activity.java:5252)
11-25 11:48:33.382: E/AndroidRuntime(8819): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2149)
11-25 11:48:33.382: E/AndroidRuntime(8819): ... 11 more
在 FileChooser.java 中,我在 OnCreate() 中调用了 list()。该实现有什么问题吗?有人有我可以参考的带有导航抽屉的文件管理器的工作示例吗?
【问题讨论】:
【参考方案1】:解决了。我将 ListFragment 用于 FileChooser 类并删除了内部类。还使用了另一个 listview.xml。 这是修改后的代码
public class FileChooser extends ListFragment
private File currentDir;
private FileArrayAdapter adapter;
public FileChooser() ;
public static ListFragment newInstance(Context context)
FileChooser f = new FileChooser();
return f;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View rootView = inflater.inflate(R.layout.activity_main, container, false);
currentDir = new File(Environment.getExternalStorageDirectory().getPath());
fill(currentDir);
return rootView;
/*
* Method to fill the current layout with files and folders from the external directory
*
* @params: Path for the SD Card
*/
void fill(File f)
File[]dirs = f.listFiles();
//this.setTitle(f.getName());
List<Item>dir = new ArrayList<Item>();
List<Item>fls = new ArrayList<Item>();
try
for(File ff: dirs)
Date lastModDate = new Date(ff.lastModified());
DateFormat formater = DateFormat.getDateTimeInstance();
String date_modify = formater.format(lastModDate);
if(ff.isDirectory())
File[] fbuf = ff.listFiles();
int buf = 0;
if(fbuf != null)
buf = fbuf.length;
else buf = 0;
String num_item = String.valueOf(buf);
if(buf == 0) num_item = num_item + " item";
else num_item = num_item + " items";
//String formated = lastModDate.toString();
dir.add(new Item(ff.getName(),num_item,date_modify,ff.getAbsolutePath(),"directory_icon"));
else
fls.add(new Item(ff.getName(),ff.length() + " Byte", date_modify, ff.getAbsolutePath(),"file_icon"));
catch(Exception e)
Collections.sort(dir);
Collections.sort(fls);
dir.addAll(fls);
if(!f.getName().equalsIgnoreCase(Environment.getExternalStorageDirectory().getName()))
dir.add(0,new Item("..","Parent Directory","",f.getParent(),"directory_up"));
adapter = new FileArrayAdapter(getActivity(),R.layout.file_view,dir);
this.setListAdapter(adapter);
@Override
public void onListItemClick(ListView l, View v, int position, long id)
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
Item o = adapter.getItem(position);
if(o.getImage().equalsIgnoreCase("directory_icon")||o.getImage().equalsIgnoreCase("directory_up"))
currentDir = new File(o.getPath());
fill(currentDir);
else
onFileClick(o);
private void onFileClick(Item o)
Toast.makeText(getActivity(), "Folder Clicked: "+ currentDir, Toast.LENGTH_SHORT).show();
【讨论】:
【参考方案2】:您可以使用我的文件管理器代码。我使用了一个简单的对话框:-
package com.wysiwyg.main;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import com.example.dev_task_197_keyboard_accesory.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.TextView;
public class FileExplore extends Activity
// Stores names of traversed directories
ArrayList<String> str = new ArrayList<String>();
// Check if the first level of the directory structure is the one showing
private Boolean firstLvl = true;
private static final String TAG = "F_PATH";
private Item[] fileList;
private File path = new File(Environment.getExternalStorageDirectory() + "");
private String chosenFile;
private static final int DIALOG_LOAD_FILE = 1000;
ListAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
loadFileList();
showDialog(DIALOG_LOAD_FILE);
Log.d(TAG, path.getAbsolutePath());
private void loadFileList()
try
path.mkdirs();
catch (SecurityException e)
Log.e(TAG, "unable to write on the sd card ");
// Checks whether path exists
if (path.exists())
FilenameFilter filter = new FilenameFilter()
@Override
public boolean accept(File dir, String filename)
File sel = new File(dir, filename);
// Filters based on whether the file is hidden or not
return (sel.isFile() || sel.isDirectory())
&& !sel.isHidden();
;
String[] fList = path.list(filter);
fileList = new Item[fList.length];
for (int i = 0; i < fList.length; i++)
fileList[i] = new Item(fList[i], R.drawable.file_icon);
// Convert into file path
File sel = new File(path, fList[i]);
// Set drawables
if (sel.isDirectory())
fileList[i].icon = R.drawable.directory_icon;
Log.d("DIRECTORY", fileList[i].file);
else
Log.d("FILE", fileList[i].file);
if (!firstLvl)
Item temp[] = new Item[fileList.length + 1];
for (int i = 0; i < fileList.length; i++)
temp[i + 1] = fileList[i];
temp[0] = new Item("Up", R.drawable.directory_up);
fileList = temp;
else
Log.e(TAG, "path does not exist");
adapter = new ArrayAdapter<Item>(this,
android.R.layout.select_dialog_item, android.R.id.text1,
fileList)
@Override
public View getView(int position, View convertView, ViewGroup parent)
// creates view
View view = super.getView(position, convertView, parent);
TextView textView = (TextView) view
.findViewById(android.R.id.text1);
// put the image on the text view
textView.setCompoundDrawablesWithIntrinsicBounds(
fileList[position].icon, 0, 0, 0);
// add margin between image and text (support various screen
// densities)
int dp5 = (int) (5 * getResources().getDisplayMetrics().density + 0.5f);
textView.setCompoundDrawablePadding(dp5);
return view;
;
private class Item
public String file;
public int icon;
public Item(String file, Integer icon)
this.file = file;
this.icon = icon;
@Override
public String toString()
return file;
@Override
protected Dialog onCreateDialog(int id)
Dialog dialog = null;
AlertDialog.Builder builder = new Builder(this);
if (fileList == null)
Log.e(TAG, "No files loaded");
dialog = builder.create();
return dialog;
switch (id)
case DIALOG_LOAD_FILE:
builder.setTitle("Choose your file");
builder.setAdapter(adapter, new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
chosenFile = fileList[which].file;
File sel = new File(path + "/" + chosenFile);
if (sel.isDirectory())
firstLvl = false;
// Adds chosen directory to list
str.add(chosenFile);
fileList = null;
path = new File(sel + "");
loadFileList();
removeDialog(DIALOG_LOAD_FILE);
showDialog(DIALOG_LOAD_FILE);
Log.d(TAG, path.getAbsolutePath());
// Checks if 'up' was clicked
else if (chosenFile.equalsIgnoreCase("up") && !sel.exists())
// present directory removed from list
String s = str.remove(str.size() - 1);
// path modified to exclude present directory
path = new File(path.toString().substring(0,
path.toString().lastIndexOf(s)));
fileList = null;
// if there are no more directories in the list, then
// its the first level
if (str.isEmpty())
firstLvl = true;
loadFileList();
removeDialog(DIALOG_LOAD_FILE);
showDialog(DIALOG_LOAD_FILE);
Log.d(TAG, path.getAbsolutePath());
// File picked
else
Intent returnIntent = new Intent();
returnIntent.putExtra("file", path + "/" + chosenFile);
setResult(RESULT_OK,returnIntent);
finish();
// Perform action with file picked
);
break;
dialog = builder.show();
return dialog;
【讨论】:
感谢您的输入,但我没有导航抽屉的文件管理器代码运行完美。当我合并两者时,我得到了错误。现在没关系,我使用 ListFragment 修复了它,并把代码供其他人参考。在接下来的一小时内无法将其标记为答案。以上是关于带有导航抽屉的 Android 文件管理器的主要内容,如果未能解决你的问题,请参考以下文章
Android - 为带有导航抽屉和应用栏的应用完全隐藏状态和导航栏