Getting a null object exception with ViewBinding while everyhting works fine when using FindViewById - android-fragments

Within my fragment code, i was trying to attach on click listener to this button so i can use it to navigate through a navigation graph.
When using viewbinding the app crashes with a null object exception, using find view by id fixes the problem,
I wanna know what's wrong !
java.lang.NullPointerException: Attempt to read from field 'android.widget.TextView com.example.teleport.databinding.FragmentLoginBinding.registerLink' on a null object reference
that's the error i get and here's the fragment code
public class LoginFragment extends Fragment implements View.OnClickListener {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private FragmentLoginBinding binding;
private NavController navController;
private TextView registerLink;
public LoginFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment LoginFragment.
*/
// TODO: Rename and change types and number of parameters
public static LoginFragment newInstance(String param1, String param2) {
LoginFragment fragment = new LoginFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_login, container, false);
}
#Override
public void onViewCreated(#NonNull #NotNull View view, #Nullable #org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
navController = Navigation.findNavController(view);
//registerLink = (TextView) view.findViewById(R.id.register_link);
//registerLink.setOnClickListener(this);
registerLink = (TextView) binding.registerLink;
registerLink.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.register_link:
navController.navigate(R.id.nav_register);
break;
}
}
}

You need to create a binding instance in the onCreateView() method.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// create instance of binding here
binding = FragmentLoginBinding.inflate(inflater, container, false);
return binding.getRoot();
}
Also, explicitly you do not need to get the reference of the views, like
registerLink = (TextView) binding.registerLink;
registerLink.setOnClickListener(this);
You can just directly us the binding instance as
binding.registerLink.setOnClickListener(this);
For more details, check the documentation here.

Related

Xamarin android. The name 'assets' does not exist in the current context

In my app I am using a fragment and inside the fragment I am trying to use
view.FindViewById<TextView>(Resource.Id.tv1).Typeface = Typeface.CreateFromAsset(Assets, "fonts/Montserrat_Light.ttf");
to change the typeface of a textview. But I am getting an error that 'The name 'assets' does not exist in the current context'
This is the fragment code
public class xFragment : Fragment
{
const string ARG_PAGE = "ARG_PAGE";
private int mPage;
public static xFragment newInstance(int page)
{
var args = new Bundle();
args.PutInt(ARG_PAGE, page);
var fragment = new xFragment ();
fragment.Arguments = args;
return fragment;
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
mPage = Arguments.GetInt(ARG_PAGE);
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = inflater.Inflate(Resource.Layout.AgeLayout, container, false);
view.FindViewById<TextView>(Resource.Id.tv1).Typeface = Typeface.CreateFromAsset(Assets, "fonts/Montserrat_Light.ttf");
if (mPage == 2)
{
view = inflater.Inflate(Resource.Layout.AgeERLayout, container, false);
}
return view;
}
}
I found the solution and was so easy. I just had to use Activity.Assets

Xamarin Android Fragment show View before ViewModel is ready

