【问题标题】:why findviewbyposition( ) of recyclerView returns null only sometimes为什么recyclerView的findviewbyposition()有时只返回null
【发布时间】:2016-05-27 14:42:41
【问题描述】:

这是我的代码:

public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{

    View rootView =  inflater.inflate(R.layout.fragment_add_aircraft, container, false);

    recyclerView=(RecyclerView)rootView.findViewById(R.id.recyclerAircraftAdd);
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
    recyclerView.setLayoutManager(layoutManager);
    adapter = new AircraftAdapter(getActivity(),path);
    recyclerView.setAdapter(adapter);
    Button button = (Button)rootView.findViewById(R.id.salvaereo);

    button.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
          adapter = (AircraftAdapter)recyclerView.getAdapter();
          ParseObject aircraft = new ParseObject("Aircrafts");

           for(int i = 0;i<adapter.getItemCount(); i++)
           {
             if (i== 0)  //first card
             {
                View view = recyclerView.getLayoutManager().findViewByPosition(i);
                ImageView image = (ImageView)view.findViewById(R.id.aircfraftImg);
                image.setDrawingCacheEnabled(true);
                image.buildDrawingCache();
                Bitmap bm = image.getDrawingCache();
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                bm.compress(Bitmap.CompressFormat.PNG, 100, stream);
                byte[] bytes = stream.toByteArray();
                ParseFile file = new ParseFile("Image.jpg",bytes);
                aircraft.put("aircraft_image",file);

                 file.saveInBackground(new SaveCallback() {
                     @Override
                     public void done(ParseException e) {
                         Log.d("sa","tutto ok");
                     }
                 });

             }
             else if (i ==1) //second card
             {
                 View view = recyclerView.getLayoutManager().findViewByPosition(i);
                 EditText immatricolazione =(EditText)view.findViewById(R.id.immatricolazione);
                 EditText modello = (EditText)view.findViewById(R.id.modello);
                 EditText manifacturer = (EditText)view.findViewById(R.id.manifacturer);
                 EditText categoria = (EditText)view.findViewById(R.id.categoria);
                 EditText classe = (EditText)view.findViewById(R.id.classe);
                 EditText velocita = (EditText)view.findViewById(R.id.velocita);
                 EditText autonomia = (EditText)view.findViewById(R.id.autonomia);
                 EditText consumo = (EditText)view.findViewById(R.id.consumo);
                 EditText posti = (EditText)view.findViewById(R.id.postitotali);
                 EditText costo = (EditText)view.findViewById(R.id.costorario);

                 aircraft.put("re",immatricolazione.getEditableText().toString());
                 aircraft.put("ml",modello.getEditableText().toString());
                 aircraft.put("man",manifacturer.getEditableText().toString());
                 aircraft.put("Aircraft_Type",categoria.getEditableText().toString());
                 aircraft.put("ar",classe.getEditableText().toString());
                 aircraft.put("post",Integer.parseInt(posti.getEditableText().toString()));
                 aircraft.put("meter",Integer.parseInt(consumo.getEditableText().toString()));
                 aircraft.put("speed",Integer.parseInt(velocita.getEditableText().toString()));
                 aircraft.put("prezzi",Float.parseFloat(costo.getEditableText().toString()));
                 aircraft.put("fuel",Integer.parseInt(autonomia.getEditableText().toString()));
             }
             else if(i==2) //third card
             {
                 View view = recyclerView.getLayoutManager().findViewByPosition(i);
                 EditText description = (EditText) view.findViewById(R.id.description);
                 aircraft.put("descrizione", description.getEditableText().toString());

                 aircraft.put("User", ParseUser.getCurrentUser());

                 dialog = ProgressDialog.show(getActivity(), "", "Caricamento aereo in corso...", true);

                 aircraft.saveInBackground(new SaveCallback() {

                     public void done(ParseException e) {
                         dialog.dismiss();

                         if (e == null) {
                             new AlertDialog.Builder(getActivity())
                                     .setMessage("Caricamento aereo avvenuto con successo!")
                                     .setCancelable(false)
                                     .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                                         @Override
                                         public void onClick(DialogInterface dialog, int which) {

                                         }
                                     }).create().show();
                         } else {
                             new AlertDialog.Builder(getActivity())
                                     .setMessage("Non è stato possibile caricare l'aereo, riprova più tardi!")
                                     .setCancelable(false)
                                     .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                                         @Override
                                         public void onClick(DialogInterface dialog, int which) {

                                         }
                                     }).create().show();
                         }


                     }
                 });
             }
           }

        }
    });

    return rootView;
}

但是有这个问题:如果我为照片(第一张卡)充电并按下按钮,它会上传照片,但如果我写入 EditText,它会崩溃并给我这个错误:

