How to display Dropbox files in a listview in andr

2019-03-01 11:13发布

I've been browsing answers on here for a while and have employed most of the answers in my code but it still doesn't seem to work. I just want to display a listview of the content in a dropbox account and also give the user an option to download a file/folder. My MainActivity used to crash right after opening it, surrounding my onPostExecute content with a try/catch statement handling NullPointerException solved the crashing. But the app still fails to display the contents in Dropbox. At the most basic stage with just a MainActivity and a DLFiles (AsyncTask) class, how do I make this work? I've been at this for days, please help! Thanks in advance.

MainActivity.java

public class MainActivity extends Activity {

    final static private String APP_KEY = "app_key_here";
    final static private String APP_SECRET = "app_secret_here";
    final static private AccessType ACCESS_TYPE = AccessType.DROPBOX;
    private static final boolean USE_OAUTH1 = false;

    // You don't need to change these, leave them alone.
    final static private String ACCOUNT_PREFS_NAME = "prefs";
    final static private String ACCESS_KEY_NAME = "ACCESS_KEY";
    final static private String ACCESS_SECRET_NAME = "ACCESS_SECRET";

    // In the class declaration section:
    private DropboxAPI<AndroidAuthSession> mDBApi;

    private boolean mLoggedIn;
    private final String FILE_DIR = "/";
    private String[] mfnames;
    private ListView mListView;
    private Button listEm;



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



        // And later in some initialization function:
        AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
        AndroidAuthSession session = new AndroidAuthSession(appKeys, ACCESS_TYPE);
        mDBApi = new DropboxAPI<AndroidAuthSession>(session);

        if (!mLoggedIn){
            if (USE_OAUTH1){
                mDBApi.getSession().startAuthentication(MainActivity.this);
            } else{
                mDBApi.getSession().startOAuth2Authentication(MainActivity.this);
            }
        }

        mListView = (ListView) findViewById(R.id.list);

        listEm = (Button) findViewById(R.id.listit);

        listEm.setOnClickListener(new OnClickListener(){
            public void onClick(View v){
                DLFiles dlf = new DLFiles(MainActivity.this,mDBApi,
                        FILE_DIR, mfnames,mListView );
                dlf.execute();
            }
        });



        checkLoggedIn(mDBApi.getSession().isLinked());


    }

    private void checkLoggedIn(boolean loggedIn){
        mLoggedIn = loggedIn;
    }



    protected void onResume() {
        super.onResume();

        if (mDBApi.getSession().authenticationSuccessful()) {
            try {
                // Required to complete auth, sets the access token on the session
                mDBApi.getSession().finishAuthentication();

                String accessToken = mDBApi.getSession().getOAuth2AccessToken();

            } catch (IllegalStateException e) {
                Log.i("DbAuthLog", "Error authenticating", e);
            }
        }
    }

    private void loadAuth(AndroidAuthSession session) {
        SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
        String key = prefs.getString(ACCESS_KEY_NAME, null);
        String secret = prefs.getString(ACCESS_SECRET_NAME, null);
        if (key == null || secret == null || key.length() == 0 || secret.length() == 0) return;

        if (key.equals("oauth2:")) {
            // If the key is set to "oauth2:", then we can assume the token is for OAuth 2.
            session.setOAuth2AccessToken(secret);
        } else {
            // Still support using old OAuth 1 tokens.
            session.setAccessTokenPair(new AccessTokenPair(key, secret));
        }
    }


    /**
     * Shows keeping the access keys returned from Trusted Authenticator in a local
     * store, rather than storing user name & password, and re-authenticating each
     * time (which is not to be done, ever).
     */
    private void storeAuth(AndroidAuthSession session) {
        // Store the OAuth 2 access token, if there is one.
        String oauth2AccessToken = session.getOAuth2AccessToken();
        if (oauth2AccessToken != null) {
            SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
            Editor edit = prefs.edit();
            edit.putString(ACCESS_KEY_NAME, "oauth2:");
            edit.putString(ACCESS_SECRET_NAME, oauth2AccessToken);
            edit.commit();
            return;
        }
        // Store the OAuth 1 access token, if there is one.  This is only necessary if
        // you're still using OAuth 1.
        AccessTokenPair oauth1AccessToken = session.getAccessTokenPair();
        if (oauth1AccessToken != null) {
            SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
            Editor edit = prefs.edit();
            edit.putString(ACCESS_KEY_NAME, oauth1AccessToken.key);
            edit.putString(ACCESS_SECRET_NAME, oauth1AccessToken.secret);
            edit.commit();
            return;
        }
    }

    private AndroidAuthSession buildSession() {
        AppKeyPair appKeyPair = new AppKeyPair(MainActivity.APP_KEY, MainActivity.APP_SECRET);

        AndroidAuthSession session = new AndroidAuthSession(appKeyPair);
        loadAuth(session);
        return session;
    }
}

DLFiles.java

public class DLFiles extends AsyncTask<Void, Long, String[]> {

    private Context mContext;
    private final ProgressDialog mDialog;
    private DropboxAPI<?> mApi;
    private String mPath;

    private FileOutputStream mFos;

    private boolean mCanceled;
    private Long mFileLen;
    private String mErrorMsg;
    private String[] fnames;

    public DLFiles( Context context, DropboxAPI<?> api,
            String dropboxPath,String[] efnames, ListView listView){
        // We set the context this way so we don't accidentally leak activities
        mContext = context.getApplicationContext();
        fnames = efnames;
        mApi = api;
        mPath = dropboxPath;

        mDialog = new ProgressDialog(context);
        mDialog.setMessage("Opening Directory");
        mDialog.show();
    }

