【问题标题】:RecyclerView + Adapter is not visible after create first time on Fragment第一次在 Fragment 上创建后,RecyclerView + Adapter 不可见
【发布时间】:2016-11-24 03:38:55
【问题描述】:

我有一个片段,其中包含一个 RecyclerView,这是用改造 2 填充的,在我的侦听器中填充适配器并在 RecyclerView 上设置。

如果应用程序被杀死并重新启动,当我第一次打开这个片段时会正确显示,但如果我按下 后退按钮 或者如果更改片段,当我尝试进入相同的永远不会显示带有适配器的 RecyclerView 片段。

我在 gradle 上使用这个:

compile 'com.android.support:cardview-v7:25.0.1'
compile 'com.android.support:recyclerview-v7:25.0.1'
compile 'com.android.support:support-v4:25.0.1'

这是我的 XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">

<include
    android:id="@+id/my_toolbar"
    layout="@layout/standard_toolbar" />

<com.sample.ui.CustomSwipeRefreshLayout
    android:id="@+id/ptr_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="visible">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <include
            android:id="@+id/empty_rewards"
            layout="@layout/no_near_by_rewards"
            android:visibility="gone"/>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rewards_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="vertical"/>

    </LinearLayout>

</com.sample.ui.CustomSwipeRefreshLayoutt>
</LinearLayout>

这是我的片段类:

public class RewardsListFragment extends BaseFragment implements GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener, LocationListener {

public static volatile boolean refreshOffersListFragment = false;
public static boolean comingFromDetailFragment = false;
private static GoogleApiClient locationClient;

private int LIMIT = 7;

private View noRewards;

ArrayList<MerchantListItem> nMerchantList = new ArrayList<>();

private RewardsRVArrayAdapter mAdapter;
private RecyclerView rList;

// Bool to track whether the app is already resolving an error
private boolean resolvingError = false;
private boolean awaitingPermission = false;
private boolean appSettingsSelected = false;
private boolean locationSettingsSelected = false;
private boolean gpsOffScreenDisplayed = false;
private boolean awaitingHomeCoordinates = true;

private double homeLatitude = 0.0;
private double homeLongitude = 0.0;
private Location currentLocation = null;
private String permissionStatus;

MerchantListRequest listRequest;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.rewards_list_fragment_2, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    rList = (RecyclerView) view.findViewById(rewards_list);
    noRewards = view.findViewById(R.id.empty_rewards);

    rList.setHasFixedSize(true);
    LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    rList.setLayoutManager(layoutManager);
}

@Override
public void onDetach() {
    super.onDetach();
    if(mAdapter != null)
    {
        mAdapter = null;
    }

    if(rList.getAdapter() != null)
    {
        rList.setAdapter(null);
    }

    if(listRequest != null) {
        listRequest.getCall().cancel();
    }
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    homeLatitude = ChimeApplication.user.latitude;
    homeLongitude = ChimeApplication.user.longitude;

    startIndeterminateProgress();
    currentLocation = new Location("");
    currentLocation.setLatitude(homeLatitude);
    currentLocation.setLongitude(homeLongitude);
    awaitingHomeCoordinates = false;

    mAdapter = new RewardsRVArrayAdapter(new ArrayList<MerchantListItem>());
    rList.setAdapter(mAdapter);

}

@Override
public void onResume() {
    super.onResume();
    getRewards();
}

private void refreshOffers() {
        startIndeterminateProgress();
        final int first_row = 0;
        final int num_rows = LIMIT;
        listRequest = new MerchantListRequest(parentActivity, currentLocation.getLatitude(), currentLocation.getLongitude(), first_row, num_rows);
        listRequest.execute(new MerchantListRequestListener(getContext()));
}

@Override
public void onRefresh() {
    refreshOffersListFragment = true;
    refreshOffers();
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.offers_list_menu, menu);
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.refresh) {
        refreshOffersListFragment = true;
        refreshOffers();
        return true;
    }

    return false;
}

@Override
public void onPause() {
    super.onPause();

    if (locationClient != null && locationClient.isConnected()) {
        locationClient.disconnect();
    }
}

private void showList() {
    noRewards.setVisibility(View.GONE);
    rList.setVisibility(View.VISIBLE);
}

private void hideList() {
    noRewards.setVisibility(View.VISIBLE);
    rList.setVisibility(View.GONE);
}

private void setMerchantsList(ArrayList<MerchantListItem> results) {

    if (nMerchantList != null && nMerchantList.size() > 0) {
        nMerchantList.clear();
    }

    for (MerchantListItem item : results) {
        nMerchantList.add(item);
    }

    if (mAdapter == null) {
        mAdapter = new RewardsRVArrayAdapter(nMerchantList);
        rList.setAdapter(null);
        rList.setAdapter(mAdapter);
    } else {
        mAdapter.addAll(nMerchantList);
        rList.postInvalidate();
    }
}

private class MerchantListRequestListener extends BaseRetrofitRequestListener<MerchantListResult> {

    public MerchantListRequestListener(Context context) {
        super(context);
    }

