【问题标题】:How to save and restore custom arraylist on configuration change [duplicate]如何在配置更改时保存和恢复自定义arraylist [重复]
【发布时间】:2016-07-23 07:33:42
【问题描述】:

我有一个 ArrayList,其中包含使用 Volley 从 Web 获取的自定义 json 对象。我希望能够在屏幕旋转时保存和恢复这些对象。我还想保存并恢复我当前在屏幕旋转时的滚动位置。

我有一个粗略的想法,这可以通过 onSaveInstanceState 和 onRestoreInstanceState 来完成?

活动代码

public class MainActivity extends AppCompatActivity {

    private final String TAG = "MainActivity";



    //Creating a list of posts
    private List<PostItems> mPostItemsList;

    //Creating Views
    private RecyclerView recyclerView;
    private RecyclerView.Adapter adapter;
    private RecyclerView.LayoutManager layoutManager;
    private ProgressDialog mProgressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "Device rotated and onCreate called");

        //Initializing Views
        recyclerView = (RecyclerView) findViewById(R.id.post_recycler);
        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);


        //Initializing the postlist
        mPostItemsList = new ArrayList<>();
        adapter = new PostAdapter(mPostItemsList, this);

        recyclerView.setAdapter(adapter);

        if (NetworkCheck.isAvailableAndConnected(this)) {
            //Caling method to get data
            getData();
        } else {
            final Context mContext;
            mContext = this;
            final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
            alertDialogBuilder.setTitle(R.string.alert_titl);
            alertDialogBuilder.setMessage(R.string.alert_mess);
            alertDialogBuilder.setPositiveButton(R.string.alert_posi, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (!NetworkCheck.isAvailableAndConnected(mContext)) {
                        alertDialogBuilder.show();
                    } else {
                        getData();
                    }


                }
            });
            alertDialogBuilder.setNegativeButton(R.string.alert_nega, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();

                }
            });
            alertDialogBuilder.show();

        }

    }

    //This method will get data from the web api
    private void getData(){


        Log.d(TAG, "getData called");
        //Showing progress dialog
        mProgressDialog = new ProgressDialog(MainActivity.this);
        mProgressDialog.setCancelable(false);
        mProgressDialog.setMessage(this.getResources().getString(R.string.load_post));
        mProgressDialog.show();

        //Creating a json request
        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigPost.GET_URL,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        Log.d(TAG, "onResponse called");
                        //Dismissing the progress dialog
                        if (mProgressDialog != null) {
                            mProgressDialog.hide();
                        }
                        /*progressDialog.dismiss();*/


                        //calling method to parse json array
                        parseData(response);

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {

                    }
                });

        //Creating request queue
        RequestQueue requestQueue = Volley.newRequestQueue(this);

        //Adding request to the queue
        requestQueue.add(jsonArrayRequest);
    }

    //This method will parse json data
    private void parseData(JSONArray array){
        Log.d(TAG, "Parsing array");

        for(int i = 0; i<array.length(); i++) {
            PostItems postItem = new PostItems();
            JSONObject jsonObject = null;
            try {
                jsonObject = array.getJSONObject(i);
                postItem.setPost_title(jsonObject.getString(ConfigPost.TAG_POST_TITLE));
                postItem.setPost_body(jsonObject.getString(ConfigPost.TAG_POST_BODY));

 } catch (JSONException w) {
                w.printStackTrace();
            }
            mPostItemsList.add(postItem);
        }

    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy called");
        if (mProgressDialog != null){
            mProgressDialog.dismiss();
            Log.d(TAG, "mProgress dialog dismissed");

        }
    }

提前致谢。

注意How to save custom ArrayList on Android screen rotate? 的重复。虽然该问题中的数组列表是在 Activity 中声明的,但我的是通过 volley 从网上获取的。我不知道如何为我的数组列表实现它,否则不会问这个问题

