单击后退按钮时,在 RecyclerView 中获得相同的项目位置

Posted

技术标签:

【中文标题】单击后退按钮时,在 RecyclerView 中获得相同的项目位置【英文标题】:Getting same item position in RecyclerView, when click on back button 【发布时间】:2018-07-03 06:54:55 【问题描述】:

我已经实现了一个应用程序,我在fragments 中使用RecyclerView。每个项目上有 3 个按钮、1 个图像和一些文本。如果我滚动并单击“查看配置文件”按钮,则将打开正在成功运行的新活动,但是当我回调按钮时,该项目将出现在开始位置。我需要项目将出现在相同的位置。

物品图片

片段代码

public class Broader_Match_Tab extends Fragment

int lastVisibleItemPosition;
SessionManager session;
private List<SuperHero> listSuperHeroes;
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
public ProgressBar progressBar;
private RequestQueue requestQueue;
private int requestCount1 = 1;
private Boolean isStarted = false;
private Boolean isVisible = false;

boolean isLastPageLoaded = false;

public String email;
TextView tvMSG;
public Broader_Match_Tab() 

@Override
public void onStart() 
    super.onStart();
    isStarted = true;
    if (isVisible && isStarted)
        getData();
    


@Override
public void setUserVisibleHint(boolean isVisibleToUser) 
    super.setUserVisibleHint(isVisibleToUser);
    isVisible = isVisibleToUser;
    if (isStarted && isVisible && (! isLastPageLoaded))  getData();  

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    View view= inflater.inflate(R.layout.activity_main_test, container, false);

    session = new SessionManager(getActivity());
    // get user data from session
    HashMap<String, String> user = session.getUserDetails();
    email = user.get(SessionManager.KEY_EMAIL);
    return view;


public void onViewCreated(View v, Bundle savedInstanceState) 
    super.onViewCreated(v, savedInstanceState);
    recyclerView = (RecyclerView) v.findViewById(R.id.recyclerView);
    recyclerView.setHasFixedSize(true);
    layoutManager = new LinearLayoutManager(getContext());
    recyclerView.setLayoutManager(layoutManager);
    listSuperHeroes = new ArrayList<>();
    requestQueue = Volley.newRequestQueue(getContext());
    adapter = new CardAdapter(listSuperHeroes, getActivity());
    recyclerView.setAdapter(adapter);
    progressBar = (ProgressBar) v.findViewById(R.id.progressBar1);
    tvMSG = (TextView)v.findViewById(R.id.tvMSG);

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() 
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int
                newState) 
            super.onScrollStateChanged(recyclerView, newState);
            if (isLastItemDisplaying(recyclerView)) 
                    getData();
            
        
    );


private JsonArrayRequest getDataFromServer(int requestCount) 
    final String DATA_URL = "https://www.example.com";
    JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(DATA_URL + String.valueOf(requestCount),
            new Response.Listener<JSONArray>() 
                @Override
                public void onResponse(JSONArray response) 
                    if (response.length() == 0) 
                        progressBar.setVisibility(View.GONE);
                        tvMSG.setText("There is no broader matches");
                        isLastPageLoaded = true;
                    
                    else 
                        parseData(response);
                        tvMSG.setVisibility(View.GONE);
                        progressBar.setVisibility(View.GONE);
                    
                
            ,
            new Response.ErrorListener() 
                @Override
                public void onErrorResponse(VolleyError error) 
                    progressBar.setVisibility(View.GONE);
                    Toast.makeText(getActivity(), "No More Items Available", Toast.LENGTH_SHORT).show();
                
            );
    return jsonArrayRequest;


private void getData() 
    if(!isLastPageLoaded)
        requestQueue.add(getDataFromServer(requestCount1));
        requestCount1++;
    