进程:com.run.flyproject,PID:10796 java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法 'android.view.View android.view.View.findViewById(int)' 在 com.run.flyproject.Fragments.AddAircraftFragment$1.onClick(AddAircraftFragment.java:78) 在 android.view.View.performClick(View.java:4756) 在 android.view.View$PerformClick.run(View.java:19749) 在 android.os.Handler.handleCallback(Handler.java:739) 在 android.os.Handler.dispatchMessage(Handler.java:95) 在 android.os.Looper.loop(Looper.java:135) 在 android.app.ActivityThread.main(ActivityThread.java:5253) 在 java.lang.reflect.Method.invoke(本机方法) 在 java.lang.reflect.Method.invoke(Method.java:372) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

【问题讨论】:

  • View数和Item数不一样。 RecyclerView 只创建填充其大小所需的视图。返回的 null 表示该项目位置的视图不存在。
  • 但我只有 3 个视图..
  • "如果位置未布置则为空"。无论哪种方式,视图都不存在,您必须为此做好准备。 developer.android.com/reference/android/support/v7/widget/…
  • 那我该如何解决呢?
  • 声明你的 rootView final 并在你的 onClickListener 中使用rootView.findViewById(...);。这仍然是 hacky,您需要使用 ViewHolders。

标签: android android-recyclerview


【解决方案1】:

这并不是一个明确的答案(明确的答案类似于“您的适配器计数与您的适配器提供的视图不一致”),但我的 cmets 可能有点混乱。你可以做这样的事情......

public class YourAdapter extends RecyclerView.Adapter<YourViewHolder>{

    private boolean mSaveImages = false;
    private SparseArray<Boolean> mImageSavedFlags = new SparseArray<>();

    public void toggleSaveStatus(){
        mSaveImages = !mSaveImages;
    }

    // ... your code