【问题讨论】:

  • 在我问这个问题之前我已经看到了这个问题。虽然该问题中的数组列表是在 Activity 中声明的,但我的是通过 volley 从网上获取的。我不知道如何为我的数组列表实现它,否则不会问这个问题。
  • 不,这是同一个问题。从哪里获取数据并不重要。我认为您要问的是“当请求未完成并且用户旋转屏幕时会发生什么?”在这种情况下,请求被先前的活动上下文卡住了,它将把它传递给被破坏的活动,你会得到一个异常。不要泄露活动上下文。
  • 是的,这是同一个问题,但我应该如何为从网络获取的数据实现它。

标签: java android


【解决方案1】:

您可以在活动中使用onConfigurationChanged 来检测轮换变化。此外,您应该使用layoutManager.findLastVisibleItemPosition() 跟踪lastVisibleItemPosition,并且当旋转发生变化时,您应该滚动到该位置。您需要使用recyclerView.setOnScrollListener() 收听滚动以保持您的lastVisibleItemPosition 更新

public class MainActivity extends AppCompatActivity {

private final String TAG = "MainActivity";

//Creating and initializing list of posts
private List<PostItems> mPostItemsList = new ArrayList<>();;

//Creating Views
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private ProgressDialog mProgressDialog;
private int lastVisibleItemPos = -1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Log.d(TAG, "Device rotated and onCreate called");

    if (NetworkCheck.isAvailableAndConnected(this)) {
        //Caling method to get data and check if postList have value set before or not
        // because this part will be called on every rotation change, we are controlling this
        if (mPostItemsList.size() <= 0) {
            //Initializing Views
            recyclerView = (RecyclerView) findViewById(R.id.post_recycler);
            layoutManager = new LinearLayoutManager(this);
            recyclerView.setLayoutManager(layoutManager);

            adapter = new PostAdapter(mPostItemsList, this);

            recyclerView.setAdapter(adapter);
            getData();
        }

    } else {
        final Context mContext;
        mContext = this;
        final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
        alertDialogBuilder.setTitle(R.string.alert_titl);
        alertDialogBuilder.setMessage(R.string.alert_mess);
        alertDialogBuilder.setPositiveButton(R.string.alert_posi, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (!NetworkCheck.isAvailableAndConnected(mContext)) {
                    alertDialogBuilder.show();
                } else {
                    getData();
                }


            }
        });
        alertDialogBuilder.setNegativeButton(R.string.alert_nega, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                finish();

            }
        });
        alertDialogBuilder.show();

    }

}

//This method will get data from the web api
private void getData(){


    Log.d(TAG, "getData called");
    //Showing progress dialog
    mProgressDialog = new ProgressDialog(MainActivity.this);
    mProgressDialog.setCancelable(false);
    mProgressDialog.setMessage(this.getResources().getString(R.string.load_post));
    mProgressDialog.show();

    //Creating a json request
    JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigPost.GET_URL,
            new Response.Listener<JSONArray>() {
                @Override
                public void onResponse(JSONArray response) {
                    Log.d(TAG, "onResponse called");
                    //Dismissing the progress dialog
                    if (mProgressDialog != null) {
                        mProgressDialog.hide();
                    }
                    /*progressDialog.dismiss();*/


                    //calling method to parse json array
                    parseData(response);

                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {

                }
            });

    //Creating request queue
    RequestQueue requestQueue = Volley.newRequestQueue(this);

    //Adding request to the queue
    requestQueue.add(jsonArrayRequest);
}

//This method will parse json data
private void parseData(JSONArray array){
    Log.d(TAG, "Parsing array");

    for(int i = 0; i<array.length(); i++) {
        PostItems postItem = new PostItems();
        JSONObject jsonObject = null;
        try {
            jsonObject = array.getJSONObject(i);
            postItem.setPost_title(jsonObject.getString(ConfigPost.TAG_POST_TITLE));
            postItem.setPost_body(jsonObject.getString(ConfigPost.TAG_POST_BODY));

        } catch (JSONException w) {
            w.printStackTrace();
        }
        mPostItemsList.add(postItem);
    }

}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    // set your adapter here with your data
    adapter = new PostAdapter(mPostItemsList, this);
    recyclerView.setAdapter(adapter);
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d(TAG, "onDestroy called");
    if (mProgressDialog != null){
        mProgressDialog.dismiss();
        Log.d(TAG, "mProgress dialog dismissed");

    }
}