private void parseData(JSONArray array) 
    for (int i = 0; i < array.length(); i++) 
        SuperHero superHero = new SuperHero();
        JSONObject json = null;
        try 
            json = array.getJSONObject(i);
            superHero.setImageUrl(json.getString(Config_Test.TAG_IMAGE_URL));
            superHero.setMglId(json.getString(Config_Test.TAG_MGLID));
            superHero.setAge(json.getString(Config_Test.TAG_AGE));
            superHero.setAgeHeight(json.getString(Config_Test.TAG_AGEHEIGHT));
            superHero.setCommunity(json.getString(Config_Test.TAG_COMMUNITY));
            superHero.setCaste(json.getString(Config_Test.TAG_CASTE));
            superHero.setOccupation(json.getString(Config_Test.TAG_OCCUPATION));
            superHero.setIncome(json.getString(Config_Test.TAG_INCOME));
            superHero.setShortlist(json.getString(Config_Test.TAG_SHORTLIST));
            superHero.setExpress_Intrest(json.getString(Config_Test.TAG_EXPRESSINTREST));
         catch (JSONException e) 
            e.printStackTrace();
        
        listSuperHeroes.add(superHero);
    
    adapter.notifyDataSetChanged();

private boolean isLastItemDisplaying(RecyclerView recyclerView) 
    if (recyclerView.getAdapter().getItemCount() != 0) 
        lastVisibleItemPosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
        if (lastVisibleItemPosition != RecyclerView.NO_POSITION && lastVisibleItemPosition == recyclerView.getAdapter().getItemCount() - 1)
            return true;
    
    return false;
  

适配器代码

public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder>

private static final String url ="https://www.example.com";
private static final String url1 = "https://www.example.com";
private static final String KEY_MATRI_ID_TO="matriID_to";
private static final String KEY_MATRI_ID_BY="matriID_by";

SessionManager session;
public String matri_id_to, matri_id_by, str_gender;
String str_shortlist,str_EI;

//Imageloader to load image
private ImageLoader imageLoader;
private Context context;

//List to store all superheroes
List<SuperHero> superHeroes;

//Constructor of this class
public CardAdapter(List<SuperHero> superHeroes, Context context)
    super();
    //Getting all superheroes
    this.superHeroes = superHeroes;
    this.context = context;


@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 
    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.superheroes_list, parent, false);
    // Session class instance
    session = new SessionManager(context);
    session.checkLogin();
    // get user data from session
    HashMap<String, String> user = session.getUserDetails();
    matri_id_by = user.get(SessionManager.KEY_EMAIL);
    str_gender = user.get(SessionManager.KEY_GENDER);

    ViewHolder viewHolder = new ViewHolder(v);
    return viewHolder;


@Override
public void onBindViewHolder(final ViewHolder holder, final int position) 

    //Getting the particular item from the list
    final SuperHero superHero =  superHeroes.get(position);

    //Loading image from url
    imageLoader = CustomVolleyRequest.getInstance(context).getImageLoader();
    if(str_gender.equalsIgnoreCase("Male")) 
        imageLoader.get(superHero.getImageUrl(), ImageLoader.getImageListener(holder.imageView, R.drawable.image, R.drawable.girl));
    
    else 
        imageLoader.get(superHero.getImageUrl(), ImageLoader.getImageListener(holder.imageView, R.drawable.image, R.drawable.boy));
    

    int pos = getItemViewType(position);
    if(superHeroes.get(pos).getImageUrl() == null) 
        holder.imageView.setVisibility(View.GONE);
     else 
        holder.imageView.setImageUrl(superHero.getImageUrl(), imageLoader);
    

    holder.textViewId.setText(superHero.getMglId());
    holder.AgeHeight.setText(superHero.getAgeHeight()+" / "+superHero.getAge());
    holder.Community.setText(superHero.getCommunity()+" / "+superHero.getCaste());
    holder.Occupation.setText(superHero.getOccupation());
    holder.Income.setText(superHero.getIncome());

    str_shortlist = superHero.getShortlist();
    if(str_shortlist.toString().equalsIgnoreCase("Shortlisted")) 
        holder.btnShortlist.setText(str_shortlist);
        holder.btnShortlist.setBackgroundColor(Color.parseColor("#FF0E3671"));
        holder.btnShortlist.setEnabled(false);
    
    else
        holder.btnShortlist.setEnabled(true);
        holder.btnShortlist.setText(str_shortlist);
        holder.btnShortlist.setBackgroundColor(Color.parseColor("#2a7fff"));
    


    str_EI = superHero.getExpress_Intrest();
    Log.e("str_EI_____",str_EI);
    if(str_EI.toString().equalsIgnoreCase("Accepted")) 
        holder.btnEI.setText(str_EI);
        holder.btnEI.setBackgroundColor(Color.parseColor("#FF045B49"));
        holder.btnEI.setEnabled(false);
    
    else if(str_EI.toString().equalsIgnoreCase("Reject"))
        holder.btnEI.setText(str_EI);
        holder.btnEI.setBackgroundColor(Color.parseColor("#FF045B49"));
        holder.btnEI.setEnabled(false);
    
    else if(str_EI.toString().equalsIgnoreCase("Declined"))
        holder.btnEI.setText(str_EI);
        holder.btnEI.setBackgroundColor(Color.parseColor("#FF045B49"));
        holder.btnEI.setEnabled(false);
    
    else if(str_EI.toString().equalsIgnoreCase("Pending.."))
        holder.btnEI.setText(str_EI);
        holder.btnEI.setBackgroundColor(Color.parseColor("#FF045B49"));
        holder.btnEI.setEnabled(false);
    
    else
    
        holder.btnEI.setEnabled(true);
        holder.btnEI.setText(str_EI);
        holder.btnEI.setBackgroundColor(Color.parseColor("#00aa88"));
    


    holder.btnShortlist.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            superHero.setShortlist("Wait...");
            holder.btnShortlist.setText(superHero.getShortlist());
            matri_id_to = superHero.getMglId();
            holder.shortlist(position);
        
    );

    holder.btnViewProfile.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            Intent n = new Intent(holder.itemView.getContext(),BlankActivity.class);
            String str_id = holder.textViewId.getText().toString();
            n.putExtra("ID",str_id);
            holder.itemView.getContext().startActivity(n);
        
    );


    holder.btnEI.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            superHero.setExpress_Intrest("Wait...");
            holder.btnEI.setText(superHero.getExpress_Intrest());
            matri_id_to = superHero.getMglId();
            holder.expressInterest(position);
        
    );



