Mam naprawdę ciężko próbować to rozgryźć. Otrzymuję NullPointerException
podczas przełączania między Fragments
a RecyclerView
, ale tylko w określonej kolejności. Kod i wyjątek znajduje się poniżej. Po pierwsze wyjaśnienie:Wyjątek NullPointerException podczas przełączania między fragmentami zawierającymi RecyclerView
Mam fragment z tego zakładkami układ jak widać tutaj:
3 z tych kart wykorzystywać ten sam fragment zawierający RecyclerView: Harmonogram, historia i Test. Każda z nich zadziała, jeśli najpierw je wybiorę. Problem polega na tym, że idę do jednej z pozostałych wyżej wymienionych zakładek po prawej stronie pierwszego wybranego! Jeśli jednak przejdę na lewą stronę pierwszego, który wybrałem, ładowanie będzie w porządku.
Jeśli wybiorę następnie test przejść do historii, a następnie zaplanować wszystko będzie działać dobrze
Jeśli wybiorę testowy następnie zaplanować te dwa będą działać, ale wtedy będzie Historii spowoduje wyjątek .
Jeśli wybiorę opcję Harmonogram, a następnie Historia, nastąpi wyjątek.
Jeśli wybiorę Historia następnie zaplanować te dwa będą działać, ale wtedy będzie testować wyjątek nastąpi
Jeśli wybiorę Historia następnie przetestować wyjątek nastąpi
I rozszerzył RecycleView i umieścić przerwę w onMeasure
, aby sprawdzić, czy mogę dowiedzieć się, co się dzieje i zauważyłem, że mAdapter
z RecyclerView
był null
. Sprawdziłem wewnątrz setAdapter()
z RecyclerView
i zawsze był przekazywany prawidłowy adapter. Wygląda na to, że w pewnym momencie mAdapter
jest czyszczone. Po prostu nie mogę zrozumieć, dlaczego tak się dzieje tylko wtedy, gdy otwieram zakładki od lewej do prawej, a nie od prawej do lewej ...
Każda pomoc będzie doceniona, gdy docieram do końca mojego rozumu!
Oto NullPointerException:
Link to Exception trace (było umieścić go tutaj, aby uniknąć limit znaków)
EDIT: Po łapania NullPointerException
IllegalStateException
wyskakuje też. Wygląda na to, że pochodzi z LayoutManager
. Here is a link to that output
Oto fragment widoku z zakładkami:
public class FKitViewer extends Fragment implements OnTabChangeListener {
public static final String TAB_INFO = "Info";
public static final String TAB_SCHEDULE = "Schedule";
public static final String TAB_HISTORY = "History";
public static final String TAB_TEST = "Test";
public static final String TAB_REQS = "Reqs";
private View mRoot;
private TabHost mTabHost;
private int mCurrentTab;
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
}
@Override
public View onCreateView(LayoutInflater li, ViewGroup container,
Bundle savedInstanceState){
mRoot = li.inflate(R.layout.kit_view, container);
mTabHost = (TabHost) mRoot.findViewById(android.R.id.tabhost);
setupTabs();
return mRoot;
}
@Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
mTabHost.setOnTabChangedListener(this);
mTabHost.setCurrentTab(mCurrentTab);
updateTab(TAB_INFO, R.id.tab1);
}
private void setupTabs(){
mTabHost.setup();
mTabHost.addTab(newTab(TAB_INFO, "Info", R.id.tab1));
mTabHost.addTab(newTab(TAB_SCHEDULE, "Schedule", R.id.tab2));
mTabHost.addTab(newTab(TAB_HISTORY, "History", R.id.tab3));
mTabHost.addTab(newTab(TAB_REQS, "Reqs", R.id.tab4));
mTabHost.addTab(newTab(TAB_TEST, "Test", R.id.tab5));
}
private TabSpec newTab(String tag, String label, int tabContentId){
TabSpec tabSpec = mTabHost.newTabSpec(tag);
tabSpec.setIndicator(label);
tabSpec.setContent(tabContentId);
return tabSpec;
}
private void updateTab(String tabId, int placeholder){
FragmentManager fm = getFragmentManager();
if(fm.findFragmentByTag(tabId) == null){
if(tabId.equals(TAB_INFO))
fm.beginTransaction()
.replace(placeholder, new FListiesView(), tabId)
.commit();
if(tabId.equals(TAB_SCHEDULE))
fm.beginTransaction()
.replace(placeholder, new FKitSchedule(false), tabId)
.commit();
if(tabId.equals(TAB_HISTORY))
fm.beginTransaction()
.replace(placeholder, new FKitSchedule(true), tabId)
.commit();
if(tabId.equals(TAB_REQS))
fm.beginTransaction()
.replace(placeholder, new KitRequirements(), tabId)
.commit();
if(tabId.equals(TAB_TEST))
fm.beginTransaction()
.replace(placeholder, new FKitSchedule(false), tabId)
.commit();
}
}
@Override
public void onTabChanged(String tabId){
Log.d("MNB", "Changing to tab: " + tabId);
if(TAB_INFO.equals(tabId)){
updateTab(tabId, R.id.tab1);
mCurrentTab = 0;
return;
}
if(TAB_SCHEDULE.equals(tabId)){
getActivity().getIntent().getExtras().putBoolean("com.crummy.history", false);
updateTab(tabId, R.id.tab2);
mCurrentTab = 1;
return;
}
if(TAB_HISTORY.equals(tabId)){
getActivity().getIntent().getExtras().putBoolean("com.crummy.history", true);
updateTab(tabId, R.id.tab3);
mCurrentTab = 2;
return;
}
if(TAB_REQS.equals(tabId)){
updateTab(tabId, R.id.tab4);
mCurrentTab = 3;
return;
}
if(TAB_TEST.equals(tabId)){
getActivity().getIntent().getExtras().putBoolean("com.crummy.history", true);
updateTab(tabId, R.id.tab5);
mCurrentTab = 4;
return;
}
}
}
Tutaj fragment:
public class RVFKitSchedule extends Fragment
realizuje LoaderManager.LoaderCallbacks {
private String mGetURL = "/index.php/droid/kitreport/";
private String mHistoryURL = "/index.php/droid/kithistory/";
private String mUpdateStatusURL = "/index.php/order_status/update/";
private Boolean mIsHistory = false;
private LinearLayout mPbl;
private int mDialogStatusLevel = 0;
private int mDialogLineId = -1;
private List<ScheduleRowModel> mItems = null;
private FKVRecyclerView mRecyclerView;
private KitScheduleRVAdapter mRVAdapter;
private int mItemCount;
private RecyclerView.LayoutManager mLayoutManager;
private FragmentActivity mParentActivity;
public RVFKitSchedule(){
}
public RVFKitSchedule(boolean isHistory){
mIsHistory = isHistory;
if(mIsHistory)
mGetURL = mHistoryURL;
}
@Override
public View onCreateView(LayoutInflater li, ViewGroup vg, Bundle b){
super.onCreateView(li, vg, b);
return li.inflate(R.layout.rv_main, vg, false);
}
@Override
public void onActivityCreated(Bundle icicle){
super.onActivityCreated(icicle);
final InputMethodManager imm = (InputMethodManager) mParentActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
}
@Override
public void onViewCreated(View view, Bundle icicle){
super.onViewCreated(view, icicle);
mParentActivity = getActivity();
mRecyclerView = (FKVRecyclerView)mParentActivity.findViewById(R.id.recyclerView);
mLayoutManager = new LinearLayoutManager(mParentActivity);
//mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//mLayoutManager.
mLayoutManager.scrollToPosition(0);
mRecyclerView.setLayoutManager(mLayoutManager);
RecyclerView.ItemDecoration itemDecoration =
new DividerItemDecoration(mParentActivity, DividerItemDecoration.VERTICAL_LIST);
mRecyclerView.addItemDecoration(itemDecoration);
mItems = new ArrayList<ScheduleRowModel>();
mRVAdapter = new KitScheduleRVAdapter(mItems, mIsHistory);
//mRecyclerView.setAdapter(null);
if(mRecyclerView.getAdapter() != null)
mRecyclerView.swapAdapter(mRVAdapter, true);
else
mRecyclerView.setAdapter(mRVAdapter);
mRecyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(mParentActivity, new RecyclerItemClickListener.OnItemClickListener(){
@Override
public void onItemClick(View v, int position){
String status = ((TextView)v.findViewById(R.id.sr_status)).getText().toString();
if(status.equals("Open"))
mDialogStatusLevel = 0;
else if(status.equals("In Production"))
mDialogStatusLevel = 1;
else if(status.equals("Waiting"))
mDialogStatusLevel = 2;
else if(status.equals("Ready"))
mDialogStatusLevel = 3;
else if(status.equals("Shipped"))
mDialogStatusLevel = 4;
int lineId = Integer.parseInt(((TextView)v.findViewById(R.id.sr_order_line_id)).getText().toString());
mDialogLineId = lineId;
OrderStatusDialog df = new OrderStatusDialog(mParentActivity, mDialogStatusLevel){
@Override
protected void onDialogClick(DialogInterface di, final int which){
Runnable update = new Runnable(){
@Override
public void run(){
updateStatus(mDialogLineId, which);
}
};
Thread t = new Thread(null, update, "MagentoBackground");
t.start();
try{
t.join();
}catch(InterruptedException e){
e.printStackTrace();
}
restartLoading();
dismiss();
}
};
df.show(getFragmentManager(), "dialog");
}
}){
@Override
public void onItemLongClick(View v, int pos){
String s = ((TextView)v.findViewById(R.id.sr_pn)).getText().toString();
String n = ((TextView)v.findViewById(R.id.sr_pn)).getText().toString();
CheckItemTypeTask task = new CheckItemTypeTask(s, null);
task.execute(mParentActivity);
int type = -1;
try{
type = task.get();
}catch(Exception e){
e.printStackTrace();
}
if(type == ItemType.PART){
openPartViewer(s);
}else if(type == ItemType.KIT){
openKitViewer(s,n);
}else if(type == ItemType.ERROR){
Toast.makeText(mParentActivity, "Error getting item type!", Toast.LENGTH_LONG);
}else{
Toast.makeText(mParentActivity, "Invalid item type!", Toast.LENGTH_LONG).show();
}
}
}
);
if(mParentActivity.getIntent().getExtras() != null){
Bundle b = mParentActivity.getIntent().getExtras();
if(!b.isEmpty()){
mGetURL += b.getString("com.crummy.kitNum");
}
}
mPbl = (LinearLayout)mParentActivity.findViewById(R.id.main_pbl);
mPbl.setVisibility(View.VISIBLE);
LoaderManager lm = getLoaderManager();
if(lm.getLoader(0) != null){
lm.initLoader(0, null, this);
}
startLoading();
}
protected void startLoading(){
getLoaderManager().initLoader(0, null, this);
}
protected void restartLoading(){
getLoaderManager().restartLoader(0, null, this);
}
@Override
public Loader<Void> onCreateLoader(int arg0, Bundle arg1){
Log.d("MNB", "FKitSchedule: onCreateLoader");
AsyncTaskLoader<Void> loader = new AsyncTaskLoader<Void>(mParentActivity){
@Override
public Void loadInBackground(){
try{
getLines();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
};
loader.forceLoad();
return loader;
}
@Override
public void onLoadFinished(Loader<Void> arg0, Void arg1){
Log.d("MNB", "FKitSchedule: onLoadFinished");
mPbl.setVisibility(View.GONE);
}
@Override
public void onLoaderReset(Loader<Void> arg0){
}
protected boolean openKitViewer(String kitNum, String kitName){
boolean result = false;
Intent i = new Intent(mParentActivity, GenFragmentActivity.class);
i.putExtra("com.crummy.frag_layout_id", R.layout.kit_view_frag);
i.putExtra("com.crummy.kitNum", kitNum);
i.putExtra("com.crummy.kitName", kitName);
startActivity(i);
return result;
}
protected boolean openPartViewer(String itemNum){
boolean result = false;
Intent i = new Intent(mParentActivity, PartInfoFragmentActivity.class);
i.putExtra("com.crummy.partnum", itemNum);
startActivity(i);
return result;
}
protected void getLines(){
Log.d("MNB", "FKitSchedule: getLines() ");
try{
HttpEntity response = HttpHelper.tryHttp(mParentActivity, mGetURL, null);
if(response == null)
return;
String res = EntityUtils.toString(response);
if(res.equals("[]")){
mParentActivity.runOnUiThread(noKitsError);
return;
}
JSONArray jsona = new JSONArray(res);
mItems = new ArrayList<ScheduleRowModel>();
Log.d("MNB", "jsona.length() = " + jsona.length());
for(int i=0; i < jsona.length(); i++){
Log.d("MNB", "Reading json line " + i);
JSONObject j = (JSONObject) jsona.get(i);
ScheduleRowModel srm = new ScheduleRowModel();
srm.custPo = j.getString("custPo");
srm.dueDate = j.getString("dueDate");
srm.partNum = j.getString("KitNumber");
srm.qty = j.getInt("quantity");
srm.status = j.getString("status");
srm.lineId = j.getInt("id");
srm.company = j.getString("name");
srm.rev = j.getString("rev");
if(!mIsHistory){
if(!j.getString("note").equals("null"))
srm.note = j.getString("note");
}
mItems.add(srm);
}
}catch(Exception e){
e.printStackTrace();
}
mParentActivity.runOnUiThread(returnRes);
}
private void addItemToList(ScheduleRowModel model){
mItemCount++;
mRVAdapter.addData(model);
}
private HttpEntity updateStatus(int lineId, int statusId){
HttpEntity resEntityPost = null;
try{
HttpClient client = new DefaultHttpClient();
String host = HttpHelper.getHost(mParentActivity);
HttpPost post = new HttpPost(host + mUpdateStatusURL);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("line_id", Integer.toString(lineId)));
nameValuePairs.add(new BasicNameValuePair("status", Integer.toString(statusId)));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse res = client.execute(post);
resEntityPost = res.getEntity();
}catch(Exception e){
e.printStackTrace();
}
return resEntityPost;
}
protected Runnable returnRes = new Runnable(){
@Override
public void run(){
Log.d("MNB", "FKitSchedule returnRes ");
mItemCount = 0;
mRVAdapter.clear();
if(mItems != null && mItems.size() > 0){
for(int i = 0; i < mItems.size(); i++){
addItemToList(mItems.get(i));
}
}
}
};
private Runnable noKitsError = new Runnable()
{
public void run(){
Toast t = Toast.makeText(mParentActivity, "No orders for this kit.", Toast.LENGTH_SHORT);
t.show();
}
};
}
Oto widok RecyclerView.Adapter:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class KitScheduleRVAdapter extends RecyclerView.Adapter<KitScheduleRVAdapter.ScheduleRowViewHolder>{
private List<ScheduleRowModel> items;
private boolean mIsHistory = false;
KitScheduleRVAdapter(List<ScheduleRowModel> modelData, boolean isHistory){
Log.d("MNB", "Constructing KitScheduleRVAdapter");
if(modelData == null){
throw new IllegalArgumentException(
"modelData must not be null");
}
this.items = modelData;
mIsHistory = isHistory;
}
@Override
public ScheduleRowViewHolder onCreateViewHolder(ViewGroup vg, int viewType){
Log.d("MNB", "KitScheduleRVAdapter.onCreateViewHolder()");
View itemView = LayoutInflater
.from(vg.getContext())
.inflate(R.layout.schedule_row, vg, false);
return new ScheduleRowViewHolder(itemView);
}
@Override
public void onBindViewHolder(ScheduleRowViewHolder vh, int pos){
Log.d("MNB", "Binding Viewholder at pos "+pos);
ScheduleRowModel model = items.get(pos);
vh.date.setText(model.dueDate);
vh.po.setText(model.custPo);
vh.partnum.setText(model.partNum);
vh.qty.setText(""+model.qty);
vh.status.setText(model.status);
vh.id.setText(""+model.lineId);
vh.company.setText(model.company);
vh.rev.setText(model.rev);
vh.note.setText(model.note);
Calendar cutoff = Calendar.getInstance();
cutoff.add(Calendar.DAY_OF_MONTH, 14);
Date co = cutoff.getTime();
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
Date d = new Date();
try {
d = s.parse(model.dueDate);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
View statusBar = vh.statusBar;
if(!mIsHistory){
if(model.status.equals("Ready")){
statusBar.setBackgroundResource(R.color.sh_ready);
}else if(model.status.equals("Waiting")){
statusBar.setBackgroundResource(R.color.sh_waiting);
}else if(model.status.equals("In Production")){
statusBar.setBackgroundResource(R.color.sh_inprod);
}
else if(d.before(co)){
statusBar.setBackgroundResource(R.color.sh_soon);
}else{
statusBar.setBackgroundResource(R.color.sh_open);
}
}
else
{
statusBar.setBackgroundResource(R.color.sh_ready);
}
}
@Override
public int getItemCount(){
return items.size();
}
public void addData(ScheduleRowModel data){
items.add(data);
this.notifyItemInserted(items.size() - 1);
}
public void clear(){
Log.d("MNB", "KitScheduleRVAdapter.clear()");
int itemsCleared = items.size();
items.clear();
notifyItemRangeRemoved(0, itemsCleared);
}
public final static class ScheduleRowViewHolder extends RecyclerView.ViewHolder{
TextView date;
TextView po;
TextView qty;
TextView partnum;
TextView status;
TextView id;
TextView company;
TextView rev;
TextView note;
View statusBar;
public ScheduleRowViewHolder(View itemView){
super(itemView);
date = (TextView) itemView.findViewById(R.id.sr_date);
po = (TextView) itemView.findViewById(R.id.sr_po);
qty = (TextView) itemView.findViewById(R.id.sr_qty);
partnum = (TextView) itemView.findViewById(R.id.sr_pn);
status = (TextView) itemView.findViewById(R.id.sr_status);
id = (TextView) itemView.findViewById(R.id.sr_order_line_id);
company = (TextView) itemView.findViewById(R.id.sr_company);
rev = (TextView) itemView.findViewById(R.id.sr_rev);
note = (TextView) itemView.findViewById(R.id.sr_note);
statusBar = itemView.findViewById(R.id.sr_status_bar);
}
}
}
Śledzenie stosu wygląda na obcięte (w środku "com.android.internal.policy.impl.PhoneWi") - czy masz sposób rejestrowania/uzyskiwania dostępu do pełnego śledzenia? –
Mam pełny ślad. Zaktualizowałem go linkiem do niego, ponieważ pełny ślad wprowadził mnie do limitu znaków –