Android CardView implementation - java

I created an Android app with list view. Whenever the an element is clicked, it passes intent to cardview.I have a single cardview in my layout file, and use it for every element in the listView.
For each list item, I define different implementation for the CardView in Java passing intents from one java file to the other. .
Please is this a good practice using a single card view and Recycler View for multiple elements changing their text programmatically. I haven't seen anyone do something like that.
Edit
#Ankit something like ...
Something like
>
<android.support.v7.widget.RecyclerView/>
</LinearLayout>```
**Tutorial page 1**
```public class Lesson_Galaxy_One extends AppCompatActivity
{ super.onCreate(savedInstanceState);
setContentView(R.layout.lesson_galaxy);
}```
**Tutorial 2**
```public class Lesson_Galaxy_Two extends AppCompatActivity
{ super.onCreate(savedInstanceState);
setContentView(R.layout.lesson_galaxy);
}```
**Tutorial 3**
```public class Lesson_Galaxy_Three extends AppCompatActivity
{ super.onCreate(savedInstanceState);
setContentView(R.layout.lesson_galaxy);
}```
Each with different elements for the RecyclerView's CardView with intents being passed from one to the other.

There won't be any issues of using a single card view for multiple list items.It's totally fine .

Related

Application architecture: ViewPager2, Fragments and MutableLiveData

Good evening,
I am new at Android App development. I have a project where I receive data from multiple sensors which are connected an instrument.
At this time, I can select any sensor and stream its data using AudioTrack. The streaming is from a service and this service is bound to the MainActivity instance. A single sensor data is streamed at the time. This is working as expected.
Now, I want to plot (using MPAndroidChart) the data for each sensor in its own chart. In the activity_main layout, I added a ViewPager2 element, and Fragments are instantiated by the PagerAdapter::CreateFragment(int position) method.
My class model is as follow (based on a ViewPager2 example):
public class MainActivity extends AppCompatActivity
public class PagerAdapter extends FragmentStateAdapter
public class ChannelFragment extends Fragment
public class SensorViewModel extends ViewModel
I tested the visualisation of the plots in the Fragments using mock data (and a different colour background). The mock data was generated in ChannelFragment::onCreateView() method. This also works, though the mock data is the same for all fragments/charts, but different background colour for each fragment.
In a live test, I also proved to myself that I process changing the visible fragment correctly. I associate each fragment to a specific sensor and the streaming data changes as the visible fragment changes. This is done from MainActivity using ViewPager2.OnPageChangeCallback onPageSelected(position)
I am able to set the sensor data to the SensorViewModel and trigger a notification when calling postValue() from SensorViewModel.
The SensorViewModel contains the following declaration
private MutableLiveData<float[][]> sensorLiveData = new MutableLiveData<>();
and is created in MainActivity::onCreate(Bundle savedInstanceState)
// Create a ViewModel to hold the audio (sensor) data. This view model is used to communicate
// with the UI, graphically display the audio data for example
sensorViewModel = new ViewModelProvider(this).get(SensorViewModel.class);
The code for the observer is defined as a ChannelFragment method and listed as
#Override
public void onViewCreated(#NonNull View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
sensorViewModel = new ViewModelProvider(requireActivity()).get(SensorViewModel.class);
sensorViewModel.getSampleData().observe(requireActivity(), new Observer<float[][]>() {
#Override
public void onChanged(#Nullable float[][] sampleData)
{
// Update the sample data graphical representation
Log.d(TAG, String.format("ChannelFragment; onChanged() sampleData length : %d, size: %d",
sampleData.length, sampleData[0].length));
addEntry(sampleData);
}
});
And the log statement reports
ChannelFragment: ChannelFragment; onChanged() sampleData length : 8, size: 170
I am stuck as to update the correct chart (correct ChannelFragment) with its corresponding sensor data.
How to a plot sampleData[0][] in Fragment at position 0, sampleData1 in Fragment at position 1, and so forth?
Calls to ChannelFragment.getId() always returns 0, though I am able to access other attributes such as title when different fragments become visible.
I also modified the SensorVIewModel as suggested by Tiago Redaelli. The new declaration:
private HashMap<Integer, MutableLiveData<ArrayList<Float>>> sensorLiveData = new HashMap<>();
where the key identifies the sensor/fragment the MutableLiveData belongs to. However, the example does not explain how to set (inject?) the ViewModel (and MutableLiveData value) to the ChannelFragment. In the example, the method setViewModel() is implemented but call is not shown.
Using this new ViewModel definition, how do I associate each HashMap values with their corresponding Fragment (who is calling setViewModel() ? What I am missing?
Thanks in advance
Daniel
Just a quick update. I was trying to create a complicated solution to my issue, including looking at ViewModel factory for example.
In my solution, I simply call setViewModel() (mentioned above) using the position/index value passed as argument when creating an instance of ChannelFragment.
This appears to be working.

How to store all child fragment classes to the parent class' instance

I'm working on a "home feed"-like feature where there's a main Fragment with several other fragments added to its layout, making up the content page. I'd like the main fragment class to be able to instanstiate all the fragment classes that inherit from a certain parent fragment class. This way the code would be more dynamic instead of adding a bunch of <fragment> tags to my xml files.
I'm kinda stuck on making up a decent architecture. How would you go on about doing this?
UPDATE:
Here's what I'm basically trying to do, but don't know how:
public class FeedFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View parentView = inflater.inflate(R.layout.fragment_home, container, false);
// Get fragments and dynamically add them to
// the FeedFragment's layout
getEntryFragmentsList();
// ...
return parentView;
}
}
public abstract class FeedEntryFragment extends Fragment {
// Somehow add fragment to list of entry fragments
}
public class TestFragment extends FeedEntryFragment {
// Already added to list of entry fragments
}
I don't think that possible to decrease the count of xmls by inheritance. I think you should try to split your xml configurations and use some <merge> or <include> to build the full one from the parts.
May be I can provide more help if you will describe your problem in more details.
You should use FrameLayout to add fragment(s) dynamically by using the FragmentTransaction.
You can also use a ViewPager with tabs or bottom tabs to show multiple fragments. Please check sample from my Dynamic Support library for the complete code.
Abstract fragments
DynamicFragment - Abstract base fragment from the Dynamic support library.
DynamicViewPagerFragment - Abstract fragment which extends the DynamicFragment to implement the ViewPager functionality.
Implementation
HomeFragment - Sample fragment extends the DynamicFragment to implement the home screen.
SettingsFragment - Sample fragment extends the DynamicViewPagerFragment to implement the settings functionality using multiple fragments inside a view pager.
Tutorial Implementation
This better suits your need. TutorialActivity returns a list of fragments to be displayed inside a ViewPager.
DynamicSimpleTutorial generates a DynamicTutorialFragment according to the supplied parameters.

Android create a PreferenceFragment without a PreferenceActivity

I added a side menu to my Application and I managed to change the content with fragments. Now I am trying to do the Preferences, but I don't want to use a PreferenceActivity because I want to do my application with fragments because I don't want to do the NavigationDrawer twice (For my main activity displaying the fragments and for the PreferenceActivity).
I found the class PreferenceFragment but after alot of research I found out that appearantly it just is a part of the SettingsActivity and when I try to addPreferenceFromResouce in the PreferenceFragment and then launch the fragment, it crashes.
So basically I am trying to find a way to display a SettingsFragment without any extra activity just by calling fragmentManager.beginTransaction().replace(R.id.contentFrame, settingsFragment).commit() just as I do with my different fragments.
I hope I asked my question understandable (I am sorry if I didn't). Thanks for your time and your help.
I found the solution myself now. It wasn't very hard.
I simply created a normal PreferenceFragment and you can use it like any other fragment without a PreferenceActivity.
public class PreferenceFragment extends android.preference.PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}}
I then replaced it using
getFragmentManager().beginTransaction().replace(R.id.contentFrame, preferenceFragment).commit();
as you normally would.
This worked great for me. I hope it also does for you.

Android Espresso functional tests with fragments

I have three activities in my app
A login activity
A main activity
A detail activity
I want to use espresso to test a sequence of events: click the login button on the login activity, which opens the main activity, and then click a list item in main activity, which opens detail activity, and then click another button in the detail activity. I started by creating this simple test, to get a reference to the listview:
public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> {
public LoginActivityTest() {
super(LoginActivity.class);
}
#Override
public void setUp() throws Exception {
super.setUp();
getActivity();
}
public void testSequence() throws Exception {
// Login
onView(withId(R.id.button_log_in)).perform(click());
// Check if MainActivity is loaded
onView(withId(R.id.container)).check(matches(isDisplayed()));
// Check if Fragment is loaded
onView(withId(R.id.list)).check(matches(isDisplayed()));
}
}
On the mainActivity onCreate() method I load a fragment like this:
getFragmentManager().beginTransaction()
.add(R.id.container, mListFragment)
.commit();
The ListFragment fragment has a list (R.id.list), but still the test fails with a NoMatchingViewException:
android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: com.tests.android.development:id/list
What am I doing wrong?
A note from the documentation for onView:
Note: the view has to be part of the view hierarchy. This may not be
the case if it is rendered as part of an AdapterView (e.g. ListView).
If this is the case, use Espresso.onData to load the view first.
To use onData to load the view, you need to check for instances of whatever your adapter is in the ListView. In other words, if your listview uses a Cursor adapter, you can try this:
onData(allOf(is(instanceOf(Cursor.class)))).check(matches(isDisplayed()));
It is important to note that the above will only pass if your listview contains at least one item. It is a good idea to have one test where an item exists, and one test where an item does not.
For more information on how to check for data that does exist, see here.
For more information on how to check for data that does not exist in an adapter, see here.
In the current version (Espresso 2.2.2) this exception is always appended with a View Hierarchy: clause that lists all the views available to match. Stroll through that and check if you can find your list.
As an alternative: check out android-sdk\tools\uiautomatorviewer.bat (or .sh) which takes a snapshot from the current screen and hierarchy. Put a breakpoint on your list matching line and check with the viewer if the list is there. If you find the list, there may be a timing issue in the test. Maybe it didn't wait enough, check out more about IdlingResources.

ActionBar in PreferenceActivity

In my application I am using the new Action Bar Compatibility sample from Google (located at <sdk>/samples/android-<version>/ActionBarCompat) which works great. The only problem I have is applying this to my PreferenceActivity in order to get a screen like the settings in the Android Market (see picture).
To fill the ActionBar with icons, each Activity must extend the ActionBarActivity class. The problem is that my Activity already extends PreferenceActivity and in Java classes can not extend more than one class.
There must be a way to get the ActionBar together with a PreferenceScreen. I would be glad if anybody could provide a solution for this common issue.
P.S.: A solution like in How to add a button to PreferenceScreen does not fit because the ActionBar is actually the title bar and so this is more a Java than a layout thing.
Edit: My answer below is rather hacky and it seems like it is now outdated (for pre Android 3.0) Have a look at the other answers for less hacky and more current solutions ~pyko 2014-09-01
I managed to get it working - not sure if this is the nicest/cleanest solution, but it works.
Had to make the following changes:
Make a copy of ActionBarActivity and have the new class extend PreferenceActivity
public abstract class ActionBarPreferenceActivity extends PreferenceActivity {
// contents exactly the same as 'ActionBarActivity'
}
Modify onCreate() in ActionBarHelperBase.java slightly - make a special case for PreferenceActivity classes
#Override
public void onCreate(Bundle savedInstanceState) {
// If the activity is a PreferenceActivity, don't make the request
if (!(mActivity instanceof PreferenceActivity)) {
mActivity.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
}
Have your PreferenceActivity extend this class and add request for FEATURE_CUSTOM_TITLE before you call super.onCreate()
public class MyPreferenceActivity extends ActionBarPreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); // add this line
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
// etc etc
}
// etc etc
}
As far as I can tell, changes 2 and 3 are needed because for PreferenceActivity:
"As soon as you call super.onCreate(), the ViewGroup will be set up and so, you are not allowed to change the Window's parameters." (see Oliver's comment to the answer)
I guess the order of how components in PreferenceActivity activities are created is different to plain Activity activities .
If you want to try a PreferenceFragment implementation based on support-v4 Fragment:
https://github.com/kolavar/android-support-v4-preferencefragment
I´m using it by myself and it isnt much work turning PreferenceActivity into PreferenceFragment.
Can you just clone the code for ActionBarActivity, and change "extends Activity" to "extends PreferenceActivity"? Then extend your new class instead of ActionBarActivity.
From all the Google apps I've seen, though, it seems unusual to put buttons in the action bar of a PreferenceActivity. If you're not putting buttons on it, you could just use a values-v11 alternate style resource to show the holo theme, and set that style in the manifest for your PreferenceActivity.
I used in my application this actionbar
https://github.com/johannilsson/android-actionbar and it's work great with this thread How to add a button to PreferenceScreen
I'd like to thank to #pyko providing a great answer, but it has problem that it won't work well on HoneyComb and above. well you can have a hack way to get it around like #AndroidDev said;
But #pyko is gonna pollute the ActionBarHelperBase class, and #AndroidDev isn't very transparent.The best way is to create ActionBarActivityPreferences who extends from PreferenceActivity; and in onCreate method, change the order of calling parent method:
#Override
protected void onCreate(Bundle savedInstanceState) {
//IMPORTATNT: MAKE SURE actionBarHelper called before super;
//as super oncreate of prefenceactivity is actuallying setting the content view
mActionBarHelper.onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
}
why calls 'mActionBarHelper.onCreate(savedInstanceState);' before 'super.onCreate(savedInstanceState);' , that is because super (i.e. PreferenceActivity) is actually setting the content view in its onCreate method, which would cause crash ("requestFeature() must be called before adding content'). SO what you need do is to swap the order, make sure ' mActionBarHelper.onCreate(savedInstanceState);' is called before super.
In this way, we don't need to pollute the 'ActionBarHelperBase' yet we keep SettingActivity very clean because we encapsulate the tricky detail to 'ActionBarActivityPreferences' and bang!
You can easily add action bar in preference activity by the following changes:
In AndroidManifest.xml :
<activity
android:name=".activity.SettingsActivity"
android:theme="#style/SettingsTheme"
android:label="Settings"/>
In v21/styles.xml
<style name="SettingsTheme" parent="#android:style/Theme.Material.Light.DarkActionBar">
<item name="android:colorPrimary">#color/colorPrimary</item>
<item name="android:colorPrimaryDark">#color/colorPrimaryDark</item>
</style>
In v14/styles.xml for Back API support:
<style name="SettingsTheme" parent="#android:style/Theme.Holo.Light.DarkActionBar">
<item name="android:actionBarStyle">#style/ActionBar.V14.Movie.NoTitle</item>
</style>
Thanks, just an update, you need to add an if statement before the Custom Title line to support HoneyComb and above.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
You can get a ActionBarSherlock lib and let you code extends SherlockPreference;

Categories

Resources