    @Override
    protected String[] doInBackground(Void... params){
        // Get the metadata for a directory


        try{
            ArrayList<String> filenames = new ArrayList<String>();
            Entry dirent = mApi.metadata(mPath, 1000, null, true, null);
            for (Entry ent: dirent.contents){
                if(ent.isDir){
                    //Add it to the list of thumbs we can choose from
                    filenames.add("<dir>" + ent.path);}
                else{
                    filenames.add(ent.fileName());
                }


            }
            fnames = filenames.toArray(new String[filenames.size()]);


        } catch (DropboxUnlinkedException e) {
            // The AuthSession wasn't properly authenticated or user unlinked.
        } catch (DropboxPartialFileException e) {
            // We canceled the operation
            mErrorMsg = "Download canceled";
        } catch (DropboxServerException e) {
            // Server-side exception.  These are examples of what could happen,
            // but we don't do anything special with them here.
            if (e.error == DropboxServerException._304_NOT_MODIFIED) {
                // won't happen since we don't pass in revision with metadata
            } else if (e.error == DropboxServerException._401_UNAUTHORIZED) {
                // Unauthorized, so we should unlink them.  You may want to
                // automatically log the user out in this case.
            } else if (e.error == DropboxServerException._403_FORBIDDEN) {
                // Not allowed to access this
            } else if (e.error == DropboxServerException._404_NOT_FOUND) {
                // path not found (or if it was the thumbnail, can't be
                // thumbnailed)
            } else if (e.error == DropboxServerException._406_NOT_ACCEPTABLE) {
                // too many entries to return
            } else if (e.error == DropboxServerException._415_UNSUPPORTED_MEDIA) {
                // can't be thumbnailed
            } else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
                // user is over quota
            } else {
                // Something else
            }
            // This gets the Dropbox error, translated into the user's language
            mErrorMsg = e.body.userError;
            if (mErrorMsg == null) {
                mErrorMsg = e.body.error;
            }
        } catch (DropboxIOException e) {
            // Happens all the time, probably want to retry automatically.
            mErrorMsg = "Network error.  Try again.";
        } catch (DropboxParseException e) {
            // Probably due to Dropbox server restarting, should retry
            mErrorMsg = "Dropbox error.  Try again.";
        } catch (DropboxException e) {
            // Unknown error
            mErrorMsg = "Unknown error.  Try again.";
        }
        return fnames;  
    }

    @Override
    protected void onProgressUpdate(Long... progress){
        int percent = (int)(100.0*(double)progress[0]/mFileLen + 0.5);
        mDialog.setProgress(percent);
    }

    @Override
    protected void onPostExecute(String[] result){
        try{
            if (result != null){
                ArrayAdapter<String> array = new ArrayAdapter<String>(mContext,
                        android.R.layout.simple_list_item_1, result);

                Log.d("dropbox", result[1]);
            }
            else
                showToast("result==null");
        }
        catch (NullPointerException e){
            e.printStackTrace();
        }


    }

activity_main.xml

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


    <Button 
      android:id="@+id/listit" 
      android:text="List directory content" 
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      />

    <LinearLayout
        android:id="@+id/listing" 
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        >

    <ListView 
        android:id="@+id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">

    </ListView>

    </LinearLayout>

</LinearLayout>

3条回答
看我几分像从前
2楼-- · 2019-03-01 11:29

if you fixed your app by catching a null-pointer exception, you still have a null value that needs to be addressed, if you are trying to add a null array as an adapter nothing will show up. From the code it looks like you are creating an array adapter from fnames, and then trying to reassign values to the array adapter twice with the secondary for loop. So I am willing to bet that fnames is null. I would set a break point on fnames in the doInBackground method and check it. Also the value that is returned from doInBackground is the parameter for onPostExecute so if you are returning a value that you want to use, use the parameter result from onPostExecute.

查看更多
走好不送
3楼-- · 2019-03-01 11:43

I now see that your code is like in DownloadRandomPicture.java.

String fnames [] = null;

In doOnBackGround():

     ArrayList<String> filenames = new ArrayList<String>();

        for (Entry ent: dirent.contents) {
            if (ent.thumbExists) {
                  filenames.add(ent.path);
             }
        }

     fnames = filenames.toArray(new String[filenames.size()]);

in onPostExecute():

       if ( fnames != null )
        {
            ArrayAdapter<String> array = new ArrayAdapter<String>(mContext, android.R.layout.simple_list_item_1, fnames);

            listView1.setAdapter(array);
        }
       else
            showToast ( "fnames==null" );
查看更多
不美不萌又怎样
4楼-- · 2019-03-01 11:45

If you want to show the files and folder of a drop box in List View then simply use this code in your project and it will solve your problem.

private void PopulateList() 
        {
          List<String> filename = new ArrayList<String>();
          String mPath = "/";
          Entry dirent = null;
            try 
            {
                dirent = mApi.metadata(mPath, 1000, null, true, null);
            } catch (DropboxException e)
            {
                System.out.println("Error :  "+e.getMessage());
            }
            for (Entry ent: dirent.contents)
            {
                if(ent.isDir)
                {
                    filename.add(ent.fileName());               
                }  
            ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getBaseContext(),android.R.layout.simple_list_item_1, filename );
             mListView.setAdapter(arrayAdapter); 

        }
查看更多
登录 后发表回答