this is my first stackoverflow post.
I was trying to build an app which retrive sensor data with LocalBroadcastManager and then update TextView in already attached fragment inside container.
I tried to call method homeFragment.passData() from MainActivity but didnt succeed.
My guess is because the fragment already inflated so it cant be updated by calling that method.
Here is MainActivity code where I call method to update the textview
#Override
public void onReceive(Context context, Intent intent) {
String azimuthValue = intent.getStringExtra("azimuth");
String pitchValue = intent.getStringExtra("pitch");
String rollValue = intent.getStringExtra("roll");
homeFragment.passData(azimuthValue, pitchValue, rollValue);
}
And here is code for HomeFragment
public class HomeFragment extends Fragment {
private static final String TAG = "HomeFragment";
private Context mContext;
private TextView xValueTextView;
private TextView yValueTextView;
private TextView zValueTextView;
private OnFragmentInteractionListener mListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
xValueTextView = (TextView) rootView.findViewById(R.id.xValueTextView);
yValueTextView = (TextView) rootView.findViewById(R.id.yValueTextView);
zValueTextView = (TextView) rootView.findViewById(R.id.zValueTextView);
Log.d(TAG, "onCreateView: layout inflated");
return rootView;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {}
public void passData(String x, String y, String z) {
xValueTextView.setText(x);
yValueTextView.setText(y);
zValueTextView.setText(z);
Log.i(TAG, "updateTextView: TextView value: " + xValueTextView.getText().toString() + "||" + yValueTextView.getText().toString() + "||" + zValueTextView.getText().toString() );
}
}
Although logcat textview.getText().toString show updated value, the actual view is not yet updated
10-21 14:03:56.240 19338-19338/pro.adhi.willyam.orientation I/HomeFragment: updateTextView: TextView value: 45||-34||4
here is screenshot from my phone : https://i.stack.imgur.com/ZDsad.png
So how to properly update textview inside fragment like what I'm trying to achieve?
I hope my question is understandable. Thankyou
You need to set up setter/getter methods in your fragment.
public class HomeFragment extends Fragment {
TextView tv;
public void setTextView(String text)
{
TextView tv = (TextView) findViewById( *your id here* );
tv.setText(text);
}
}
In the MainActivity you just use this call:
public class MainActivity extends AppCompatActivity {
...
HomeFragment.setTextView("Hello World!");
...
}
Related
Conditions:
I have an Activity and I'm creating PagerAdapter extends FragmentPagerAdapter with one Fragment class. TabLayout includes 10 tabs. I have TabLayout.addOnTabSelectedListener and there in onTabSelected() I am updating some custom variable in app's SharedPreferences which depends on current tab name and tab index. Tab's names are not static - there are loading from server too.
My task:
With this value I should make a retrofit2 Call to my server and load values in adapter with recyclerview for my Fragment.
My problem:
I am loading the same data for the different tabs, which should contatin different data! I am understand that this happens because in all cases I have the same SharedPreferences variable's value so I am making retrofit Call with same conditions.
setOffscreenPageLimit() can't be setted to 0 - default is 1 according documentation:
https://developer.android.com/reference/kotlin/androidx/viewpager/widget/ViewPager#setoffscreenpagelimit;
setUserVisibleHint() on SO I've found this like some variant for solving my problem, but it can't be overrided because is deprecated now.
Solution:
I think I should save previous and next tab name in some way and then I can make different parallel retrofit Calls with different conditions. When tab selected I can get current, previous and next tab name. But how, where and when I should make two more retrofit calls?
UPD 08.02.2022: Still thinking about this problem.
Code:
SomeActivity.java
public class SomeActivity extends BaseActivity {
private String TAG="SomeActivity";
private Context context;
private TabLayout tabs;
private ViewPager viewpager;
private ProgressBar PBLoading;
private PagerAdapter_SomePAdapter adapter;
List<String> names = new ArrayList<>();
private String[] tabTitles;
public String previousTabName;
public String nextTabName;
public int counterForPreviousTabName;
public int counterForNextTabName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
context = getApplicationContext();
String categories = AppPreferences.getCategories(context);
tabTitles = categories.split(";");
tabs = findViewById(R.id.tabs);
viewpager = findViewById(R.id.viewpager);
PBLoading = findViewById(R.id.PBLoading);
tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
#Override
public void onTabSelected(TabLayout.Tab tab) {
Log.d(TAG, "onTabSelected");
AppPreferences.setCurrentValueForRetrofit(getApplicationContext(), tab.getPosition());
counterForPreviousTabName = tmpTab.getPosition() - 1;
counterForNextTabName = tmpTab.getPosition() + 1;
//here I can get tab names.
}
});
adapter = new PagerAdapter_SomePAdapter(getSupportFragmentManager(), SomeActivity.this);
viewpager.setAdapter(adapter);
adapter.updateTitleData(tabTitles);
tabs.setupWithViewPager(viewpager);
adapter.notifyDataSetChanged();
}
}
PagerAdapter_SomePAdapter.java:
public class PagerAdapter_SomePAdapter extends FragmentPagerAdapter {
int PAGE_COUNT = 2;
private String[] tabTitles = new String[] { "", ""};
private Context mContext;
Fragment_fragment fragment_fragment;
String TAG = "PagerAdapter_SomePAdapter";
public PagerAdapter_SomePAdapter(FragmentManager fm, Context context) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
mContext = context;
fragment_fragment = new Fragment_fragment();
}
#Override public int getCount() {
return PAGE_COUNT;
}
#Override public Fragment getItem(int position) {
return fragment_fragment.newInstance(position + 1, tabTitles[position]);
}
#Override public CharSequence getPageTitle(int position) {
return tabTitles[position];
}
public void updateTitleData(String[] tabTitlesNew) {
tabTitles = tabTitlesNew;
PAGE_COUNT = tabTitlesNew.length;
notifyDataSetChanged();
}
}
Fragment_fragment.java:
public class Fragment_fragment extends Fragment {
private String TAG = "Fragment_fragment";
private static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
private View rootView;
private RecyclerView RV;
private Adapter_Items adapter;
public static Fragment_fragment newInstance(int page, String tabName) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
Fragment_fragment fragment = new Fragment_fragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mPage = getArguments().getInt(ARG_PAGE);
}
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
mContext=context;
}
#SuppressLint("ClickableViewAccessibility")
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.content_list, container, false);
RV = rootView.findViewById(R.id.recycler_view);
new loadDataAS().execute();
return rootView;
}
private void loadData(){
//retrofit call code;
}
class loadDataAS extends AsyncTask<Void, Void, Void> {
final ProgressDialog progress = new ProgressDialog(mContext);
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
loadData();
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
adapter = new Adapter_Items(arguments, arguments2, arguments3);
RV.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
}
Adapter_Items:
public class Adapter_Items extends RecyclerView.Adapter<Adapter_Items.ViewHolder>{
private LayoutInflater mInflater;
private Context mContext;
private static String TAG = "Adapter_Items";
public Adapter_Items(List<Integer>arguments, List<String>arguments2, List<String>arguments3){
//initializing arguments
}
// inflates the row layout from xml when needed
#NotNull
#Override
public ViewHolder onCreateViewHolder(#NotNull ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recycle_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
//setting view's information
}
#Override
public int getItemCount() {
return arguments.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
}
}
}
First thing,
fragment should contain different data
Saving tab name after tab selected will not work. You should remove this
AppPreferences.setCurrentValueForRetrofit(getApplicationContext(),
tab.getPosition());
You should call retrofit code inside the fragment with the tabName (Not from sharedPref) to get data for that tab.
For this, make the following changes,
You are already passing the tabName to fragment instance
newInstance(int page, String tabName)
use that tabName and pass to your AsyncTask -> loadData() as
loadData(tabName);
Then you can use that in your retrofit call and get the data.
Note:
setOffscreenPageLimit()
This method will load fragments just before they are completely visible. It would be useful and a great user experience to display data directly rather than fetching only when user selects the tab.
The problem is that when i click in the button the first time no text is in the EditText object, in the second click it works but does not replace the frame.
I Have one activity with a container for a fragment that has a editText and a button, when click the button i replace the fragment in the container with another fragment to display the text in the edit text.
I'm following this tutorial:
https://www.youtube.com/watch?v=OLbsiE42JvE&list=PLshdtb5UWjSrOJfpFOE-u55s3SnY2EO9v&index=14
i'm in video "Android tutorial (2018) - 14 - Fragment to Fragment Communication".
The diference from this tutorial from my app is that my activity is the third in the same project, and i'm working in that activity as it was my main.
public class FinalActivity extends AppCompatActivity implements HeadLineFragment.OnMessageListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_final);
if(findViewById(R.id.final_activity_fragment)!= null) {
if (savedInstanceState != null) {
return;
}
HeadLineFragment headLineFragment = new HeadLineFragment();
getSupportFragmentManager().beginTransaction().add(R.id.final_activity_fragment, headLineFragment, null).commit();
}
}
#Override
public void onMessageSend(String message) {
ArticleFragment articleFragment = new ArticleFragment();
Bundle bundle = new Bundle();
bundle.putString("message",message);
articleFragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction().replace(R.id.final_activity_fragment, articleFragment,null).addToBackStack(null).commit();
}
}
public class HeadLineFragment extends Fragment {
OnMessageListener onMessageListener;
private Button button;
private EditText editText;
public interface OnMessageListener{
public void onMessageSend(String message);
}
public HeadLineFragment(){
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.headline_fragment, container, false);
button = view.findViewById(R.id.bfrag);
editText = view.findViewById(R.id.editText21);
button.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
String message = editText.getText().toString();
String s = editText.getText().toString();
onMessageListener.onMessageSend(message);
}
});
return view;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
Activity activity = (Activity) context;
try {
onMessageListener = (OnMessageListener) activity;
}catch (ClassCastException e){
throw new ClassCastException(activity.toString() + " must implement OnMessageListener....");
}
}
#Override
public void onResume() {
super.onResume();
editText.setText("");
}
}
public class ArticleFragment extends Fragment {
private TextView textView;
public ArticleFragment(){}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(
R.layout.article_fragment,container, false);
textView = view.findViewById(R.id.txt_message_display);
Bundle bundle = getArguments();
String message = bundle.getString("message");
textView.setText(message);
return view;
}
}
I expect that the functionality has the same behavior as in the video of the tutorial
I eventually solved my own problem, the layout of the Activity had a fragment instead of a frame layout. By changing that the problem was solved.
I have an image in feed_item.xml that is inflated in the custom adapter.I am able to handle click events for the image.
I Have a relative layout in my activity_main that is rendered player.setVisibility(View.GONE); when my Main Activity is launched.I would like to setVisibility(View.VISIBLE) of this layout when my image in the row is clicked.
I have trouble relating the two layouts with my Custom Adapter and Main Activity.Any suggestions will be appreciated!!
FeedListAdapter.java
public class FeedListAdapter extends BaseAdapter {
private Activity activity;
private LayoutInflater inflater;
private List<FeedItem> feedItems;
ImageLoader imageLoader = AppController.getInstance().getImageLoader();
public FeedListAdapter(Activity activity, List<FeedItem> feedItems) {
this.activity = activity;
this.feedItems = feedItems;
}
#Override
public int getCount() {
return feedItems.size();
}
#Override
public Object getItem(int location) {
return feedItems.get(location);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (inflater == null)
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null)
convertView = inflater.inflate(R.layout.feed_item, null);
TextView name = (TextView) convertView.findViewById(R.id.name);
FeedItem item = feedItems.get(position);
name.setText(item.getName());
String fontPath = "fonts/Lato-Light.ttf";
// Loading Font Face
Typeface tf = Typeface.createFromAsset(activity.getAssets(), fontPath);
// Applying font
name.setTypeface(tf);
ImageView play=(ImageView)convertView.findViewById(R.id.play);
play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(activity, "Show Layout!", Toast.LENGTH_SHORT).show();
}
});
ImageView options=(ImageView)convertView.findViewById(R.id.options_popup);
options.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showFilterPopup(view);
}
});
return convertView;
}
}
MainActivity.java
public class MainActivity extends ActionBarActivity {
RelativeLayout player;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.app_bar);
setSupportActionBar(toolbar);
TextView mToolBarTextView = (TextView) findViewById(R.id.text_view_toolbar_title);
mToolBarTextView.setText("Home");
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
listView = (InnerGridView) findViewById(R.id.list);
feedItems = new ArrayList<FeedItem>();
listAdapter = new FeedListAdapter(this, feedItems);
listView.setAdapter(listAdapter);
player = (RelativeLayout) findViewById(R.id.player);
player.setVisibility(View.GONE);
}
}
You can create your own interface with a method like this
public interface OnClickInMyAdapterListener {
public void onItemclicked();
}
than your activity should implement this interface and override its method
public class MainActivity extends ActionBarActivity implements OnClickInMyAdapterListener {
...
...
}
#Override
public void onItemclicked() {
// do what you want
}
change your adapter in order to recive the interface
private OnClickInMyAdapterListener myActivityInterface;
public FeedListAdapter(Activity activity, List<FeedItem> feedItems, OnClickInMyAdapterListener myActivityInterface ) {
this.activity = activity;
this.feedItems = feedItems;
this.myActivityInterface= myActivityInterface;
}
in the activity pass the interface to the adapter
listAdapter = new FeedListAdapter(this, feedItems, (OnClickInMyAdapterListener ) this);
and use it in your adapter wherever you want
this.myActivityInterface.onItemclicked();
... This solution is useful also if your adapter is used in more diffrent activites
You can write one public method in Activity
And cast your activity context to your Activity
((MainActivity)activity).doSomething();
activity is context you are passing to adapter
doSomething is method in activity
Rather than setting OnClickListeners on the Views within your custom Adapter, you should call:
listView.setOnItemSelectedListener(this);
And have your Activity implement AdapterView.OnItemSelectedListener
See http://developer.android.com/reference/android/widget/AdapterView.OnItemSelectedListener.html
I've make it more simple and updated it based on the answers in my previous post: Adding Assigned Values in Spinner NullPointerException
I have a MainAcitivty that uses a ViewPager. I have 2 Fragments in my MainActivity (FragA and FragB)
In my FragA I have a spinner. While in FragB, I have a TextView and a Button.
Now what am I trying to do is, when I select "Hello" in my spinner, my int a will have a value of 5. And when I click the Button, 5 will display in the TextView.
Here's my code:
FragA
public class FragA extends Fragment {
Spinner spinner1;
String s1;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fraga, container, false);
spinner1 = (Spinner) view.findViewById(R.id.spinner1);
ArrayAdapter<CharSequence> adapter_a = ArrayAdapter.createFromResource(getActivity(), R.array.spinner1,android.R.layout.simple_spinner_item );
spinner1.setAdapter(adapter_a);
s1 = spinner1.getSelectedItem().toString();
return view;
}
public int getInt() {
int a = 0;
if(s1.equals("Hello")) {
a = 5;
}
return a;
}
}
MainActivity
public class MainActivity extends FragmentActivity {
ViewPager viewPager = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager)findViewById(R.id.pager);
FragmentManager fragmentManager = getSupportFragmentManager();
viewPager.setAdapter(new MyAdapter(fragmentManager));
}
public class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter (FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = null;
if (i == 0)
{
fragment = new FragA();
}
if (i == 1)
{
fragment = new FragB();
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
}
public String get() {
FragA FragA = new FragA();
return Integer.toString(FragA.getInt());
}
}
FragB
public class FragB extends Fragment{
TextView textView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragb, container, false);
textView = (TextView) view.findViewById(R.id.textview);
Button button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(Click);
return view;
}
OnClickListener Click = new OnClickListener() {
#Override
public void onClick(View v) {
textView.setText(((MainActivity)getActivity()).get());
}
};
}
By the way, I have no problem passing the value of a from FragA to FragB when this is my code:
public int getInt() {
int a = 5;
return a;
}
But, it doesn't involve my spinner and that's not I want to do.
Here is a simple way to communicate between fragments.
In MainActivity, keep static instances of the fragments.
public static FragA fragmentA;
public static FragB fragmentB;
Now if you want to access FragB from FragA, write something similar:
((MainActivity) getActivity()).fragmentB.setSomething();
And Here is a better/proper way to communicate between fragments:
http://developer.android.com/training/basics/fragments/communicating.html
I've created simple fragment.
FRAGMENT CLASS
public class MyFragment extends Fragment {
static int count = 0;
static TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("TEST", "oncreate");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag, container, false);
tv = (TextView) view.findViewById(R.id.tv);
return view;
}
public static TextView setMyText(String text) {
tv.setText(text);
return tv;
}
}
But the thing is that onCreate fragment is called twice (when activity is first launched). Anyone has an idea why? In fact every lifecycle method is called twice ( onAttach, onResume..). I'm not rotating screen or anything, if someone might wonder. Is this common case or I'm doing something wrong here?
ACTIVITY CLASS
public class MainActivity extends FragmentActivity {
private static int COUNT = 0;
private static int COUNT2 = 5;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_pager);
ViewPager vp = (ViewPager) findViewById(R.id.vp);
vp.setAdapter(new MyAdapter(getSupportFragmentManager()));
vp.setOnPageChangeListener(new CustomPageListener());
}
private static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
MyFragment mf = new MyFragment();
return mf;
}
#Override
public int getCount() {
return 5;
}
}
private class CustomPageListener extends ViewPager.SimpleOnPageChangeListener {
#Override
public void onPageSelected(int position) {
MyFragment.setMyText("This is page "+position);
}
}
}
By default FragmentStatePagerAdapter will instantiate two pages for ViewPager. The onCreate it is called twice, once for each fragment returned by public Fragment getItem(int position)