我真的很难弄清楚这个问题。当在 Fragments 与 RecyclerView 之间切换时,我得到了一个 NullPointerException 但只是以特定的顺序。代码和异常如下。先解释一下:
我有一个带有此选项卡式布局的 fragment ,如下所示:
这些选项卡中的 3 个使用包含 RecyclerView 的相同 fragment :Schedule、History 和 Test。如果我先选择它们,它们中的任何一个都可以工作。现在的问题是,当我转到我选择的第一个选项卡右侧的其他选项卡之一时!但是,如果我转到我选择的第一个的左侧,那将加载得很好。
如果我选择“测试”,然后转到“历史记录”,然后选择“安排”,一切都会正常进行
如果我选择 Test 然后 Schedule 这两个将起作用,但是然后转到 History 将导致 异常。
如果我选择 Schedule then History,则会发生异常。
如果我选择 History 然后 Schedule 这两个会起作用,但是然后去 Test 会发生异常
如果我选择 History then Test 异常将会发生
我扩展了 RecycleView 并中断了 onMeasure 以查看是否可以弄清楚发生了什么,我注意到 的 为 mAdapter RecyclerViewnull。我在 RecyclerView 的 setAdapter() 内部进行了检查,它始终传递了一个有效的适配器。所以看起来 mAdapter 在某个时候被清除了。我只是不明白为什么它只会在我打开从左到右而不是从右到左的选项卡时发生...
任何帮助都将不胜感激,因为我对这个已经无能为力了!
这是 NullPointerException:
Link to Exception trace (不得不把它放在这里以避免字符限制)
编辑: 在捕捉到 NullPointerException 之后,也会弹出一个 IllegalStateException。看起来来自 LayoutManager。 Here is a link to that output
这是标签 View 的 fragment :
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;
}
}
}
这是 fragment :
public class RVFKitSchedule extends Fragment
实现 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();
}
};
这是 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);
}
}
}
最佳答案
您应该在 onViewCreated() 而不是 onActivityCreated() 中执行 View 分配(和 LayoutManager 分配)——onActivityCreated() 不是当您的 Fragment 通过 ViewPager 分离并重新附加时,不会再次发生。 View 在消失和返回时将被销毁 (onDestroyView()) 并重新创建 (onCreateView()),但 RecyclerView 永远不会在这种情况下获取它的 LayoutManager。
编辑:从评论中提取,另一个问题是使用父 Activity 来解析 RecyclerView 而不是使用 Fragment 的 查看。由于 findViewById() 执行深度优先搜索,如果您附加了多个包含具有相同 ID 的 View 的 Fragments,您最终可能会得到错误的 View ,但一切仍然会编译和运行,只是会产生意想不到的结果。使用在 onViewCreated() 中返回的 view 将您的 View 搜索限制为只是您在 onCreateView() 中膨胀的布局>.
关于java - 在包含 RecyclerView 的 fragment 之间切换时出现 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26790102/
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我正在从erb文件切换到HAML。我将hamlgem添加到我的系统中。我创建了app/views/layouts/application.html.haml文件。我应该只删除application.html.erb文件吗?此外,仍然有/public/index.html文件被呈现为默认页面。我想创建自己的默认index.html.haml页面。我应该把它放在哪里以及如何使系统呈现该文件而不是默认索引文件?谢谢! 最佳答案 是的,您可以删除任何已转换为HAML的View的ERB版本。至于你的另一个问题,删除public/index/h
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行