How to use EventBus in fragment? - java

In my application i use fragment into Activity and i want when run one code into fragment, call some codes in Activity.
I write below codes but when load data not run activity code.!
Fragment codes:
public void loadRecentPosts() {
ApiUtils.getApiInterface().getRecentPosts(AppConstant.DEFAULT_PAGE).enqueue(new Callback<List<Post>>() {
#Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
if (response.isSuccessful()) {
if (!recentPostList.isEmpty()) {
recentPostList.clear();
}
recentPostList.addAll(response.body());
if (recentPostList.size() > 0) {
recentPostAdapter.notifyDataSetChanged();
EventBus.getDefault().post(new LoadMainDataEvent());
}
} else {
showEmptyView();
}
pbSectionLoader.setVisibility(View.GONE);
}
#Override
public void onFailure(Call<List<Post>> call, Throwable t) {
showEmptyView();
t.printStackTrace();
}
});
}
}
Activity code:
#Subscribe (threadMode = ThreadMode.MAIN)
public void onLoadMainDataEvent(LoadMainDataEvent loadMainDataEvent){
Toast.makeText(activity, "OK", Toast.LENGTH_SHORT).show();
}
I want when get data from server into fragment, run codes in activity page.
How can i fix it? please help me. Thanks

Try this it work fine
FragmentClass.java
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageBusEvent event) {
}
#Override
public void onDestroy() {
//unregister event bus
EventBus.getDefault().unregister(this);
super.onDestroy();
}

Related

Swipe to refresh data using SwipeRefreshLayout in fragment?

I want my layout to be refreshed when the app starts and the data should show in and when the user swipes the data should be updated and show new data if new data is available on the server.
The actual problem is that the data is not loading when the app is started. Rather it is happening only on swiping. How can I achieve that on opening the app the data is loaded first and then the data is updated on swiping?
public class FirstFragment extends Fragment {
FragmentFirstBinding binding;
APIInterfaces interfaces;
ArrayList<VideoModels> list = new ArrayList<>();
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentFirstBinding.inflate(inflater, container, false);
MyAdapter adapter = new MyAdapter(list,getContext());
binding.myRecyclerView.setAdapter(adapter);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(),2);
binding.myRecyclerView.setLayoutManager(gridLayoutManager);
interfaces = RetrofitInstance.getRetrofit().create(APIInterfaces.class);
binding.swipeToRefresh.setRefreshing(true);
binding.swipeToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
interfaces.getPosts().enqueue(new Callback<List<VideoModels>>() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onResponse(#NonNull Call<List<VideoModels>> call, #NonNull Response<List<VideoModels>> response) {
list.clear();
if (response.isSuccessful()) {
assert response.body() != null;
list.addAll(response.body());
adapter.notifyDataSetChanged();
binding.swipeToRefresh.setRefreshing(false);
}
}
#Override
public void onFailure(#NonNull Call<List<VideoModels>> call, #NonNull Throwable t) {
Toast.makeText(getContext(), "Check you Internet", Toast.LENGTH_SHORT).show();
binding.swipeToRefresh.setRefreshing(false);
}
});
}
});
binding.swipeToRefresh.setRefreshing(false);
return binding.getRoot();
}
}
EDIT-1: Added complete code.
Your answer will helpful for me.
You need to call this method in onResume() state
public void getData() {
interfaces.getPosts().enqueue(new Callback<List<VideoModels>>() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onResponse(#NonNull Call<List<VideoModels>> call, #NonNull Response<List<VideoModels>> response) {
list.clear();
if (response.isSuccessful()) {
assert response.body() != null;
list.addAll(response.body());
adapter.notifyDataSetChanged();
binding.swipeToRefresh.setRefreshing(false);
}
}
#Override
public void onFailure(#NonNull Call<List<VideoModels>> call, #NonNull Throwable t) {
Toast.makeText(getContext(), "Check you Internet", Toast.LENGTH_SHORT).show();
binding.swipeToRefresh.setRefreshing(false);
}
});
}
if you call binding.swipeLayout.isRefreshing = true
in SwipeRefreshLayout source code, mNotify boolean value is false
so cannot do anything in setOnRefreshListener
public void onAnimationEnd(Animation animation) {
if (mRefreshing) {
// Make sure the progress view is fully visible
mProgress.setAlpha(MAX_ALPHA);
mProgress.start();
if (mNotify) {
if (mListener != null) {
mListener.onRefresh();
}
}
mCurrentTargetOffsetTop = mCircleView.getTop();
} else {
reset();
}
}
this is why setOnRefreshListener not invoke
if you want manual invoke it do like this by reflect set mNotify boolean value is true
val swipeClass = SwipeRefreshLayout::class.java
val method = swipeClass.getDeclaredMethod("setRefreshing", Boolean::class.java, Boolean::class.java)
method.isAccessible = true
method.invoke(binding.swipeLayout, true, true)
After finding the solution for 1 day. Finally, I found my solution.
To use SwipeRefreshLayout work in Fragment and want to refresh your data Onswipe. use the below code and modify it as your requirement.
This is a fragment.
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentFirstBinding.inflate(inflater, container, false);
// swiping on starting of an app.
binding.swipeToRefresh.setRefreshing(true);
getData();
binding.swipeToRefresh.setRefreshing(false);
// when user swipe
binding.swipeToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onRefresh() {
getData();
}
});
return binding.getRoot();
}
public void getData(){
// you have to put all of your onCreate code here to work properly. most of time it throws an error. So, make sure you added code properly.
ArrayList<VideoModels> list = new ArrayList<>();
MyAdapter adapter = new MyAdapter(list,getContext());
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(),2);
binding.myRecyclerView.setAdapter(adapter);
binding.myRecyclerView.setLayoutManager(gridLayoutManager);
binding.swipeToRefresh.setRefreshing(true);
interfaces = RetrofitInstance.getRetrofit().create(APIInterfaces.class);
interfaces.getPosts().enqueue(new Callback<List<VideoModels>>() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onResponse(#NonNull Call<List<VideoModels>> call, #NonNull Response<List<VideoModels>> response) {
list.clear();
if (response.isSuccessful()) {
assert response.body() != null;
list.addAll(response.body());
adapter.notifyDataSetChanged();
binding.swipeToRefresh.setRefreshing(false);
}
}
#Override
public void onFailure(#NonNull Call<List<VideoModels>> call, #NonNull Throwable t) {
Toast.makeText(getContext(), "Check you Internet", Toast.LENGTH_SHORT).show();
binding.swipeToRefresh.setRefreshing(false);
}
});
}