    @Override
    public void onRequestFailed(int code, String errorMessage) {
        android.util.Log.e("RECYCLERVIEW", "FAIL request");
        stopIndeterminateProgress();
        dialogCheck();
        if (errorMessage != null && !errorMessage.isEmpty() && isVisible()) {
            Toast.makeText(context, errorMessage, Toast.LENGTH_LONG).show();
            hideList();
        }
    }

    @Override
    public void onRequestSuccessful(Response<MerchantListResult> response) {
        dialogCheck();
        stopIndeterminateProgress();
        if (response != null && response.body().results != null) {
            showList();

            setMerchantsList(response.body().results);


        } else {
            hideList();
        }
    }

    private void dialogCheck() {
        if (!Utils.isHighAccuracySet(parentActivity) && ContextCompat.checkSelfPermission(parentActivity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
                ContextCompat.checkSelfPermission(parentActivity, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            displayGPSOffDialog();
        }
    }
}

private void getRewards() {
    if (ContextCompat.checkSelfPermission(parentActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        if (!(RewardsListFragment.this).shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                awaitingPermission = true;
                (RewardsListFragment.this).requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
                                Manifest.permission.ACCESS_COARSE_LOCATION},
                        PermConst.REWARDS_LOCATION_PERMISSION_REQUESTED);
            }
        } else {
            displayPermissionDeniedDialog();
            final int first_row = 0;
            final int num_rows = LIMIT;

            listRequest = new MerchantListRequest(parentActivity, currentLocation.getLatitude(), currentLocation.getLongitude(), first_row, num_rows);
            listRequest.execute(new MerchantListRequestListener(parentActivity));
            awaitingPermission = false;
        }

    } else {
        if (locationClient != null && !locationClient.isConnected() && Utils.isHighAccuracySet(parentActivity)) {
            // Turn off no offers and gps disabled screens only if the no offers screen is not currently displayed.
            locationClient.connect();
        } else {
            if (locationClient == null && Utils.isHighAccuracySet(parentActivity)) {
                refreshOffersListFragment = true;
                locationClient = new GoogleApiClient.Builder(parentActivity.getApplicationContext())
                        .addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
                locationClient.connect();
            } else {
                final int first_row = 0;
                final int num_rows = LIMIT;

                listRequest = new MerchantListRequest(parentActivity, currentLocation.getLatitude(), currentLocation.getLongitude(), first_row, num_rows);
                listRequest.execute(new MerchantListRequestListener(parentActivity));
                if (!Utils.isHighAccuracySet(parentActivity)) {
                    gpsOffScreenDisplayed = true;
                }
            }
        }
        awaitingPermission = false;
    }

    mPullToRefreshLayout.setEnabled(true);

}

最后这是我的适配器:

public class RewardsRVArrayAdapter extends RecyclerView.Adapter<RewardsRVArrayAdapter.ViewHolder> {

private List<MerchantListItem> results;
private final int sdkVersion;
private Bitmap defaultImage;
private final DecimalFormat dollarFormatter = new DecimalFormat("$##.##");

private int lastAnimatedPosition = -1;

public RewardsRVArrayAdapter(List<MerchantListItem> results) {
    this.results = results;
    sdkVersion = Utils.getSDKVersion();
    setHasStableIds(false);
}

@Override
public RewardsRVArrayAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // create a new view
    defaultImage = BitmapFactory.decodeResource(parent.getContext().getResources(), R.drawable.big_text);
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.rewards_list_item, parent, false);
    // set the view's size, margins, paddings and layout parameters
    return new ViewHolder(v);
}

@Override
public void onViewAttachedToWindow(ViewHolder holder) {
    super.onViewAttachedToWindow(holder);
}

@Override
public void onViewDetachedFromWindow(ViewHolder holder) {
    super.onViewDetachedFromWindow(holder);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    MerchantListItem offerItem = results.get(position);
    Deal deal = offerItem.deal != null ? offerItem.deal : null;

    if (offerItem.type.equalsIgnoreCase(Const.MERCHANT_MERCHANT_STRING)) {
        setMerchant(holder, offerItem, deal);
    } else if (offerItem.type.equalsIgnoreCase(Const.MERCHANT_REWARD_STRING)) {

        setCategoryReward(holder, deal);
    }

    //Set up the banner
    if (offerItem.banner != null && offerItem.banner.text != null && !offerItem.banner.text.isEmpty()) {
        holder.banner.setVisibility(View.VISIBLE);
        holder.banner.setText(offerItem.banner.text);

        //Set color of banner based on type
        if (offerItem.banner.type.equalsIgnoreCase(Banner.TYPE_FEATURED)) {
            holder.banner.setBackgroundResource(R.drawable.yellow_banner);
            holder.banner.setTextColorRes(R.color.text);
        } else if (offerItem.banner.type.equalsIgnoreCase(Banner.TYPE_PERSONALIZED)) {
            holder.banner.setBackgroundResource(R.drawable.blue_banner);
            holder.banner.setTextColorRes(android.R.color.white);
        } else if (offerItem.banner.type.equalsIgnoreCase(Banner.TYPE_LIMITED)) {
            holder.banner.setBackgroundResource(R.drawable.orange_banner);
            holder.banner.setTextColorRes(android.R.color.white);
        }

        //For some reason padding did not work in XML so I moved it here
        holder.banner.setPadding(Utils.convertDpToPixel(10, holder.banner.getContext()), Utils.convertDpToPixel(3, holder.banner.getContext()),
                Utils.convertDpToPixel(10, holder.banner.getContext()), Utils.convertDpToPixel(3, holder.banner.getContext()));
    } else {
        holder.banner.setVisibility(View.GONE);
    }
}

