How to inflate layout from extended activity? - java

I have extended BaseActivity from ActionBarActivity, in which I set the activity's content. There's a FrameLayout in the layout file I use.
When I extend BaseActivity to use in e.g. MainActivity, I'd like MainActivity to inflate the FrameLayout with a custom layout file.
I couldn't come up with a solution. I always got errors. This is how far I came.
BaseActivity.java
public class BaseActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.base);
}
}
MainActivity.java
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
FrameLayout mFrame = (FrameLayout) findViewById(R.id.content);
mFrame.addView(LayoutInflater.from(context).inflate(R.layout.activity_nav_test, mFrame, true));
return super.onCreateView(parent, name, context, attrs);
}
Thanks a lot for your help!
Chris

Your approach seems to be proper but add view inside frame layout in onCreate method instead.
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout mFrame = (FrameLayout) findViewById(R.id.content);
mFrame.addView(LayoutInflater.from(this).inflate(R.layout.activity_nav_test, mFrame, true));
}

In this method :
#Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
FrameLayout mFrame = (FrameLayout) findViewById(R.id.content);
mFrame.addView(LayoutInflater.from(context).inflate(R.layout.activity_nav_test, mFrame, true));
return super.onCreateView(parent, name, context, attrs);
}
You must return ur custom view. Try this. I hope it helps
return mFrame;

Related

How do you show a DialogPreference

Here is a random layout called some_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"">
<!-- Some views in here -->
</androidx.constraintlayout.widget.ConstraintLayout>
Here is a class SomeDialog.java that extends DialogPreference:
import android.content.Context;
import androidx.preference.DialogPreference;
public class SomeDialog extends DialogPreference {
public SomeDialog(Context context) {
super(context);
}
#Override
public int getDialogLayoutResource() {
return R.layout.some_layout;
}
}
And here's the preference screen:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<android.example.perappbrightness.SomeDialog
android:title="#string/rate_app"
android:summary="#string/rate_summary"
android:key="rate_app"/>
</PreferenceScreen>
Relevant part of crash error. The line at which MainActivty crashes is PreferenceManager.setDefaultValues(this, R.xml.preferences, false);:
java.lang.RuntimeException: Unable to start activity ComponentInfo{android.example.perappbrightness/android.example.perappbrightness.MainActivity}: android.view.InflateException: Binary XML file line #36: Error inflating class android.example.perappbrightness.SomeDialog
Caused by: android.view.InflateException: Binary XML file line #36: Error inflating class android.example.perappbrightness.SomeDialog
android.example.perappbrightness.MainActivity.onCreate(MainActivity.java:72)
 
SettingsActivity.java is an untouched. It's from the template of Android Studio.
What am I doing wrong?
First, you need to add more constructors to SomeDialog. The Context constructor is not enough since the Preference will be inflated from xml. Having the following three constructors is usually sufficient:
public SomeDialog(Context context) {
super(context);
}
public SomeDialog(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SomeDialog(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
In addition to that, the SettingsFragment in your SettingsActivity needs to implement onDisplayPreferenceDialog(Preference preference) to show a custom dialog for the custom Preference.
public static class SettingsFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
}
#Override
public void onDisplayPreferenceDialog(Preference preference) {
if (preference instanceof SomeDialog) {
MyDialogFragment dialogFragment = new MyDialogFragment();
Bundle b = new Bundle();
b.putString(MyDialogFragment.KEY, preference.getKey());
b.putInt(MyDialogFragment.KEY_LAYOUT_RES_ID, ((SomeDialog) preference).getDialogLayoutResource());
dialogFragment.setArguments(b);
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(getFragmentManager(), null);
} else super.onDisplayPreferenceDialog(preference);
}
}
And, last not least, you also have to provide the custom dialog itself. This is done via a class extending DialogFragment.
My very simple DialogFragment has a TextView inside a FrameLayout, just to show it works
MyDialogFragment code:
public class MyDialogFragment extends DialogFragment {
public static final String KEY = "key";
public static final String KEY_LAYOUT_RES_ID = "resid";
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(requireArguments().getInt(KEY_LAYOUT_RES_ID), container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView textView = view.findViewById(R.id.textView);
textView.setText(requireArguments().getString(KEY));
}
}

Update textview inside fragment from MainActivity

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!");
...
}

Passing views from abstract activity

