Java堆栈无法使用Android适配器

时间:2017-08-18 16:31:04

标签: java android amazon-s3

我正在为Android中的Amazon S3开发文件管理器应用程序。我使用堆栈来保存文件夹对象以帮助导航。堆栈中的每个对象都是一个文件夹,其中包含该文件夹中文件和文件夹的arraylist mObjects

onClick事件侦听器将先前单击的对象推送到堆栈,并为所单击的对象调用arraylist的setter。

问题是推入堆栈的后续对象会更改堆栈中第一个对象的mObjects字段。我不明白为什么,因为mObjects字段对每个对象都有私有修饰符。

许多小时的代码盯着和谷歌搜索都变成了空白。我在Android Studio中完成了堆栈跟踪,我发现奇怪的是堆栈中第一个对象的mObjects字段在我的BucketObjectListFragment类中的行adapter.setData(o.getmObjects())处发生了变化。

public class BucketObjectListFragment extends ListFragment {
    public static List<S3ObjectSummary> s3ObjList;
    private final int position = 2;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        generateS3Objects();
        for(S3ObjectSummary s : s3ObjList) {
            Log.i("s3ObjList", s.getKey());
        }

        //Create the stack
        ObjectStack myStack = new ObjectStack();

        //Create a new object to hold the home list view
        BucketObject o = new BucketObject();
        o.setPrefixKey("/");

        //Create the home object's list of folders and files
        o.setHomeObjects();

        //Create an adapter to hold the list of files and folders
        ObjectAdapter adapter = new ObjectAdapter(o.getmObjects());
        setListAdapter(adapter);

        //Replicate an Android onClick event. First push the home view onto the stack.
        myStack.push(o);
        Log.i("Stack dump", "...");
        myStack.printStack();

        //Create a new BucketObject for the clicked folder.
        o = ((ObjectAdapter) getListAdapter()).getItem(position);
        o.setmObjects(o.getPrefixKey());
        adapter.setData(o.getmObjects());

        myStack.push(o);
        Log.i("Stack dump", "...");
        myStack.printStack();
    }

    public static void generateS3Objects(){
        //Generate a random list of files and directories that look like S3 objects.
        S3ObjList = new ArrayList<S3ObjectSummary>();
        for(int i=0; i<5; i++){
            S3ObjectSummary obj = new S3ObjectSummary();
            s3ObjList.add(obj);
        }
    }

    private class ObjectAdapter extends ArrayAdapter<BucketObject> {
        private ObjectAdapter(ArrayList<BucketObject> objects) {
            super(getActivity(), android.R.layout.simple_list_item_1, objects);
        }

        public void setData(ArrayList<BucketObject> items) {
            clear();
            setNotifyOnChange(false);
            if (items != null) {
                for (BucketObject item : items)
                    add(item);
            }
            notifyDataSetChanged();
        }
    }
}

我的BucketObject类。

public class BucketObject {
    private UUID id;
    private String prefixKey;
    private String key;
    private ArrayList<BucketObject> mObjects;

    public BucketObject() {
        id = UUID.randomUUID();
    }

    public BucketObject(String mPrefixKey, String mKey) {
        id = UUID.randomUUID();
        prefixKey = mPrefixKey;
        key = mKey;
    }

    @Override
    public String toString() {
        return prefixKey;
    }

    public String getPrefixKey() {
        return prefixKey;
    }

    public void setPrefixKey(String mPrefixKey) {
        prefixKey = mPrefixKey;
    }

    public ArrayList<BucketObject> getmObjects(){
        return mObjects;
    }

    public ArrayList<BucketObject> setHomeObjects(){
        ArrayList<BucketObject> mFiles = new ArrayList<>();
        mObjects = new ArrayList<>();

        //Use a HashSet to hold unique folders and directories
        Set<String> mySet = new HashSet<String>();

        for (S3ObjectSummary summary : BucketObjectListFragment.s3ObjList) {
            String obj = summary.getKey();
            int firstSlash = obj.indexOf("/");

            if (firstSlash != -1){ //if object has multiple forward slashes
                String myKey = obj.substring(0, firstSlash);
                if(mySet.add(myKey)){ //add to set if not a duplicate directory
                    BucketObject b = new BucketObject((myKey + "/"), myKey);
                    mObjects.add(b);
                }
            }
            else {
                //Get files
                BucketObject b = new BucketObject(obj, obj);
                mFiles.add(b);
            }
        }
        mObjects.addAll(mFiles);
        return mObjects;
    }