Fragment and BroadcastReceiver freeze app after some seconds

Here is full code of the app which freezes (UI) after some seconds of work.
Is something dangerous here?
Thank you!
public class FragmentOne extends Fragment {
private Context _context;
private View view;
private BroadcastReceiver broadcastReceiver;
public FragmentOne() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_fragment_one, container, false);
setup();
return view;
}
#Override
public void onAttach(Context context)
{
super.onAttach(context);
_context = context;
}
private void setup()
{
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent i)
{
try
{
DLocation dLocation = (DLocation) i.getExtras().get("coordinates");
if (dLocation != null) {
Log.d("Первый фрагмент", "Применение параметров шир. сообщения к контролам окна");
TextView textLon = (TextView)view.findViewById(R.id.textLon);
textLon.setText(dLocation.Longitude);
TextView textLat = (TextView)view.findViewById(R.id.textLat);
textLat.setText(dLocation.Latitude);
TextView textTime = (TextView)view.findViewById(R.id.textTime);
textTime.setText(dLocation.TimeOfRequest);
TextView textErrors = (TextView)view.findViewById(R.id.textErrors);
textErrors.setText(dLocation.Errors);
}
}
catch (Exception ex)
{
Toast.makeText(getActivity(), ex.getMessage(), Toast.LENGTH_LONG).show();
}
}
};
_context.registerReceiver(broadcastReceiver, new IntentFilter("location_update"));
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
if (broadcastReceiver != null) {
_context.unregisterReceiver(broadcastReceiver);
}
}
}
Root Cause
I think you are using a 3rd party library to detect location. The library is receiving the GPS coordinates at a very high rate. These coordinates are then received by your broadcast receiver. Your broadcast receiver is doing it's work on the UI thread. The reason why your app freezes is because the UI thread is doing work at very high rate.
Solution
The solution to your problem lies in Bound Service. You can find code examples in android developer docs Bound Services.
For use cases like a music player, where media is played in a background thread but duration of played music is shown on the UI, bound service can be useful. I hope this sets you in the right direction.

Destroyed fragment content remains on screen