I have a problem with await async method. I have a fragment (SalesFragment) which contains TabLayout with two fragments (FirstSalesFragment and SecondSalesFragment). When I showing SalesFragment and there is in TabLayout selected FirstSalesFragment I have there in ViewModel async method which call API and gives me some data. But problem is in FirstSalesFragment I have Microcharts layout and I want show there Chart, but main problem is my entries for chart are from async method from Api and OnCreateView method just doesnt wait for my async method in ViewModel.
My FirstSales view just show but chart is empty because OnCreateView doesnt wait for Entries... I tried OnActivityCreated or OnStart method but its same...
My SalesFragment
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
_view = base.OnCreateView(inflater, container, savedInstanceState);
var viewPager = _view.FindViewById<ViewPager>(Resource.Id.viewpager);
if (viewPager != null)
{
var fragments = new List<MvxViewPagerFragmentInfo>
{
new MvxViewPagerFragmentInfo(ViewModel.FirstSalesTab, typeof(FirstSalesFragment), typeof(FirstSalesViewModel)),
new MvxViewPagerFragmentInfo(ViewModel.SecondSalesTab, typeof(SecondSalesFragment), typeof(SecondSalesViewModel))
};
viewPager.Adapter = new MvxCachingFragmentStatePagerAdapter(Activity, ChildFragmentManager, fragments);
}
var tabLayout = _view.FindViewById<TabLayout>(Resource.Id.tabs);
tabLayout.SetupWithViewPager(viewPager);
return _view;
}
FirstSalesViewModel:
public class FirstSalesViewModel : BaseViewModel
{
private readonly ISessionInfo _session;
private readonly IInfoMessageReporter _infoMessageReporter;
public FirstSalesViewModel()
{
_session = Mvx.Resolve<ISessionInfo>();
_infoMessageReporter = Mvx.Resolve<IInfoMessageReporter>();
}
public async Task Initialize()
{
}
public void Init()
{
Task.Run(InitializeHourlySales);
}
private async Task InitializeHourlySales()
{
// Call API async service... initialize Entries here....
}
private List<Entry> _entries;
public List<Entry> Entries
{
get { return _entries; }
set
{
_entries = value;
RaisePropertyChanged(() => Entries);
}
}
}
}
FirstSalesFragment
public class FirstSalesFragment : BaseFragment<FirstSalesViewModel>
{
protected override int FragmentId => Resource.Layout.fragment_firstsales;
private View _view;
private ChartView _chartView;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
_view = base.OnCreateView(inflater, container, savedInstanceState);
_chartView = _view.FindViewById<ChartView>(Resource.Id.chartView);
if (_chartView != null)
{
InitializeChart();
}
return _view;
}
private void InitializeChart()
{
var tempEntries = ViewModel.Entries;
if (tempEntries == null || tempEntries.Count == 0)
{
_chartView.Chart = null;
return;
}
var tempChart = new LineChart
{
Entries = tempEntries,
LineMode = LineMode.Straight,
LineSize = 5,
LabelTextSize = 25,
AnimationDuration = new TimeSpan(0, 0, 5),
BackgroundColor = SKColor.Parse("#EEEEEE")
};
_chartView.Chart = tempChart;
}
}
Do your call to your async code in OnResume which supports using async.
I've modified your code sample a bit and made a call to your ViewModel.Init() in OnResume() for FirstSalesFragment.
FirstSalesViewModel
public class FirstSalesViewModel : BaseViewModel
{
...
public async Task Init()
{
await Task.Run(InitializeHourlySales);
}
private async Task InitializeHourlySales()
{
// Call API async service... initialize Entries here....
}
.....
FirstSalesFragment
...
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
_view = base.OnCreateView(inflater, container, savedInstanceState);
_chartView = _view.FindViewById<ChartView>(Resource.Id.chartView);
return _view;
}
public async override void OnResume()
{
base.OnResume();
await ViewModel.Init();
if (_chartView != null)
{
InitializeChart();
}
}
...

MvvmCross : Tab Implementation in Android

