I am getting errors on few devices where I am trying to display a toast inside fragments. this toast is usually on retrofit response failure. toast code is simple. Please suggest, could not find any reason searching here and there.
Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();
and my ST logs are below.
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.widget.Toast.(Toast.java:103)
at android.widget.Toast.makeText(Toast.java:256)
According to the code & javadoc for Fragment.getActivity() you can get null returned:
/**
* Return the {#link FragmentActivity} this fragment is currently associated with.
* May return {#code null} if the fragment is associated with a {#link Context}
* instead.
*
* #see #requireActivity()
*/
#Nullable
final public FragmentActivity getActivity() {
return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
Particularly this could happen when your Fragment is not attached to an activity (as pointed out here and here).
Similarly, getContext() can also return null.
There's a good discussion on when these can be null on this possibly related post:
Why getContext() in fragment sometimes returns null?
The simple solution has been provided already - put in a null check before displaying the Toast.
But the underlying problem is one of architecture - your code is coupling API activity to your UI, and assuming certain things about your UI state i.e. you are assuming that when the API call returns, your screen is still visible to the user.
A better solution would be to decouple the Retrofit call from the UI - put the API calls in a separate class that does not depend on the UI state.
Use an event or pub-sub framework to communicate from this API wrapper class back to any UI components that need to know when an API call returns.
EventBus or RxJava would be 2 common solutions for this (LocalBroadcastManager would be a less common approach).
This will allow any code to call into your API, and to subscribe to be notified when the API returns.
It also allows you to save your API responses in (for example) a local database, in which case you could just rely on the LiveData pattern to update any UI that needs to be.
Here's a Medium article giving a brief description of how to use the Android Architecture Components in this manner using the Repository pattern.
Given that some projects cannot be redesigned immediately, there may be need for workarounds.
The above mentioned null check workaround is useful in that the app will no longer crash. Unfortunately it does mean that the user will not be alerted to the failed API call.
One alternative is to create your own Application subclass (many projects will already have done this in order to initialise common libraries) and provide a method for static access to this application Context. (A similar suggestion has subsequently been made by Kushal.)
You could then choose to display the Toast using the application Context instead of the one from the fragment. You may lose any specific styling that would have been gained from the more specific context, but the advantage would be that your user still gets to see the Toast message.
Exposing your Application as a singleton has been described very nicely on this post:
Application singleton use in Android
Sometimes getActivity() or getContext() may produce a null pointer exception when the fragment is not associated with an Activity. So use the onAttach method
public class yourFragment extends Fragment {
Context context
#Override
public void onAttach(Context context) {
this.context = context;
super.onAttach(context);
}
}
Maybe getActivity() called when fragment detached. Try it.
if (isAdded()) {
Toast.makeText(getActivity(), "something", Toast.LENGTH_SHORT).show();
}
Your activity context is null in this line :
Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();// getActivity() is null
To avoid crash use this :
if(getActivity() != null)
Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();
Change your getActivity() to getContext(). try the given code below:
Toast.makeText(getContext(), "Connection Failure", Toast.LENGTH_LONG).show();
if (isAdded()) {
Toast.makeText(getActivity(), "something", Toast.LENGTH_SHORT).show();
}
or try this
if(getActivity() != null)
Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();
Both will work fine in my case because in some case getActivity() called when fragment detached.
So we have to take care of that as well.
Related
In the Android docs i found this article about conditional navigation where a login function returns LiveData to propagate the signIn result back from the viewmodel to the fragment. I assume the viewModel uses LiveDataBuilder to create the LiveData
//Fragment
fun login(username: String, password: String) {
userViewModel.login(username, password).observe(viewLifecycleOwner, Observer { result ->
if (result.success) {
savedStateHandle.set(LOGIN_SUCCESSFUL, true)
findNavController().popBackStack()
} else {
showErrorMessage()
}
})
}
I assume viewmodel does something like this.
fun login(username: String, password: String) = liveData {
//perform login
}
I always thought this is bad practice since it creates a Livedata object on every login attempt. In this case i mostly use another SingleLiveData object to post the login result to. I also used callbacks quite often. Something like this:
fun login(username: String, password: String) {
userViewModel.login(username, password,
onSuccess = {
//DO SOMETHING
}, onError = {
//DO SOMETHING
})
}
Can someone explain which is now the best approach and what is the reason the other appraoches should not be used?
You must not use callbacks in that way. You are leaking the views to the ViewModel.
LiveData used in this way is basically a glorified callback that will automatically be cancelled when the Fragment's view goes out of scope, so it's easier to use safely on the Fragment, and it avoids leaking the Fragment to the ViewModel. It saves you a lot of boilerplate that would be required to do it safely and without leaking the Fragmet.
I always thought this is bad practice since it creates a Livedata object on every login attempt.
I don't see what's bad about that. It's a lightweight object. Probably lighter weight than most of the Strings you work with in an app.
I'm creating an android application that contains one main activity and three fragments. There is a side navigation bar and depend on the selected menu item, it will replace the fragment loaded into the main screen.
In one of those fragments, I'm loading data from a REST API and once the data received, it will update the fragment UI. I'm using ok-http to send REST API calls. So in the onResponse() method, I have to call getActivity().runOnUiThread() to update the UI elements with received data and show Toast notifications for errors.
I already read that there is a chance to return null while calling getActivity() method within a fragment due to detach the fragment from the activity. I'm also aware that it's not a good idea to create a reference to the activity in onAttach() method and use it later like below, since it will prevent GC to clean that activity object after detaching from the fragment.
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
mActivity = (Activity)context;
}
Therefore I'm currently doing null check before calling getActivity() method as shown below which is recommended in most of the SO answers.
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
//Update UI
}
);
}
But according to the above code block, It's obvious that if there is no activity attached to the fragment (when getActivity() returns null), the UI will not be updated.
It's okay to not executing the UI updates if the fragment is not on the screen anymore. So my question is, is there any possibility of showing the fragment UI to the user while getActivity() returning null?
This question is mostly to solicit opinions on the best way to handle my app. I have three fragments being handled by one activity. Fragment A has one clickable element the photo and Fragment B has 4 clickable elements the buttons. The other fragment just displays details when the photo is clicked. I am using ActionBarSherlock.
The forward and back buttons need to change the photo to the next or previous poses, respectively. I could keep the photo and the buttons in the same fragment, but wanted to keep them separate in case I wanted to rearrange them in a tablet.
I need some advice - should I combine Fragments A and B? If not, I will need to figure out how to implement an interface for 3 clickable items.
I considered using Roboguice, but I am already extending using SherlockFragmentActivity so that's a no go. I saw mention of Otto, but I didn't see good tutorials on how to include in a project. What do you think best design practice should be?
I also need help figuring out how to communicate between a fragment and an activity. I'd like to keep some data "global" in the application, like the pose id. Is there some example code I can see besides the stock android developer's information? That is not all that helpful.
BTW, I'm already storing all the information about each pose in a SQLite database. That's the easy part.
The easiest way to communicate between your activity and fragments is using interfaces. The idea is basically to define an interface inside a given fragment A and let the activity implement that interface.
Once it has implemented that interface, you could do anything you want in the method it overrides.
The other important part of the interface is that you have to call the abstract method from your fragment and remember to cast it to your activity. It should catch a ClassCastException if not done correctly.
There is a good tutorial on Simple Developer Blog on how to do exactly this kind of thing.
I hope this was helpful to you!
The suggested method for communicating between fragments is to use callbacks\listeners that are managed by your main Activity.
I think the code on this page is pretty clear:
http://developer.android.com/training/basics/fragments/communicating.html
You can also reference the IO 2012 Schedule app, which is designed to be a de-facto reference app. It can be found here:
http://code.google.com/p/iosched/
Also, here is a SO question with good info:
How to pass data between fragments
It is implemented by a Callback interface:
First of all, we have to make an interface:
public interface UpdateFrag {
void updatefrag();
}
In the Activity do the following code:
UpdateFrag updatfrag ;
public void updateApi(UpdateFrag listener) {
updatfrag = listener;
}
from the event from where the callback has to fire in the Activity:
updatfrag.updatefrag();
In the Fragment implement the interface in CreateView do the
following code:
((Home)getActivity()).updateApi(new UpdateFrag() {
#Override
public void updatefrag() {
.....your stuff......
}
});
To communicate between an Activity and Fragments, there are several options, but after lots of reading and many experiences, I found out that it could be resumed this way:
Activity wants to communicate with child Fragment => Simply write public methods in your Fragment class, and let the Activity call them
Fragment wants to communicate with the parent Activity => This requires a bit more of work, as the official Android link https://developer.android.com/training/basics/fragments/communicating suggests, it would be a great idea to define an interface that will be implemented by the Activity, and which will establish a contract for any Activity that wants to communicate with that Fragment. For example, if you have FragmentA, which wants to communicate with any activity that includes it, then define the FragmentAInterface which will define what method can the FragmentA call for the activities that decide to use it.
A Fragment wants to communicate with other Fragment => This is the case where you get the most 'complicated' situation. Since you could potentially need to pass data from FragmentA to FragmentB and viceversa, that could lead us to defining 2 interfaces, FragmentAInterface which will be implemented by FragmentB and FragmentAInterface which will be implemented by FragmentA. That will start making things messy. And imagine if you have a few more Fragments on place, and even the parent activity wants to communicate with them. Well, this case is a perfect moment to establish a shared ViewModel for the activity and it's fragments. More info here https://developer.android.com/topic/libraries/architecture/viewmodel . Basically, you need to define a SharedViewModel class, that has all the data you want to share between the activity and the fragments that will be in need of communicating data among them.
The ViewModel case, makes things pretty simpler at the end, since you don't have to add extra logic that makes things dirty in the code and messy. Plus it will allow you to separate the gathering (through calls to an SQLite Database or an API) of data from the Controller (activities and fragments).
I made a annotation library that can do the cast for you. check this out.
https://github.com/zeroarst/callbackfragment/
#CallbackFragment
public class MyFragment extends Fragment {
#Callback
interface FragmentCallback {
void onClickButton(MyFragment fragment);
}
private FragmentCallback mCallback;
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1
mCallback.onClickButton(this);
break;
case R.id.bt2
// Because we give mandatory = false so this might be null if not implemented by the host.
if (mCallbackNotForce != null)
mCallbackNotForce.onClickButton(this);
break;
}
}
}
It then generates a subclass of your fragment. And just add it to FragmentManager.
public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager().beginTransaction()
.add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), "MY_FRAGM")
.commit();
}
Toast mToast;
#Override
public void onClickButton(MyFragment fragment) {
if (mToast != null)
mToast.cancel();
mToast = Toast.makeText(this, "Callback from " + fragment.getTag(), Toast.LENGTH_SHORT);
mToast.show();
}
}
Google Recommended Method
If you take a look at this page you can see that Google suggests you use the ViewModel to share data between Fragment and Activity.
Add this dependency:
implementation "androidx.activity:activity-ktx:$activity_version"
First, define the ViewModel you are going to use to pass data.
class ItemViewModel : ViewModel() {
private val mutableSelectedItem = MutableLiveData<Item>()
val selectedItem: LiveData<Item> get() = mutableSelectedItem
fun selectItem(item: Item) {
mutableSelectedItem.value = item
}
}
Second, instantiate the ViewModel inside the Activity.
class MainActivity : AppCompatActivity() {
// Using the viewModels() Kotlin property delegate from the activity-ktx
// artifact to retrieve the ViewModel in the activity scope
private val viewModel: ItemViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.selectedItem.observe(this, Observer { item ->
// Perform an action with the latest item data
})
}
}
Third, instantiate the ViewModel inside the Fragment.
class ListFragment : Fragment() {
// Using the activityViewModels() Kotlin property delegate from the
// fragment-ktx artifact to retrieve the ViewModel in the activity scope
private val viewModel: ItemViewModel by activityViewModels()
// Called when the item is clicked
fun onItemClicked(item: Item) {
// Set a new item
viewModel.selectItem(item)
}
}
You can now edit this code creating new observers or settings methods.
There are severals ways to communicate between activities, fragments, services etc. The obvious one is to communicate using interfaces. However, it is not a productive way to communicate. You have to implement the listeners etc.
My suggestion is to use an event bus. Event bus is a publish/subscribe pattern implementation.
You can subscribe to events in your activity and then you can post that events in your fragments etc.
Here on my blog post you can find more detail about this pattern and also an example project to show the usage.
I'm not sure I really understood what you want to do, but the suggested way to communicate between fragments is to use callbacks with the Activity, never directly between fragments. See here http://developer.android.com/training/basics/fragments/communicating.html
You can create declare a public interface with a function declaration in the fragment and implement the interface in the activity. Then you can call the function from the fragment.
I am using Intents to communicate actions back to the main activity. The main activity is listening to these by overriding onNewIntent(Intent intent). The main activity translates these actions to the corresponding fragments for example.
So you can do something like this:
public class MainActivity extends Activity {
public static final String INTENT_ACTION_SHOW_FOO = "show_foo";
public static final String INTENT_ACTION_SHOW_BAR = "show_bar";
#Override
protected void onNewIntent(Intent intent) {
routeIntent(intent);
}
private void routeIntent(Intent intent) {
String action = intent.getAction();
if (action != null) {
switch (action) {
case INTENT_ACTION_SHOW_FOO:
// for example show the corresponding fragment
loadFragment(FooFragment);
break;
case INTENT_ACTION_SHOW_BAR:
loadFragment(BarFragment);
break;
}
}
}
Then inside any fragment to show the foo fragment:
Intent intent = new Intent(context, MainActivity.class);
intent.setAction(INTENT_ACTION_SHOW_FOO);
// Prevent activity to be re-instantiated if it is already running.
// Instead, the onNewEvent() is triggered
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
getContext().startActivity(intent);
There is the latest techniques to communicate fragment to activity without any interface follow the steps
Step 1- Add the dependency in gradle
implementation 'androidx.fragment:fragment:1.3.0-rc01'
I am having trouble with volley (again). I want to run a volley request in a class, so more than one activity can feed off its results and update their UI's accordingly. I have got it return data and call the request from the UI but now im struggling to update the UI with the new data. I have looked at answers but I'm trying to understand the structure and I am at a loss, can some please advise/ talk me through it
assuming I understand what you mean as being:
A Volley request returns, updates some data set through some activity
In this case, assuming the calling activity contains everything, and reminding that this is a very general example, what you should usually do (usually, since there are exceptions to the case), is just insert the data into the data set contained in your UI holder (e.g. your recycler adapter) and update it, an example would be your adapter holding a method similar to this:
public void updateDataSet(List<Item> items)
{
//mItemList is the adapters member list
if (null != mItemList)
{
mItemList.clear();
mItemList.addAll(items);
}
else
mItemList = items;
notifyDataSetChanged();
}
you call this inside the request callback you fired earlier, just make sure to initialize everything BEFORE you fire the request, e.g.
#Override
public void onResponse(JSONObject response)
{
Log.d(TAG + ": ", "somePostRequest Response : " + response.toString());
// here you need to parse to JSON to a list and then call...
List<Item> items = parseResponse(response);
myAdapter.updateDataSet(items);
}
Now, if what you meant was
A Volley request returns in some Activity, I want it to update stuff in another place
there are a couple of options:
As someone said in the comments - you could go for EventBus.
You could hold a DataManager class, which would be a global singleton, in which case you can either hold the data and update it there, and then every activity (in it's onResume or other relevant lifecycle method) knows to pull that data.
You could do the same as option 2, with the exception of that DataManager holding a reference to other UI parts (e.g. Fragments), and triggering member methods in them that pass the data and trigger the updates.
Personally I find option 3 cumbersome and somewhat bad practice, but if all else fails, (and it shouldn't, but if it does) then you can try.
There are more options out there, it depends and varies according to the data, your app architecture, coding style and other stuff you apply.
Hope this helps!
You can use EventBus. To use EventBus you need to register class where you will receive update and when you publish event for those event all classes will receive it.
Here is an example using greenrobot's EventBus :
Event Model :
public class MessageEvent {
/* Additional fields if needed */
}
Subscribe :
EventBus.getDefault().register(this); // In Activity onCreate method
#subscribe
public void onMessageEvent(MessageEvent event){
// this is the method to receive event
}
Publish event :
EventBus.getDefault().post(new MessageEvent());
Now every class subscribed for this event model will be updated.
Note : subscribed classes have to alive, If anyone destroyed they won't receive update.
I want to ask why we get this annotation:
Method invocation getContext.getContentResolver() may produce
NullPointerException
Why is it there and not in other parts of program Fragment/Activity? That approach has been used in tutorial made by Google - here is link for ContentProvider code https://github.com/udacity/Sunshine-Version-2/blob/sunshine_master/app/src/main/java/com/example/android/sunshine/app/data/WeatherProvider.java even if you create an aplication with just a blank activity and put that method in a newly created ContentProvider it is there.
Should we use getContext().getContentResolver().notifyChange(uri, null);outside ContentProvider getting the uri passed and then after the update/insert/delete is finished notifyChange? or maybe we can fix it somehow?
If you look in the source of ContentProvider (just hold SHIFT and click on the classname in Android Studio) then you will find that the implementation is holding an object of type Context as mContext.
Your solution is just the same, which means if mContext of ContentProvider is null, your reference will also be null. So there is no need for this.
To help you out, this is just a warning of your IDE if make such a construct yourself. But in this case there will always be context, because the ContentProvider is generated by your system. To avoid the error in your IDE just write #SuppressWarnings("ConstantConditions") above your class definition like:
...
#SuppressWarnings("ConstantConditions")
public class NoteProvider extends ContentProvider {
...
If you can make sure that getContext() can never be null then you can simply ignore this warning. I think the warning even disappears of you just check for null:
if (getContext() != null) {
getContext().getContentResolver();
}
You just have to keep in mind the code won't be executed if getContext() is null.
Cheers
edit:
Be careful with the answer #Shivani Gupta gave you, because you could get different contexts. See: Difference between getContext() , getApplicationContext() , getBaseContext() and "this"
Write getApplicationContext().getContentResolver()
Hope this will work.
Ok it seems I fixed it myself by declaring Context on the beggining of the class.
public class NoteProvider extends ContentProvider {
Context context;
then initializing it in onCreate()
#Override
public boolean onCreate() {
mSQLiteOpenHelper = new NoteDbHelper(getContext());
context = getContext();
return true;
}
I think that made sure that I always have Context when I use context.getContentResolver().notifyChange(uri, null); or retCursor.setNotificationUri(context.getContentResolver(), uri); in insert/update/delete/query method- retCursor being returned cursor by mentioned methods.
I have run the aplication on my phone and did not have issues yet if I will there will probably be an edit for this post.
EDIT:
It does not make a difference after all - explanationin answer by #Mate, thank you for that I think I get it now :]
According to ContentProvider getContext() docs:
Retrieves the Context this provider is running in. Only available once onCreate() has been called -- this will return null in the constructor.
So the getContext() method does not return null in insert(), update() or delete(), because onCreate() will be called before these calls.
So it's OK to disable that warning for that line if you use it in such case...
//noinspection ConstantConditions
getContext().getContentResolver().notifyChange(uri, null);
Whenever you try to use a member or a method of an object, you can have a runtime exception if the object, whose member/method you try to use is null. Let's suppose you want to use a member/method of an object, obj. If you use it like this:
if (obj != null) {
//use members/methods of obj
}
then you prevented the problem. However, you might want to handle it as an exception, like this:
try {
//use members/methods of obj
} catch (NullPointerException npe) {
//handle the NullPointerException
}