【讨论】:

  • 这些adapter = new PostAdapter(mPostItemsList, this); recyclerView.setAdapter(adapter); 在您的回答中重复了两次,是否合适。并且getData 在轮换后仍然被调用。
  • 你绝对是对的。保存项目后,我们不需要调用“configurationchanged”。但是,如果您想保留它以进行某些特定于方向的工作,那将没有问题。但因此您不需要在应用程序中定义两次“适配器”,也不需要在轮换后调用“getData”。
  • 好的,但 getData 在轮换后仍然被调用
  • 您确定在 onCreate 方法中删除了初始化 arrayList。因为每次初始化并将其分配给 mPostList 时,arraylist 的大小将等于 0,并且应用程序将在每次旋转时一次又一次地调用 'getData()' 函数
  • 根据 James 的说法,“在您的情况下,关键是不要在每次旋转设备时调用 getData()。如果您已经在 mPostItemsList 中加载了数据,则通过 onSaveInstanceState 保存并恢复它(),然后在 onCreate() 中从保存状态中获取数据。如果该数据不存在,则调用 getData()。但在他的回答中,从mPostItems = savedInstanceState.getParcelableArrayList(KEY_POST_ITEMS); 行开始,因为mPostItems 不是声明的变量,Android Studio 以红色突出显示它。
【解决方案2】:

事实上,这是the post you mentioned 的副本。是的,该列表是在该帖子的活动的 onCreate() 中声明的,而您是异步执行的。但是,想法是一样的。

一旦您有数据要发送,在您的应用程序的任何时候,它都可以被保存和恢复。

在您的情况下,关键是不要在每次旋转设备时调用 getData()。如果您已经在 mPostItemsList 中加载了数据,则通过 onSaveInstanceState() 保存和恢复它,并在 onCreate() 中从保存的状态中获取数据。如果该数据不存在,则调用 getData()。

public class MainActivity extends AppCompatActivity {

    private final String TAG = "MainActivity";
    private final String KEY_POST_ITEMS = "#postitems";

    //Creating a list of posts
    private List<PostItems> mPostItemsList;

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

        initializeViews();

        if (savedInstanceState != null && savedInstanceState.containsKey(KEY_POST_ITEMS)){
            mPostItemsList = savedInstanceState.getParcelableArrayList(KEY_POST_ITEMS);
        } else {
            //Initializing the postlist
            mPostItemsList = new ArrayList<>();

            if (NetworkCheck.isAvailableAndConnected(this)) {
                //Caling method to get data
                getData();
            } else {
                showNoNetworkDialog();
            }
        }

        mAdapter = new PostAdapter(mPostItemsList, this);
        recyclerView.setAdapter(adapter);

    }

    private void parseData(JSONArray array){
        mPostItemsList.clear();

        for(int i = 0; i<array.length(); i++) {
            PostItems postItem = new PostItems();
            JSONObject jsonObject = null;
            try {
                jsonObject = array.getJSONObject(i);
                postItem.setPost_title(jsonObject.getString(ConfigPost.TAG_POST_TITLE));
                postItem.setPost_body(jsonObject.getString(ConfigPost.TAG_POST_BODY));
            } catch (JSONException w) {
                w.printStackTrace();
            }

            mPostItemsList.add(postItem);
        }

        mAdapter.notifyDataSetchanged();

    }

编辑:我没有看到保存滚动位置的要求。看看Emin Ayar's answer。此外,这里也有类似的答案:How to save recyclerview scroll position

【讨论】:

  • mPostItems = savedInstanceState.getParcelableArrayList(KEY_POST_ITEMS); 行我没有变量mPostItems。或者我​​弄错了吗?
  • 对不起,这是我的错字。这应该是mPostItemsList,而不是 mPostItems
  • 感谢詹姆斯的回答。我突然想到它是mPostItemsList,我实际上尝试过,但 Android Studio 抱怨;我忘记了真正的抱怨。我现在不在我的电脑上,可以检查一下。只是想让你知道。
  • @Faraday 你有想过这个吗?
猜你喜欢
  • 2016-08-08
  • 2014-03-06
  • 2016-06-12
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多