public SuperHero getItem(int position)
    return superHeroes.get(position);


@Override
public int getItemCount() return superHeroes.size();

    @Override
    public int getItemViewType(int position) 
        return position;
    

class ViewHolder extends RecyclerView.ViewHolder
    public NetworkImageView imageView;
    public TextView textViewId;
    public TextView AgeHeight;
    public TextView Community;
    public TextView Occupation;
    public TextView Income;

    public Button btnShortlist;
    public Button btnViewProfile;
    public Button btnEI;

    //Initializing Views
    public ViewHolder(final View itemView) 
        super(itemView);
        imageView = (NetworkImageView) itemView.findViewById(R.id.imageViewHero);
        textViewId = (TextView) itemView.findViewById(R.id.textViewId);
        AgeHeight = (TextView) itemView.findViewById(R.id.AgeHeight);
        Community = (TextView) itemView.findViewById(R.id.Community);
        Occupation = (TextView) itemView.findViewById(R.id.Occupation);
        Income = (TextView) itemView.findViewById(R.id.Income);
        btnShortlist = (Button) itemView.findViewById(R.id.btnshort);
        btnViewProfile = (Button) itemView.findViewById(R.id.buttonViewProfile);
        btnEI = (Button) itemView.findViewById(R.id.btnExpressIntrest);
    

    public void shortlist(final int position) 
        StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() 
            @Override
            public void onResponse(String response) 
                if (response.trim().equalsIgnoreCase("success")) 
                    superHeroes.get(position).setShortlist("Shortlisted");
                    // holder.btnShortlist.setText(superHero.getShortlist());
                    notifyDataSetChanged();
                
            
        ,
                new Response.ErrorListener() 
                    @Override
                    public void onErrorResponse(VolleyError error) 
                        Toast.makeText(context, error.toString(), Toast.LENGTH_LONG).show();
                    
                ) 
            @Override
            protected Map<String, String> getParams() 
                Map<String, String> params = new HashMap<String, String>();
                params.put(KEY_MATRI_ID_BY, matri_id_by);
                params.put(KEY_MATRI_ID_TO, matri_id_to);
                return params;
            
        ;
        RequestQueue requestQueue = Volley.newRequestQueue(context);
        requestQueue.add(stringRequest);
    

    public void expressInterest(final int position) 
        StringRequest stringRequest1 = new StringRequest(Request.Method.POST, url1, new Response.Listener<String>() 
            @Override
            public void onResponse(String response) 
                if(response.trim().equalsIgnoreCase("success")) 
                    superHeroes.get(position).setExpress_Intrest("Pending..");
                    notifyDataSetChanged();
                
            
        ,
                new Response.ErrorListener() 
                    @Override
                    public void onErrorResponse(VolleyError error) 
                        Toast.makeText(context, error.toString(), Toast.LENGTH_LONG).show();
                    
                ) 
            @Override
            protected Map<String, String> getParams() 
                Map<String, String> params = new HashMap<String, String>();
                params.put(KEY_MATRI_ID_BY,matri_id_by);
                params.put(KEY_MATRI_ID_TO,matri_id_to);
                return params;
            
        ;
        RequestQueue requestQueue = Volley.newRequestQueue(context);
        requestQueue.add(stringRequest1);
    
   
  