I am trying to implement tabs through MvvmCross in Xamarin. I came across MvxTabActivity in Android and MvxTabBarViewController in IOS. Both are working well. The problem is MvxTabActivity is obselete. Are there any alternatives for MvxTabActivity?
I found another way to implement this, which uses TabLayout and a ViewPager.
The solution asks to use fragments within a fragment. I have pasted the code for this approach. The problem here is on swiping the tabs, all the data in previous tabs is lost.
I tried using RetainInstance = true, that gave following exception : "Can't retain fragements that are nested in other fragments."
Product Detail Activity :
[Activity(Label = "ProductDetailView")]
public class ProductDetailView : MvxAppCompatActivity<ProductDetailViewModel>
{
private FrameLayout _mainFrame;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.product_detail_view);
if (FindViewById<FrameLayout>(Resource.Id.frame_Detail) != null)
{
var frag = new NutritionCategoryView();
frag.ViewModel = ViewModel.NutritionCategoryModel;
var trans = SupportFragmentManager.BeginTransaction();
trans.Replace(Resource.Id.frame_Detail, frag);
trans.AddToBackStack(null);
trans.Commit();
}
}
}
Nutrition Category View Fragment :
public class NutritionCategoryView : MvxFragment
{
public NutritionCategoryViewModel vm
{
get { return (NutritionCategoryViewModel) ViewModel; }
}
private TabLayout _tablayout;
private ViewPager _viewPager;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
this.EnsureBindingContextIsSet(inflater);
var view = this.BindingInflate(Resource.Layout.nutrition_category_view, container, false);
SetViewPager(view);
return view;
}
private void SetViewPager(View view)
{
_viewPager = view.FindViewById<Android.Support.V4.View.ViewPager>(Resource.Id.viewpager);
if (_viewPager != null)
{
var fragments = new List<CategoryTabsAdapter.FragmentInfo>
{
new CategoryTabsAdapter.FragmentInfo
{
FragmentType = typeof(CategoryView),
Title = "Proximates",
ViewModel = vm.Category1
},
new CategoryTabsAdapter.FragmentInfo
{
FragmentType = typeof(CategoryView),
Title = "Minerals",
ViewModel = vm.Category2
},
new CategoryTabsAdapter.FragmentInfo
{
FragmentType = typeof(CategoryView),
Title = "Fats",
ViewModel = vm.Category3
},
new CategoryTabsAdapter.FragmentInfo
{
FragmentType = typeof(CategoryView),
Title = "Vitamins",
ViewModel = vm.Category4
}
};
_viewPager.Adapter = new CategoryTabsAdapter(Activity, ChildFragmentManager, fragments);
}
_tablayout = view.FindViewById<TabLayout>(Resource.Id.sliding_tabs);
_tablayout.SetBackgroundColor(Android.Graphics.Color.Black);
_tablayout.SetupWithViewPager(_viewPager);
}
}
Category Tabs Adapter :
public class CategoryTabsAdapter : FragmentStatePagerAdapter
{
private readonly Context _context;
public IEnumerable<FragmentInfo> Fragments { get; private set; }
public CategoryTabsAdapter(Context context, FragmentManager fragmentManager, IEnumerable<FragmentInfo> fragments) : base(fragmentManager)
{
_context = context;
Fragments = fragments;
}
public override int Count
{
get { return Fragments.Count(); }
}
public override Fragment GetItem(int position)
{
var fragmentInfo = Fragments.ElementAt(position);
var fragment = Fragment.Instantiate(_context, Java.Lang.Class.FromType(fragmentInfo.FragmentType).Name);
((MvxFragment)fragment).ViewModel = fragmentInfo.ViewModel;
return fragment;
}
public override ICharSequence GetPageTitleFormatted(int position)
{
return new Java.Lang.String(Fragments.ElementAt(position).Title);
}
public class FragmentInfo
{
public string Title { get; set; }
public Type FragmentType { get; set; }
public IMvxViewModel ViewModel { get; set; }
}
}
Category View Fragment
public class CategoryView : MvxFragment<CategoryViewModel>
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
this.EnsureBindingContextIsSet(inflater);
var view = this.BindingInflate(Resource.Layout.category_view, container, false);
//Exception caused here :
//RetainInstance = true;
return view;
}
}
I am new to Xamarin and MvvmCross, so could come up with this much research only. Any solution for either approaches would be of great help.
P.S. This is my first question on Stackoverflow.
I think you need to use the MvxCachingFragmentStatePagerAdapter which is in the MvvmCross.Droid.Support.V4 Nuget package. Then hook it up to your TabLayout with SetupWithViewPager().
var viewPager = view.FindViewById<ViewPager>(Resource.Id.viewpager);
if (viewPager != null)
{
var fragments = new List<MvxCachingFragmentStatePagerAdapter.FragmentInfo>
{
new MvxCachingFragmentStatePagerAdapter.FragmentInfo(
"TitleA",
typeof (YourFragmentA),
typeof (YourViewModelA)),
new MvxCachingFragmentStatePagerAdapter.FragmentInfo(
"TitleB",
typeof (YourFragmentB),
typeof (YourViewModelB)),
new MvxCachingFragmentStatePagerAdapter.FragmentInfo(
"TitleC",
typeof (YourFragmentC),
typeof (YourViewModelC))
};
viewPager.Adapter = new MvxCachingFragmentStatePagerAdapter(Activity, ChildFragmentManager, fragments);
viewPager.OffscreenPageLimit = fragments.Count;
var tabLayout = view.FindViewById<TabLayout>(Resource.Id.tabs);
tabLayout.SetupWithViewPager(viewPager);
}
Your tabs are being recreated each time because you are using FragmentStatePagerAdapter instead of FragmentPagerAdapter. From the docs, FragmentPagerAdapter:
This version of the pager is best for use when there are a handful of
typically more static fragments to be paged through, such as a set of
tabs. The fragment of each page the user visits will be kept in
memory, though its view hierarchy may be destroyed when not visible.
This can result in using a significant amount of memory since fragment
instances can hold on to an arbitrary amount of state. For larger sets
of pages, consider FragmentStatePagerAdapter.
FragmentStatePagerAdapter:
This version of the pager is more useful when there are a large number
of pages, working more like a list view. When pages are not visible to
the user, their entire fragment may be destroyed, only keeping the
saved state of that fragment. This allows the pager to hold on to much
less memory associated with each visited page as compared to
FragmentPagerAdapter at the cost of potentially more overhead when
switching between pages.
So use FragmentPagerAdapter, but I think it will have to be at the Activity level, and not a fragment within a fragment.

android fragment reloading (onCreate) each time when back Button pressed