I have fragments making API call via Retrofit + RxJava. I subscribe the Subscription in onActivityCreated and dispose at onDestroy. When I switch from FragmentA to FragmentB while FragmentA is still processing the API call, FragmentB appears below the content of FragmentA. It means FragmentA contents remains on top of the screen and there is no control over it.
FragmentA.java
public class FragmentA extends Fragment {
#BindView(R.id.swipe_refresh) SwipeRefreshLayout mSwipeRefresh;
#BindView(R.id.recycler_view) RecyclerView mRecyclerView;
private ItemsAdapter mAdapter;
private CompositeDisposable mCompositeDisposable = new CompositeDisposable();
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_list, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
ButterKnife.bind(this, view);
mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
fetchItems();
}
});
mAdapter = new ItemsAdapter();
mRecyclerView.setAdapter(mAdapter);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mSwipeRefresh.setRefreshing(true);
fetchItems();
}
#Override
public void onDestroy() {
super.onDestroy();
mCompositeDisposable.clear();
}
private void fetchItems() {
RequestInterface requestInterface = Utils.createService();
mCompositeDisposable.add(requestInterface.getItemsForA()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Response>() {
#Override
public void accept(#NonNull Response response) throws Exception {
mAdapter.swapItems(response.getItems());
mSwipeRefresh.setRefreshing(false);
}
}, new Consumer<Throwable>() {
#Override
public void accept(#NonNull Throwable throwable) throws Exception {
Toast.makeText(getActivity(), "Error: " + throwable.getLocalizedMessage(), Toast.LENGTH_LONG).show();
mSwipeRefresh.setRefreshing(false);
}
}));
}
}
FragmentB.java
public class FragmentB extends Fragment {
//Same as `FragmentA` but different API call
}
I have also did some logging and found out that all of the life-cycle methods for FragmentA including onDestroyView gets called.
You need to call following methods on SwipeRefreshLayout to fix this.
swipeRefreshLayout.setRefreshing(false);
swipeRefreshLayout.destroyDrawingCache();
swipeRefreshLayout.clearAnimation();
super.onDestroyView();
}

java.lang.IllegalStateException: Activity has been destroyed when using datetime picker library

I am new to Android development.
I want to create a customized date and time picker in my Application.
I downloaded this library from github to achieve this.
When I try to use it in my application, it crashes and I got the following error:
java.lang.IllegalStateException: Activity has been destroyed
Can anybody look at my code to see what I am missing?
import jp.seesaa.android.datetimepicker.date.DatePickerDialog;
import jp.seesaa.android.datetimepicker.time.RadialPickerLayout;
import jp.seesaa.android.datetimepicker.time.TimePickerDialog;
/**
* Created by MAC12 on 20-Apr-15.
*/
public class HomeFragment extends Fragment implements DatePickerDialog.OnDateSetListener, TimePickerDialog.OnTimeSetListener {
public HomeFragment(){
}
String tg="HomeFragment ";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
// cls.findViewById(R.layout.fragment_home).setOnClickListener();
return rootView;
}
#Override
public void onViewCreated(View view,Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
Button button = (Button) view.findViewById(R.id.date_picker_day);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ActivityCls cls=new ActivityCls();
cls.Start();
}
});
}
#Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class.getDeclaredField("fragment_home");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public class ActivityCls extends FragmentActivity
{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// findViewById(R.layout.date_picker_day).setOnClickListener();
DatePickerDialog.newInstance(HomeFragment.this, 2006, 1, 2)
.show(getSupportFragmentManager(), "datepicker");
}
public void Start()
{
DatePickerDialog.newInstance(HomeFragment.this, 2006, 1, 2)
.show(getSupportFragmentManager(), "datepicker");
}
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onStop() {
// Log.w(TAG, "App stopped");
super.onStop();
}
#Override
public void onDestroy() {
// Log.w(TAG, "App destoryed");
super.onDestroy();
}
#Override
public void onDateSet(DatePickerDialog dialog, int year, int monthOfYear, int dayOfMonth) {
}
#Override
public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) {
}
}
http://developer.android.com/guide/topics/ui/controls/pickers.html here you can see the format of the date is moth day and year, you are pasing year before then you have that exception.

android hide toolbar in specific fragment