@Override
public int getItemCount() {
    return results != null ? results.size() : 0;
}

public MerchantListItem getItemAtPosition(int position)
{
    return results.get(position);
}

public void addAll(ArrayList<MerchantListItem> newResults)
{
    this.results.clear();
    for(MerchantListItem item : newResults)
    {
        this.results.add(item);
    }
    dataSetChanged();
}

@UiThread
protected void dataSetChanged() {
    notifyDataSetChanged();
}

private void setMerchant(final ViewHolder viewHolder, final MerchantListItem offerItem, final Deal deal) {
    loadCardImage(offerItem.image_url, viewHolder);
    viewHolder.merchant_name_txt.setText(offerItem.name);

    if (deal != null) {
        viewHolder.merchant_offer_txt.setText(deal.name);
        viewHolder.offer_amount.setText(dollarFormatter.format(deal.promotional_value));
    }
}

private void setCategoryReward(final ViewHolder viewHolder, Deal deal) {
    if(deal != null)
    {
        loadCardImage(deal.category_reward.card_image_url, viewHolder);
        viewHolder.merchant_name_txt.setText(deal.category_reward.card_title);
        viewHolder.merchant_offer_txt.setText(deal.name);
        viewHolder.offer_amount.setText(dollarFormatter.format(deal.promotional_value));
    }
}

private void loadCardImage(String url, final ViewHolder viewHolder) {
    if (url != null && !url.isEmpty()) {
        Picasso.with(viewHolder.main_layout.getContext()).load(url).memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE ).fit().networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE, NetworkPolicy.OFFLINE).into(viewHolder.main_layout);
    } else {
        setDefaultImage(viewHolder.main_layout);
    }

}

@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
private void setBackgroundImage(View view, Drawable drawable) {
    //FIXME we can remove this because we don't support any below to API 16 (JELLY BEAN)
    if (sdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
        view.setBackgroundDrawable(drawable);
    } else {
        view.setBackground(drawable);
    }
}

public static class ViewHolder extends RecyclerView.ViewHolder {
    // each data item is just a string in this case
    ButtonTextView banner;
    ButtonTextView merchant_name_txt;
    HeaderTextView merchant_offer_txt;
    ImageView main_layout;
    ButtonTextView offer_amount;
    public ViewHolder(View v) {
        super(v);
        banner = (ButtonTextView) v.findViewById(R.id.banner);
        merchant_name_txt = (ButtonTextView) v.findViewById(R.id.merchant_name_txt);
        merchant_offer_txt = (HeaderTextView) v.findViewById(R.id.merchant_reward_txt);
        main_layout = (ImageView) v.findViewById(R.id.image_layout);
        offer_amount = (ButtonTextView) v.findViewById(R.id.reward_amount);
    }
}

}

奇怪的是,这发生在 Android M 和 N 上,但现在发生在 Android L 上,我之前通过 支持库阅读了 RecyclerView 的一些问题> 但我找不到解决方案。

附上一张 gif 来检查行为是什么 Gif bug RecyclerView

【问题讨论】:

    标签: android listview android-fragments android-recyclerview adapter


    【解决方案1】:

    由于我不能直接检查,因为你的项目有很多依赖项,我建议你记录你方法的每个部分。

    我想你的 getRewards() 方法有一些错误。 如果您的刷新方法工作正常,您可以使用

    private boolean firstTime = true;
    
    @Override
    public void onResume() {
        super.onResume();
        if(firstTime){
            getRewards();
            firstTime = false;    
        }
        else{
            onRefresh();
        }
    }
    

    改为

    【讨论】:

    • 我检查了每个方法,getRewards() 工作正常,只是检查 locationClient 是否为空或已连接。
    • 我会投票赞成你的答案,有一段时间很有帮助,但这并不能解决问题,因为我正在寻求许可,并重新制作我的 getRewards 方法并解决了问题。
    • @DiegoF 谢谢,正如我之前提到的,如果您的刷新方法运行良好,则此答案只是一种解决方法。我无法用你的代码复制这个问题,因为你只包含有限的代码,而你的项目有很多依赖项
    【解决方案2】:

    在RewardsListFragment的onCreateView中添加以下代码

    mAdapter = new RewardsRVArrayAdapter(new ArrayList<MerchantListItem>());
    rList.setAdapter(mAdapter);
    

    【讨论】:

    • 不,这仍然无法正常工作,由于某种原因,当我走到片段并返回时,RecyclerView 有最后一个适配器的引用,如果我尝试输入 null,这不会任何变化
    • 那你也试试onresume
    猜你喜欢
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    • 1970-01-01
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    相关资源
    最近更新 更多