I'm trying to pass some views to ClassA from abstract ClassB, so that ClassA can use: ClassA extends ClassB
Instead of using something like this for each view I'd like to be inherited/passed on:
protected View getView1() {
return view1;
}
I want a bulk way to let ClassX (in this case, ClassA) know which views it should be using. But keep some views private to ClassB to use for itself.
The code below does work, but is it okay to do it this way? or is there a better way?
public abstract class ClassB extends Activity {
abstract void useTheseViews(View view1, View view2);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View view1 = findViewById(R.id.view1);
View view2 = findViewById(R.id.view2);
useTheseViews(view1, view2);
View view3 = findViewById(R.id.view3);
view3.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// do something independent here
}
});
}
}
public class ClassA extends ClassB {
private View view1, view2;
#Override
void useTheseViews(View view1, View view2) {
this.view1 = view1;
this.view2 = view2;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view1.setOnClickListener(..);
view2.setOnClickListener(..);
}
}
Reason? ClassA and ClassX use the same base layout, but do different functions on the same views.
My ClassB holds a base layout and initializes the views (buttons, switches..), and uses some of the views for itself regardless of what class extends it.
I would do it this way
public abstract class ClassB extends Activity {
private View view1, view2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view1 = findViewById(R.id.view1);
view2 = findViewById(R.id.view2);
}
protected View getView1(){
return view1;
}
protected View getView2(){
return view2;
}
}
public class ClassA extends ClassB {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getView1().setOnClickListener(..);
getView2().setOnClickListener(..);
}
}
and if you don't want to create protected getter for each view, use a holder class
public abstract class ClassB extends Activity {
protected class ViewHolder {
public final View view1, view2;
public ViewHolder(){
view1 = findViewById(R.id.view1);
view2 = findViewById(R.id.view2);
}
}
private ViewHolder viewHolder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewHolder = new ViewHolder();
}
protected ViewHolder getViewHolder(){
return viewHolder;
}
}
public class ClassA extends ClassB {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getViewHolder().view1.setOnClickListener(..);
getViewHolder().view2.setOnClickListener(..);
}
}
the way I'm suggesting seems coherent with OOP, also, if you say ClassA and ClassB I would assume that ClassA extends ClassB. What happens if you want to create a third class that extends ClassA?

Android Fragment initialization

I am meeting with Fragment for the first time. So it is a bit complicated to me. I am reading a tutorial at android-hive. But I am unable to understand a point. There are something I don't understand.
There are oneFragment(), twoFragment()... But I can't initiate them. So, please complete any of those... oneFragmemt() or twoFragment() from this link. I will be so pleased. Help me...
Muhamar, you always need to initiate the fragment inside an activity. If your fragment 1 has this code:
public class OneFragment extends Fragment{
public OneFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_one, container, false);
}
}
then in the main activity you can initiate like in the tutorial says:
public class MainActivity extends AppCompatActivity {
//blabla
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//blablabla
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new OneFragment(), "ONE");
//blabla
viewPager.setAdapter(adapter);
}
In this case the main activity is using an adapter to display more than one fragment, so you should have in your code more the file of the adapter, which you can find also in the tutorial.
UPDATE:
if you don't want to initalize the fragment with the adapter, you have to do two things to initialize the fragment:
1) Put fragment in layout: in the layout of your main activity you have to include a fragment and identify it (in this example android:id="#+id/headlines_fragment"):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment android:name="com.example.android.fragments.HeadlinesFragment"
android:id="#+id/headlines_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
2) Insert the fragment in your main activity: with the following code you can add the freagment in your activity:
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
OneFragment firstFragment = new OneFragment();
// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.headlines_fragment, firstFragment).commit();
}
}
UPDATE 2: to initialize from the adapter you just have to add it on the main activity, as the tutorial says. add this class on main activity:
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Hope it helps ;)

Combining Java layout and xml

I created a custom RelativeLayout and I want to populate it with a design from an xml file, is it possible?
My code:
This is the onCreate from my main activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new CustomRelativeLayout(this));
getLayoutInflater().inflate(R.layout.three_items_list_row, null, false);
}
Just call addView for your custom RelativeLayout instance,
I must say it not a very good coding because you add a Layout level
You need to modify your class to this:
class CustomRelativeLayout{
public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyle){
super(context,attrs,defStyle);
init();
}
public CustomRelativeLayout(Context context, AttributeSet attrs){
super(context,attrs);
init();
}
public CustomRelativeLayout(Context context){
super(context);
init();
}
private void init(){
LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View v = inflatet.inflate(R.layout.three_items_list_row, this, false);
addView(v);
}
}

Categories