I have a problem that I don't know how to solve. How do you hide a toolbar in a specific fragment, I have already been searching around on the internet and what I found was communicating activity and fragment would solve it. But it doesn't work for me at all, here is my code:
main_activity:
public class MainActivity extends ActionBarActivity implements like_frag.OnHideToolbar{
....
public void onHidingToolbar(int position){
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
if(toolbar == null){
getSupportActionBar().hide();
}else{
getSupportActionBar().hide();
}
}
like_frag.java
public class like_frag extends Fragment {
OnHideToolbar mCallback;
Toolbar toolbar;
public interface OnHideToolbar {
public void onHidingToolbar(int position);
}
public void onAttach(Activity activity){
try{
mCallback = (OnHideToolbar) activity;
}catch(ClassCastException e){
throw new ClassCastException(activity.toString() + "error implementing");
}
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View rootView = inflater.inflate(R.layout.swipefrag, container, false);
toolbar = (Toolbar)getActivity().findViewById(R.id.toolbar);
return rootView;
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
}
thanks in advance.
I have a drawer inside the toolbar.
Put this code in fragment in which you want to hide toolbar...
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().hide();
}
#Override
public void onStop() {
super.onStop();
((AppCompatActivity)getActivity()).getSupportActionBar().show();
}
In the fragment's onCreate method call:
((AppCompatActivity) getActivity()).getSupportActionBar().hide();
Replace AppCompateActivity with the activity class you used.
Edited:
You could simply use the onResume method to call hide() and the onStop method to call show() as suggested in some of the comments.
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().hide();
}
#Override
public void onStop() {
super.onStop();
((AppCompatActivity)getActivity()).getSupportActionBar().show();
}
If you are using the new Navigation Component, add this while setting up the toolbar
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
#Override
public void onDestinationChanged(#NonNull NavController controller,
#NonNull NavDestination destination, #Nullable Bundle arguments) {
if(destination.getId() == R.id.full_screen_destination) {
toolbar.setVisibility(View.GONE);
bottomNavigationView.setVisibility(View.GONE);
} else {
toolbar.setVisibility(View.VISIBLE);
bottomNavigationView.setVisibility(View.VISIBLE);
}
}
});
And for Kotlin, you can do the following:
navController.addOnDestinationChangedListener { _, destination, _ ->
if(destination.getId() == R.id.full_screen_destination) {
toolbar.setVisibility(View.GONE)
bottomNavigationView.setVisibility(View.GONE);
} else {
toolbar.setVisibility(View.VISIBLE)
bottomNavigationView.setVisibility(View.VISIBLE);
}
}
Create an interface in the fragment and use it to tell the parent activity to hide the toolbar.
Add these lines to your fragment:
private OnEventListener listener;
public interface OnEventListener {
void hideToolbar() ;
}
public void setOnEventListener(OnEventListener listener) {
this.listener = listener;
}
After creating your fragment in the main activity add:
myFragment.setOnEventListener(new MyFragment.OnEventListener() {
#Override
public void hideToolbar() {
getSupportActionBar().hide();
}
});
Whenever you need to hide the toolbar execute:
listener.hideToolbar();
from inside your fragment.
Just add these methods to the fragment where you want to diable the toolbar ,and also in the fragment's onStop() make it visible again.
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().hide();
}
#Override
public void onStop() {
super.onStop();
((AppCompatActivity)getActivity()).getSupportActionBar().show();
}
in kotlin hide and show supportActionBar as follows:
override fun onResume() {
super.onResume()
(activity as AppCompatActivity).supportActionBar?.hide()
}
override fun onStop() {
super.onStop()
(activity as AppCompatActivity).supportActionBar?.show()
}
and if you want to have your own custom toolbar, in OncreateView set:
//your Custom toolbar in xml
val toolbar = binding.toolbar
(activity as AppCompatActivity).setSupportActionBar(toolbar)
Simply use supportActionBar?.hide() or supportActionBar?.show().
If you are using NavigationController:
navController.addOnDestinationChangedListener { controller, destination, arguments ->
if (destination.id == R.id.loginSuccessFragment) {
supportActionBar?.hide()
} else {
supportActionBar?.show()
}
}
Put this code in fragment in which you want to hide toolbar...
Add this( ((AppCompatActivity)getActivity()).getSupportActionBar().hide();) in onCreateView or in onResume.
and do this in onDestroy()
#Override
public void onDestroy() {
super.onDestroy();
((AppCompatActivity)getActivity()).getSupportActionBar().show();}
use getSupportActionBar().hide(); and getSupportActionBar().show(); in lifeCycle methods
You can try it.
#Override
public void onDestinationChanged(#NonNull NavController controller, #NonNull NavDestination destination, #Nullable Bundle arguments) {
if (destination.getId() == R.id.nav_dashboard){
if (toolbar !=null){
toolbar.setVisibility(View.GONE);
}
}else {
toolbar.setVisibility(View.VISIBLE);
}
}

Categories