    @Override
    public void onBindViewHolder(YourViewHolder holder, final int position) {
        // Could also manage this in a loop or something
        // in your constructor/when you set your adapter data
        // but this will set our SparseArray
        if(mImageSavedFlags.get(position) == null)
            mImageSavedFlags.put(position, false);

        // ... your code
        if(mSaveImages && !mImageSavedFlags.get(position){
            // ... save your image
            mImageSavedFlags.put(position, true);
        }
    }

    // ... your code
}

这样,每当您尝试绑定视图时,您都可以检查是否要保存 ImageViews 源以及是否尚未保存,如果尚未保存,它将保存源并更新 SparseArray。

要切换您的状态,只需执行以下操作

button.setOnClickListener(new View.OnClickListener()
{
    @Override
    public void onClick(View v){
        adapter.toggleSaveStatus();
    }
}

值得注意的是,这只会保存您在打开保存设置后实际滚动到的图像。我想你可以强制滚动你的 RecyclerView 但这会涉及到别的东西。

同样重要的是要意识到,如果您正在执行诸如从 URL 或基于位置或其他内容的可绘制对象加载图像之类的操作,您实际上并不需要您的 ImageView 在保存之前加载源代码,那里有很多方法(包括库)可以保存尚未显式加载到您的应用中的图像,这将完全消除在此过程中包含适配器的需要。

我确信这不是唯一的方法,我确信这不是最好的答案,但我的 cmets 再次变得有点混乱。

【讨论】:

    【解决方案2】:

    你可以同时使用

    recyclerViewInstance.findViewHolderForAdapterPosition(adapterPosition) 和 recyclerViewInstance.findViewHolderForLayoutPosition(layoutPosition)。 确保 RecyclerView 视图使用两种类型的位置

    适配器位置:适配器中项目的位置。这是从适配器的角度来看的位置。 布局位置 : 项目在最新布局计算中的位置。这是从 LayoutManager 的角度来看的位置。 您应该对 findViewHolderForAdapterPosition(adpterPosition) 使用 getAdapterPosition(),对 findViewHolderForLayoutPosition(layoutPosition) 使用 getLayoutPosition()。

    取一个成员变量来保存recyclerview适配器中先前选择的项目位置和其他成员变量来检查用户是否是第一次点击。

    底部附有示例代码和屏幕截图以获取更多信息。

    public class MainActivity extends AppCompatActivity {     
    
    private RecyclerView mRecyclerList = null;    
    private RecyclerAdapter adapter = null;    
    
    @Override    
    protected void onCreate(Bundle savedInstanceState) {    
        super.onCreate(savedInstanceState);    
        setContentView(R.layout.activity_main);    
    
        mRecyclerList = (RecyclerView) findViewById(R.id.recyclerList);    
    }    
    
    @Override    
    protected void onStart() {    
        RecyclerView.LayoutManager layoutManager = null;    
        String[] daysArray = new String[15];    
        String[] datesArray = new String[15];    
    
        super.onStart();    
        for (int i = 0; i < daysArray.length; i++){    
            daysArray[i] = "Sunday";    
            datesArray[i] = "12 Feb 2017";    
        }    
    
        adapter = new RecyclerAdapter(mRecyclerList, daysArray, datesArray);    
        layoutManager = new LinearLayoutManager(MainActivity.this);    
        mRecyclerList.setAdapter(adapter);    
        mRecyclerList.setLayoutManager(layoutManager);    
    }    
    }    
    
    
    public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyCardViewHolder>{          
    
    private final String TAG = "RecyclerAdapter";        
    private Context mContext = null;        
    private TextView mDaysTxt = null, mDateTxt = null;    
    private LinearLayout mDateContainerLayout = null;    
    private String[] daysArray = null, datesArray = null;    
    private RecyclerView mRecyclerList = null;    
    private int previousPosition = 0;    
    private boolean flagFirstItemSelected = false;    
    
    public RecyclerAdapter(RecyclerView mRecyclerList, String[] daysArray, String[] datesArray){    
        this.mRecyclerList = mRecyclerList;    
        this.daysArray = daysArray;    
        this.datesArray = datesArray;    
    }    
    
    @Override    
    public MyCardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {    
        LayoutInflater layoutInflater = null;    
        View view = null;    
        MyCardViewHolder cardViewHolder = null;    
        mContext = parent.getContext();    
        layoutInflater = LayoutInflater.from(mContext);    
        view = layoutInflater.inflate(R.layout.date_card_row, parent, false);    
        cardViewHolder = new MyCardViewHolder(view);    
        return cardViewHolder;    
    }    
    
    @Override    
    public void onBindViewHolder(MyCardViewHolder holder, final int position) {    
        mDaysTxt = holder.mDaysTxt;    
        mDateTxt = holder.mDateTxt;    
        mDateContainerLayout = holder.mDateContainerLayout;    
    
        mDaysTxt.setText(daysArray[position]);    
        mDateTxt.setText(datesArray[position]);    
    
        if (!flagFirstItemSelected){    
            mDateContainerLayout.setBackgroundColor(Color.GREEN);    
            flagFirstItemSelected = true;    
        }else {    
            mDateContainerLayout.setBackground(null);    
        }    
    }    
    
    @Override    
    public int getItemCount() {    
        return daysArray.length;    
    }    
    
    class MyCardViewHolder extends RecyclerView.ViewHolder{    
        TextView mDaysTxt = null, mDateTxt = null;    
        LinearLayout mDateContainerLayout = null;    
        LinearLayout linearLayout = null;    
        View view = null;    
        MyCardViewHolder myCardViewHolder = null;    
    
        public MyCardViewHolder(View itemView) {    
            super(itemView);    
            mDaysTxt = (TextView) itemView.findViewById(R.id.daysTxt);    
            mDateTxt = (TextView) itemView.findViewById(R.id.dateTxt);    
            mDateContainerLayout = (LinearLayout) itemView.findViewById(R.id.dateContainerLayout);    
    
            mDateContainerLayout.setOnClickListener(new View.OnClickListener() {    
                @Override    
                public void onClick(View v) {    
                    LinearLayout linearLayout = null;    
                    View view = null;    
    
                    if (getAdapterPosition() == previousPosition){    
                        view = mRecyclerList.findViewHolderForAdapterPosition(previousPosition).itemView;    
                        linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);    
                        linearLayout.setBackgroundColor(Color.GREEN);    
                        previousPosition = getAdapterPosition();    
    
                    }else {    
                        view = mRecyclerList.findViewHolderForAdapterPosition(previousPosition).itemView;    
                        linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);    
                        linearLayout.setBackground(null);    
    
                        view = mRecyclerList.findViewHolderForAdapterPosition(getAdapterPosition()).itemView;    
                        linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);    
                        linearLayout.setBackgroundColor(Color.GREEN);    
                        previousPosition = getAdapterPosition();    
                    }    
                }    
            });    
        }    
    }       
    

    } 1
    来源

    【讨论】:

      【解决方案3】:

      你得到NullPointerException,因为你的recyclerView.getLayoutManager().find...返回null和你的第二个问题,为什么你没有按位置查看,检查recyclerView.getLayoutManager().getChildCount()以验证你有没有该索引的孩子

      【讨论】:

        猜你喜欢
        • 2021-08-04
        • 1970-01-01
        • 2013-12-30
        • 1970-01-01
        • 1970-01-01
        • 2022-12-26
        • 1970-01-01
        • 2023-02-20
        • 1970-01-01
        相关资源
        最近更新 更多