    public ArrayList<BucketObject> setmObjects(String prefixKey){
        ArrayList<BucketObject> mFiles = new ArrayList<>();
        mObjects = new ArrayList<>();

        //Use a HashSet to hold unique folders and directories
        Set<String> mySet = new HashSet<String>();

        for (S3ObjectSummary summary : BucketObjectListFragment.s3ObjList) {
            String obj = summary.getKey();
            if (obj.startsWith(prefixKey)) {
                String suffix = obj.replaceFirst(prefixKey, "");
                int firstSlash = suffix.indexOf("/");

                if (firstSlash != -1) {
                    String key = suffix.substring(0, firstSlash);
                    if (mySet.add(key)) { //add to set if not a duplicate directory
                        BucketObject b = new BucketObject(obj, key);
                        mObjects.add(b);
                    }
                }
                else{
                    if(!suffix.equals("")) {
                        BucketObject b = new BucketObject(obj, suffix);
                        mFiles.add(b);
                    }
                }
            }
        }
        mObjects.addAll(mFiles);
        return mObjects;
    }
}

我的ObjectStack类。

public class ObjectStack {
    private Stack<BucketObject> s3ObjectStack;

    public ObjectStack(){
        s3ObjectStack = new Stack<>();
    }

    public void push(BucketObject o) {
        s3ObjectStack.push(o);
    }

    public void printStack(){
        //Prints the contents of mObjects for each BucketObject in the stack.

        for(BucketObject o : s3ObjectStack){
            int i = 0;
            Log.i("BucketObject ", o.toString());
            for(BucketObject b : o.getmObjects()){
                Log.i("mObjects " + Integer.toString(i), b.toString());
                i++;
            }
        }
    }
}

生成S3对象的类。

public class S3ObjectSummary {
    private final String key;
    private static final String abc = "abcdefghijklmnopqrstuvwxyz";
    private static SecureRandom rnd = new SecureRandom();

    public S3ObjectSummary(){
        key = randomString(7);
    }

    public String getKey(){
        return key;
    }

    private String randomString(int len){
        StringBuilder sb = new StringBuilder(len);
        for(int i = 0; i < len; i++){
            sb.append(abc.charAt(rnd.nextInt(abc.length())));
        }
        sb.insert(3, '/');
        return sb.toString();
    }
}

主要活动类。

public class StartActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start);
    }
}

带片段的活动的xml。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ie.codemaker.test_panda.StartActivity">

    <fragment
        android:name="ie.codemaker.test_panda.BucketObjectListFragment"
        android:id="@+id/fooFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>

编辑:我已经编辑了上述内容,以提供完整,最小化和可验证的程序。这有助于我将问题缩小到适配器的setData()方法。即使我将单击的对象重命名为o以外的其他内容(堆栈中的第一个对象),第一个对象的私有字段仍会在setData()处更改。如果有人还需要Manifest.xml来运行我可以提供的代码。

1 个答案:

答案 0 :(得分:0)

这里的问题是,正如其他人在另一个问题的答案中所指出的那样,&#34;一个典型的Java错误,指针&#34;使用Android的ArrayAdapter:https://stackoverflow.com/a/14408492/3350944

在以下行中,我将数组mObjects传递给适配器:

ObjectAdapter adapter = new ObjectAdapter(o.getmObjects());

然后,在这一行中,我将新数组mObjects传递给适配器,但适配器仍然指向第一个数组:

adapter.setData(p.getmObjects());

我用新的arrayList&lt;&gt;解决了这个问题在我传递给适配器的BucketObjectListFragment类中:

private ArrayList<BucketObject> newArray;
ObjectAdapter adapter = new ObjectAdapter(newArray);

然后,当我想要更新适配器时,我清除了适配器的列表,并将项目从newArray添加到mObjects

viewList.clear();
for(BucketObject obj : p.getmObjects()){
    newArray.add(obj);
}
adapter.notifyDataSetChanged();