I am new in android using fragments in my Project. first time my fragment is creating then api called and get data load in fragment. here when i clicked at any item i replaced fragment by another fragment there also another api called and load data to fragment.
now here problem situation generated for me.
from here i back Button pressed.
fragment reloading same as first time creating but it should be show data as i left before going to next fragment.
so please provide me solution how i can get same data as i left means savedInstanceState data.
im my first fragment getCategory method call Api and get Data first time when i choose any category i replace fragment with another fragment but when i m returning same getCategory method recall perform same process as it first time.
fragment should not call api method again on backpressed it should show same category on this i clicked before.
my first fragment where calling api......
public class LandingFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private GridLayoutManager gridLayoutManager;
private static RecyclerView category_Grid;
private Fragment myFragment = null;
ProgressBar mProgressView;
View mLoginFormView;
private Category category;
private CategoryAdapter categoryAdapter;
private List<CategoryObject> rowListItem;
private String productId;
private OnFragmentInteractionListener mListener;
public LandingFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment LandingFragment.
*/
// TODO: Rename and change types and number of parameters
public static LandingFragment newInstance(String param1, String param2) {
LandingFragment fragment = new LandingFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v= inflater.inflate(R.layout.fragment_landing, container, false);
return v;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initViews(view);
RecyclerViewListeners();
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Activity context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
private void initViews(final View v) {
mLoginFormView = (View)v.findViewById(R.id.mainView);
mProgressView = (ProgressBar)v.findViewById(R.id.login_progress);
category_Grid = (RecyclerView)v.findViewById(R.id.cat_grid);
category_Grid.setHasFixedSize(true);
gridLayoutManager = new GridLayoutManager(getActivity(), 3);
category_Grid.setLayoutManager(gridLayoutManager);
}
private void RecyclerViewListeners(){
category_Grid.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), category_Grid, new ItemClickListener(){
#Override
public void onClick(View view, int position) {
String entityId = rowListItem.get(position).getCategoryId();
String catName = rowListItem.get(position).getName();
Integer ishave = rowListItem.get(position).getIshaveSubcategories();
if(ishave==1) {
myFragment = SubcategoryFragment.newInstance(""+catName, "" + entityId);
ActivityUtils.launchFragementWithAnimation(myFragment, getActivity());
}else{
myFragment = ProductListFragment.newInstance("", "" + entityId);
ActivityUtils.launchFragementWithAnimation(myFragment, getActivity());
}
}
#Override
public void onLongClick(View view, int position) {
}
}));
}
public void getCategory() {
showProgress(true);
String URL = getResources().getString(R.string.category_api);
StringRequest req = new StringRequest(Request.Method.POST,URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
VolleyLog.v("Response:%n %s", response);
Gson gson = new GsonBuilder().serializeNulls().create();
try {
JSONObject jsonObject = new JSONObject(response);
if (jsonObject.getString("status").equals(getResources().getString(R.string.response_success))){
category = gson.fromJson(response, Category.class);
rowListItem = category.getCategory();
if(navigationUpdated){
someEventListener.someEvent(rowListItem);
navigationUpdated = false;
}
Log.d("CATEGORYID::::::::",""+rowListItem.get(1).getCategoryId());
categoryAdapter = new CategoryAdapter(getActivity(),rowListItem);
category_Grid.setAdapter(categoryAdapter);
categoryAdapter.notifyDataSetChanged();
return;
}
else if (jsonObject.getString("status").equals(getResources().getString(R.string.login_Er_respose))){
Log.e("","ERRORRRRRR");
return;
}
} catch (JSONException e) {
showProgress(false);
Log.e("My App", "Could not parse malformed JSON: \"" + response + "\"");
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
showProgress(false);
VolleyLog.e("Error: ", error.getMessage());
}
}){
#Override
protected Map<String,String> getParams(){
Map<String,String> params = new HashMap<String, String>();
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String,String> params = new HashMap<String, String>();
params.put("Content-Type","application/x-www-form-urlencoded");
return params;
}
};
AppController.getInstance().addToRequestQueue(req);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
private void showProgress(final boolean show) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mProgressView.animate().setDuration(shortAnimTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
} else {
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
}
You can check your rowListItem.size(), if it's size is 0 then call getCategory() service, otherwise load your data from your rowListItem. Here is sample code which I am using to load data from arraylist if it is not empty:
if (mArrayArticle.size() == 0) {
isDataLoading = true;
mRecyclerList.setVisibility(View.INVISIBLE);
getCategory();
} else {
mHomeItemAdapter = new HomeItemAdapter(getActivity(), mArrayArticle, this);
mRecyclerList.setAdapter(mHomeItemAdapter);
}
Here mArrayArticle is my ArrayList, Hope it will help you.
for more clarification i want to tell..
how i implement the #Bhvk_AndroidBee solution
fragment backpressed call onActivityCreated Method so first overridethis method in fragment
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//here you can check null condition for rowListItem
}
}
inside onActivityCreated method I checked the condition like that
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(rowListItem!=null){
categoryAdapter = new CategoryAdapter(getActivity(),rowListItem);
category_Grid.setAdapter(categoryAdapter);
categoryAdapter.notifyDataSetChanged();
}else {
//call the method for first time creating your view
getCategory();
}
}
hope this would be helpfull for more strugglers like me...