【问题讨论】:

请发布适配器代码 请检查更新后的代码 看这里:***.com/a/65645664/3904109 【参考方案1】:

保存实例代码:

Parcelable mListState;

protected void onSaveInstanceState(Bundle state) 
     super.onSaveInstanceState(state);

     // Save list state
     mListState = mLayoutManager.onSaveInstanceState();
     state.putParcelable(LIST_STATE_KEY, mListState);

恢复状态码:

protected void onRestoreInstanceState(Bundle state) 
    super.onRestoreInstanceState(state);

    // Retrieve list state and list/item positions
    if(state != null)
        mListState = state.getParcelable(LIST_STATE_KEY);

在 onResume() 中更新布局管理器:

@Override
protected void onResume() 
    super.onResume();

    if (mListState != null) 
        mLayoutManager.onRestoreInstanceState(mListState);
    

希望对你有帮助

【讨论】:

【参考方案2】:

主要问题是 onPause 您正在清除整个数据,当片段再次可见时,您正在从页面 1 请求服务器。注释以下代码。

    @Override
public void onPause()
    super.onPause();
    //listSuperHeroes.clear();
    //adapter.notifyDataSetChanged();
    //requestCount1=1;
   
  

在此处更新 isLastPageLoaded:

private boolean isLastPageUpdated = false;
     private JsonArrayRequest getDataFromServer(int requestCount) 
            final String DATA_URL = "https://www.XYZ.php?matri_id="+email+"&page=";
            JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(DATA_URL + String.valueOf(requestCount),
                    new Response.Listener<JSONArray>() 
                        @Override
                        public void onResponse(JSONArray response) 
                            if (response.length() == 0) 
                                progressBar.setVisibility(View.GONE);
                                tvMSG.setText("There is no broader matches");
                    isLastPageLoaded = true;
                            
                            else 
                                parseData(response);
                                tvMSG.setVisibility(View.GONE);
                                progressBar.setVisibility(View.GONE);
                            
                        
                    ,
                    new Response.ErrorListener() 
                        @Override
                        public void onErrorResponse(VolleyError error) 
                            progressBar.setVisibility(View.GONE);
                            Toast.makeText(getActivity(), "No More Items 
                            Available", Toast.LENGTH_SHORT).show();
                        
                    );
            return jsonArrayRequest;
        

在getData()中

 private void getData() 
if(!isLastPageUpdated)
    requestQueue.add(getDataFromServer(requestCount1));
    requestCount1++;

【讨论】:

所以当你启动新的活动时,片段的 onPause 方法被调用并且所有适配器数据都被清除。当您从当前活动按下返回按钮时,onresume() 方法与 setUserVisiblityHint() 方法一起被调用。 onPause 方法将 requestcount 值设置为 1,因此您只能为第一页加载数据。假设您单击了第 5 页上的项目,所以回到片段您只有第一页数据。您如何假设只有第一页数据的回收站视图应该滚动到第 5 页?? 当我滚动所有项目并更改选项卡并返回上一个选项卡时,它会显示“没有更多可用项目” 是的,因为如果您移动到当前片段的相邻选项卡,则当前片段在内存中,如果您移动到前一个片段,则不会再次加载它。在片段中,您已移至最后一页。 创建一个标志值来跟踪 pageCount。如果您已经达到了页面的最大数量,则不要在 setUserVisiblityHint 方法中调用 getData 方法。 取一个布尔值 isLastPageLoaded = false;当你到达最后一页时 make isLastPageLoaded = true;在@Override public void setUserVisibleHint(boolean isVisibleToUser) super.setUserVisibleHint(isVisibleToUser); isVisible = isVisibleToUser; if (isStarted && isVisible && (!isLastPageLoaded)) getData(); 【参考方案3】:

将适配器的位置保存在适配器的某个变量中。使用

将滚动更改到后按时的该位置
linearLayoutManager.scrollToPositionWithOffset(int, int);

内部活动。

【讨论】:

【参考方案4】:

你需要重写 onBackPressed() 并添加 recyclerView.scrollToPosition(position);

@Override
public void onBackPressed() 
    super.onBackPressed();
    recyclerView.scrollToPosition(position);
    finish();

【讨论】:

我应该在哪里使用这个方法 在您的视图配置文件活动中。您可以将当前位置传递给该活动的捆绑包 您也可以将recyclerView.scrollToPosition(position); 放入您的Broader_Match_Tab onResume() 并将位置设为静态 这行不通,请检查@Arvind 的答案,他在哪里评论 onPause 代码。【参考方案5】:

保存在 onSaveInstanceState 中点击的项目的位置并将其传递给 scrollToPosition 或

下面试试

private static final String SELECTED_KEY = "selected_position";

@Override
    public void onSaveInstanceState(Bundle outState) 
        lastFirstVisiblePosition = ((LinearLayoutManager)mRecylerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
        outState.putInt(SELECTED_KEY, lastFirstVisiblePosition);
    

在 Oncreate 中

已编辑..

if(savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY))
        
            lastFirstVisiblePosition = savedInstanceState.getInt(SELECTED_KEY);


        

使用 ((LinearLayoutManager) mRecylerView.getLayoutManager()).scrollToPosition(lastFirstVisiblePosition) 或

mRecylerView.smoothScrollToPosition(lastFirstVisiblePosition); 填充数据后,最好在 adapter.notifyDataSetChanged();

【讨论】:

使用 int lastFirstVisiblePosition=-1;首先是顶部的第一个视图(recyclerview 项)。 请查看更新后的答案,重要的是在填充数据后使用下面的行,mRecylerView.smoothScrollToPosition(mPosition);【参考方案6】:

我之前遇到过同样的问题,然后我用一个更简单的解决方案解决了我的问题。我只是在onViewCreated() 中调用了适配器.startListening(); 而不是onStart 并在onDestroyView() 中调用了适配器.stopListening(); 而不是onStop()。 这会阻止整个列表在从下一个活动返回时重新生成,从而保留之前的滚动位置。

【讨论】:

【参考方案7】:

我已经解决了如下问题:

在 onViewCreated 和 onStart 中都调用了 .startListening

在 onDestroyView 中调用 .stopListening

不要在 onStop 中调用 .stopListening

我在片段中的代码如下:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle 
savedInstanceState) 
    super.onViewCreated(view, savedInstanceState);
    if (mAdapterHb != null) 
        mAdapterHb.startListening();
    

@Override
public void onStart() 
    super.onStart();
    if (mAdapterHb != null) 
        mAdapterHb.startListening();
    


@Override
public void onStop() 
    super.onStop();
//        if (mAdapterHb != null) 
//            mAdapterHb.stopListening();
//        


@Override
public void onDestroyView() 
    super.onDestroyView();
    if (mAdapterHb != null) 
        mAdapterHb.stopListening();
    

【讨论】:

以上是关于单击后退按钮时,在 RecyclerView 中获得相同的项目位置的主要内容,如果未能解决你的问题,请参考以下文章

当我单击浏览器后退按钮或移动设备后退按钮时,保留选定的选项卡

为啥在我第一次单击按钮时在我的 RecyclerView 中调用绑定?

Flutter单击后退按钮时如何执行

在执行功能时单击导航控制器上的后退按钮时应用程序崩溃

在android qtquick中单击后退按钮时应用程序退出

Javascript/jQuery 仅在浏览器后退/前进按钮单击时检测哈希更改