Android bundle is null after replacing fragment

I have two fragments which are VolleyFragment and AnotherFragment, setting VolleyFragment as the initial fragment. In this fragment, the bundle data is displaying ok. However, when I go to AnotherFragment, the app crashes. It says this error:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String[] android.os.Bundle.getStringArray(java.lang.String)' on a null object reference
at com.example.rendell.volleyfragment.AnotherFragment.onCreateView(AnotherFragment.java:28)
MainActivity
public class MainActivity extends AppCompatActivity {
public static final String JSON_URL = "http://192.168.0.102/musicmania/music/getMF";
TextView id,name,email;
String[] ids, names, emails;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
id = (TextView) findViewById(R.id.id);
name = (TextView) findViewById(R.id.name);
email = (TextView) findViewById(R.id.email);
sendRequest();
}
private void sendRequest(){
StringRequest stringRequest = new StringRequest(JSON_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
showJSON(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_LONG).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
}
private void showJSON(String json){
ParseJSON pj = new ParseJSON(json);
pj.parseJSON();
id.setText(ParseJSON.ids[0]);
name.setText(ParseJSON.titles[0]);
email.setText(ParseJSON.artists[0]);
FragmentManager fragmentTransaction = getFragmentManager();
android.app.FragmentTransaction transaction = fragmentTransaction.beginTransaction();
VolleyFragment squadFragment = new VolleyFragment();
AnotherFragment anotherFragment = new AnotherFragment();
Bundle bundle = new Bundle();
bundle.putStringArray("id", ParseJSON.ids);
bundle.putStringArray("name", ParseJSON.titles);
bundle.putStringArray("email", ParseJSON.artists);
squadFragment.setArguments(bundle);
anotherFragment.setArguments(bundle);
transaction.replace(R.id.containerView, squadFragment);
transaction.commit();
}
public void changeFragment(View view) {
FragmentManager fragmentTransaction = getFragmentManager();
android.app.FragmentTransaction transaction = fragmentTransaction.beginTransaction();
AnotherFragment anotherFragment = new AnotherFragment();
transaction.replace(R.id.containerView, anotherFragment);
transaction.commit();
}
}
VolleyFragment
public class VolleyFragment extends Fragment {
TextView id,name,email;
String[] ids,names,emails;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.volley_fragment, container, false);
id = (TextView) view.findViewById(R.id.id);
name = (TextView) view.findViewById(R.id.name);
email = (TextView) view.findViewById(R.id.email);
ids = getArguments().getStringArray("id");
names = getArguments().getStringArray("name");
emails = getArguments().getStringArray("email");
//jsonArray.setIds(id);
id.setText(/*jsonArray.getIds()*/ids[0]);
name.setText(names[0]);
email.setText(emails[0]);
return view;
}
}
AnotherFragment
public class AnotherFragment extends Fragment {
TextView id,name,email;
String[] ids,names,emails;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.another_fragment, container, false);
id = (TextView) view.findViewById(R.id.id);
name = (TextView) view.findViewById(R.id.name);
email = (TextView) view.findViewById(R.id.email);
ids = getArguments().getStringArray("id");
names = getArguments().getStringArray("name");
emails = getArguments().getStringArray("email");
//jsonArray.setIds(id);
id.setText(/*jsonArray.getIds()*/ids[0]);
name.setText(names[0]);
email.setText(emails[0]);
return view;
}
}
I'm having trouble following exactly what you're doing here, but I see a number of problems:
In showJSON, you new up a ParseJSON object and assign it to pj, but never make use of pj. Instead you reach statically into ParseJSON for the values to populate a Bundle. That seems really odd. I'd expect the pj instance to contain the data.
Typically one does not "new" up a fragment. The usual pattern is to use a static builder in the class of the fragment itself.
You're passing the same Bundle to two different fragments. Unless you know for a fact that's OK, try instead using a different Bundle for each one.
in showJSON, your AnotherFragment instance doesn't seem to be used at all
I don't see any place where changeFragment is called
You're passing string arrays in the Bundle, but you only ever use the first element in the array in the fragment. Consider just passing a single string instead?

Resources