Custom view returns NULL when initialized - java

I want to create a custom reusable view to show in a gridlayout.
I can't seem to get the view to initialize. It always returns null in my Activity
Can anyone help me understand what I am doing wrong? I feel like it is in my Tile constructor.
My Activity:
private void addTile() {
TileView tile = new TileView(this);
tile.setTextTitle("CALLS");
tile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tilePressed(v);
}
});
mGridLayout.addView(tile);
}
The GridLayout portion of the Activity's XML:
<GridLayout
android:id="#+id/glTileArea"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/COLOR_LIGHT_GREEN"
android:columnCount="2"
android:rowCount="2" >
</GridLayout>
My reusable view:
public class TileView extends View{
private View mView;
private Context mContext;
private TextView mTitle;
public TileView(Context context) {
super(context);
this.mContext = context;
}
public View TileView(){
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
mView = inflater.inflate(R.layout.sample_tile_view,null);
mTitle = (TextView) mView.findViewById(R.id.tvTitle);
return mView;
}
public void setTextTitle(String text){
mTitle.setText(text);
}
}
The XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/COLOR_BLUE"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="TITLE"
android:textAlignment="center"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#color/COLOR_WHITE"
android:textStyle="bold"/>
</LinearLayout>
Error that I get:
Attempt to invoke virtual method 'void
android.widget.TextView.setText(java.lang.CharSequence)' on a null
object reference at com.mycompany.myapp.Views.TileView.setTextTitle
(TileView.java:77)

Problem is due to:
tile.setTextTitle("CALLS");
line. mTitle is null because TileView() method is not called anywhere in which initializing TextView.
Either call TileView() before calling setTextTitle method:
tile.TileView();
tile.setTextTitle("CALLS");
or call TileView method in constructor :
public TileView(Context context) {
super(context);
this.mContext = context;
this.TileView(); //<< call here
}

Try to move the code in TileView() to TileView(Context context)
public TileView(Context context) {
super(context);
this.mContext = context;
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
mView = inflater.inflate(R.layout.sample_tile_view,null);
mTitle = (TextView) mView.findViewById(R.id.tvTitle);
}

Related

Android ViewPager from custom library Bug

I learning, how to create a android library and I create a simple onboarding Library. But I have a problem with my ViewPager from my custom module.
When I swipe in right and left, my seconds item is not display or first and second view is overlay.
I don't understand where the problem comes from
[![enter image description here][2]][2]
[![ ][3]][3]
Main class in my library:
public class OnBoardingView extends FrameLayout implements LifecycleObserver {
public OnBoardingView(#NonNull Context context) {
super(context, null);
this.initialize(context, null);
}
public OnBoardingView(#NonNull Context context, #NonNull AttributeSet attrs) {
super(context, attrs);
this.initialize(context, attrs);
}
private void initialize(#NonNull Context context, #Nullable AttributeSet attrs) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.onboarding_view_root, this);
List<String> list = new ArrayList<String>();
list.add("Hello world 1");
list.add("Hello world 2");
list.add("Hello world 3");
ViewPager viewPager = findViewById(R.id._screenPager);
OnBoardingAdapter<String> onBoardingAdapter = new OnBoardingAdapter<String>(context, list);
viewPager.setAdapter(onBoardingAdapter);
}
}
My adapter:
public class OnBoardingAdapter<T> extends PagerAdapter {
private Context context;
private List<T> onBoardingList;
public OnBoardingAdapter(Context context, List<T> list) {
this.context = context;
this.onBoardingList = list;
}
#Override
public int getCount() {
return this.onBoardingList.size();
}
#Override
public boolean isViewFromObject(#NonNull View view, #NonNull Object object) {
return view.getClass() == object.getClass();
}
#Override
public void destroyItem(#NonNull ViewGroup container, int position, #NonNull Object object) {
container.removeView((View) object);
}
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
View view = LayoutInflater.from(context).inflate(R.layout.onboarding_screen_view, null);
container.addView(view);
return view;
}
}
My XML file to content ViewPager :
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<androidx.viewpager.widget.ViewPager
android:id="#+id/_screenPager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
My Xml for each page:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="onboarding_screen_view" />
</LinearLayout>
And in main main_activity file I call this to display my module:
<com.domaine.onboarding.OnBoardingView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Try to return view instead of container
If you want to achieve this easily try to use viewpager2, you can use adapter that similar with recyclerview adapter
https://developer.android.com/training/animation/vp2-migration

VideoView not playing video or audio in RecyclerView

Hi I am trying to create a video journal fragment that has a recyclerview which contains a title, a mood, and a video in each list item. For some reason the videoview is not even showing up. The videofilePath is saving correctly and I've checked with println statements. I'm not getting any errors, but its just completely collapsed. The next list item starts before the video displays.
Here is my ViewHolder class
public class JournalViewHolder extends RecyclerView.ViewHolder{
private TextView title;
private TextView mood;
private VideoView mVideoView;
MediaController mMediaController;
Context mContext;
public JournalViewHolder(View view, Context context){
super(view);
mContext = context;
title = (TextView)view.findViewById(R.id.JournalTitle);
mood = (TextView)view.findViewById(R.id.JournalMood);
mVideoView = (VideoView)view.findViewById(R.id.JournalVideo);
mMediaController = new MediaController(context);
}
public void bind(JournalEntry journalEntry){
title.setText(journalEntry.getTitle());
mood.setText(journalEntry.getMood());
if(journalEntry.getVideoFileName() != null){
Uri uri = Uri.parse(journalEntry.getVideoFileName());
mVideoView.setVideoURI(uri);
mVideoView.requestFocus();
mVideoView.setMediaController(mMediaController);
mVideoView.setZOrderOnTop(true);
mVideoView.start();
}
}
}
Here is my adapter class
public class JournalRecyclerViewAdapter extends RecyclerView.Adapter<JournalViewHolder> {
private List mJournalEntries;
private Context mContext;
public JournalRecyclerViewAdapter(List<JournalEntry> entries, Context context){
mJournalEntries = entries;
mContext = context;
}
#Override
public JournalViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.journal_list_items, parent, false);
JournalViewHolder holder = new JournalViewHolder(view, mContext);
return holder;
}
#Override
public void onBindViewHolder(JournalViewHolder holder, int position) {
JournalEntry entry = mJournalEntries.get(position);
holder.bind(entry);
}
#Override
public int getItemCount() {
return mJournalEntries.size();
}
}
Here is my class that initiates the list of items and the recyclerview
public class JournalView extends FragmentLoggingLifeCycler {
private RecyclerView mRecyclerView;
DataAccess mDataAccess;
List<JournalEntry> mEntryList;
public static final String USERNAME_KEY = "username";
public static final String PASSWORD_KEY = "password";
String password;
String username;
User currentUser;
private Context mContext;
public JournalView() {
// Required empty public constructor
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mContext = activity.getApplicationContext();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_journal_view, container, false);
Bundle data = getArguments();
username = data.getString(USERNAME_KEY);
password = data.getString(PASSWORD_KEY);
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
mDataAccess = DataAccess.getDataAccess(container.getContext());
currentUser = mDataAccess.getLoginUser(username, password);
mEntryList = mDataAccess.getAllJournals();
//mDataAccess.mDatabase.delete(Scheme.Journal.NAME, null, null);
// mEntryList = trimList(mEntryList, currentUser.getUsername());
// for(int counter = 0; counter < mEntryList.size(); counter++){
// System.out.println(mEntryList.get(counter).getTitle());
// }
mRecyclerView = (RecyclerView)view.findViewById(R.id.JournalList);
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(new JournalRecyclerViewAdapter(mEntryList, mContext));
return view;
}
private static List<JournalEntry> trimList(List<JournalEntry> entries, String username){
List<JournalEntry> returnedList = new ArrayList<>();
for(int i = 0; i< returnedList.size(); i++){
System.out.println(entries.get(i).getUsername()+ ", " +username);
if(entries.get(i).getUsername().equals(username)){
returnedList.add(entries.get(i));
}
}
return returnedList;
}
}
and now here are my XML files.
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="#+id/JournalList">
List Item files
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_weight="2">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2"
android:text="#string/Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="#+id/JournalTitle"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2"
android:text="#string/Mood"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="#+id/JournalMood"/>
</LinearLayout>
<VideoView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="#+id/JournalVideo"
android:visibility="visible"/>
Check out this Sample Code for how to have videos playing inside RecyclerView
VideoInRecyclerViewExamples
I'm developing a library named OneItem that may help you.
https://github.com/tbrand/OneItem
In #selectItemAt(int position), start playing video with your arbitrary VideoView(such as MediaPlayer or ExoPlayer).
In #UnSelectItemAt(int position), stop playing video and release it.

setText in CustomPagerAdapter

This is my custom ViewPager adapter. I'm trying to set a title for each page to a TextView as a function of the position of the ViewPager. Why isn't this working?
public class CustomPagerAdapter extends PagerAdapter {
private int[] image_resources = {
android.R.color.transparent,
R.drawable.image1,
};
private String[] title_resources = {
"",
"Title #1",
};
private Context ctx;
private LayoutInflater layoutInflater;
public CustomPagerAdapter(Context ctx) {
this.ctx = ctx;
}
#Override
public int getCount() {
return image_resources.length;
}
#Override
public boolean isViewFromObject(View view, Object o) {
return (view == (RelativeLayout) o);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
layoutInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View item_view = layoutInflater.inflate(R.layout.pager_item, container, false);
ImageView imageview = (ImageView) item_view.findViewById(R.id.image_view);
imageview.setImageResource(image_resources[position]);
TextView title = (TextView) item_view.findViewById(R.id.title_view);
title.setText(title_resources[position]);
container.addView(item_view);
return item_view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((RelativeLayout) object);
}
}
I keep getting the following error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.app.feed.CustomPagerAdapter.instantiateItem(CustomPagerAdapter.java:114)
The error is definitely being thrown at the following line: title.setText(title_resources[position]);
Nevermind. I got it working by adding the TextView to the pager_item.xml as correctly hinted at by j2emanue. Previously, I had my TextView in the layout of the page within which the ViewPager was located, which was incorrect.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/image_view"
android:scaleType="centerCrop" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="#+id/title_view"
android:layout_centerHorizontal="true" />
</RelativeLayout>

Why imageButton in a ListView does not toggle untill scrolled?

I have a simple listView via a custom adapter. Each row in the list view is composed of a ImageButton and TextView.
The idea is to change the ImageButton when user taps on it and it does not work. However, ImageButton changes for the views that are scrolled and recycled. I mean, when user scrolls down the list and comes back to the top and tap on the ImageButton it works as expected for those rows that were scrolled and back again.
Can you guys help me out what i'm missing? I'm extremely new to Android and have been stuck around this for about a week now trying to fix this.
Here's the APK for the sample test app:
https://www.dropbox.com/s/pzlahtqkgj010m8/app-ListViewExample.apk?dl=0
Here are the relevant parts of my code:
avtivity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/listView"
/>
</RelativeLayout>
and to render the single row in the ListView the following xml is utilized:
single_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageButton"
android:src="#drawable/b"
android:layout_weight="2"
style="#style/ListView.first"
android:layout_gravity="center"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/textView"
android:layout_weight="10"
android:layout_gravity="center"
/>
</LinearLayout>
coming to the Java code,
MainActivity.java is
public class MainActivity extends AppCompatActivity {
String[] titles;
ListView list;
private listViewAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Resources res = getResources();
titles = res.getStringArray(R.array.titles);
list = (ListView) findViewById(R.id.listView);
adapter = new listViewAdapter(this, titles);
list.setAdapter(adapter);
}
}
and the custom adapter listViewAdapter.java look like this
class sListItem {
public ImageButton button;
public TextView text;
public boolean active;
}
public class listViewAdapter extends ArrayAdapter<String> {
private final String[] titles;
Context context;
private int size = 15;
public sListItem mp[] = new sListItem[size];
public listViewAdapter(Context context, String[] titles) {
super(context, R.layout.single_row, R.id.imageButton, titles);
this.context = context;
this.titles = titles;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.single_row, parent, false);
if(mp[position] == null)
mp[position] = new sListItem();
mp[position].button = (ImageButton) row.findViewById(R.id.imageButton);
mp[position].button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mp[position].active = !mp[position].active;
setIcon(position, mp[position].active);
}
});
mp[position].text = (TextView) row.findViewById(R.id.textView);
mp[position].text.setText(titles[position]);
setIcon(position, mp[position].active);
return row;
}
private void setIcon(int position, boolean active) {
Drawable drawable;
if(active){
drawable = getContext().getResources().getDrawable(R.drawable.a);
} else {
drawable = getContext().getResources().getDrawable(R.drawable.b);
}
mp[position].button.setImageDrawable(drawable);
}
}
EDIT: Added link to sample test app.
You should tell adapter to update by calling notifydatasetchanged in the click listener
mp[position].button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mp[position].active = !mp[position].active;
setIcon(position, mp[position].active);
notifydatasetchanged();
}
});

Custom onClickListner in custom widget - how?

I have a custom widget thats extends Linear layout.
It just block of text with litle.
Here is xml of widget:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:background="#drawable/actionbar_background"
android:layout_height="35dp"
android:paddingLeft="15dp"
android:gravity="center_vertical">
<TextView
android:id="#+id/title"
android:layout_height="35dp"
android:textColor="#color/white"
android:layout_width="match_parent"
android:textSize="18dp"
android:clickable="true"
android:gravity="center_vertical" />
</LinearLayout>
<TextView
android:id="#+id/ingreds"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="Some text"
android:paddingLeft="15dp" />
</LinearLayout>
If I creating onClickListener for that custom widget somewhere in Activity - it reacts only if I click on last TextView in that layout. But I need to set onClickListener for horizontal LinearLayout which contains "title" textView, or directly on title TextView.
Important: I want to set these listeners OUTSIDE the custom widget class.
I think that I need to override setOnclickListener method in my custom class or something like that, but I'm not sure how it can be done.
Here is the class of custom widget:
public class MyTextBlock extends LinearLayout {
private TextView title;
private TextView ingreds;
public MyTextBlock(Context context) {
this(context, null);
}
public MyTextBlock(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_text_block, this, true);
title = (TextView) findViewById(R.id.title);
ingreds = (TextView) findViewById(R.id.ingreds);
}
public void setText(String text) {
ingreds.setText(text);
}
public void setTitle(String titleText) {
title.setText(titleText);
}
}
Thanks for answering.
Just implement the OnClickListener to this view class and set textview.setOnClickLister(this);
now handle the click event under the onClick(View v) method.
MyTextBlock textviewCustom = ....
textviewCustom.setonclickListner(MainClass.this);
public class MyTextBlock extends LinearLayout {
private TextView title;
private TextView ingreds;
public MyTextBlock(Context context) {
this(context, null);
}
public MyTextBlock(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_text_block, this, true);
title = (TextView) findViewById(R.id.title);
ingreds = (TextView) findViewById(R.id.ingreds);
}
public void setonclickListner(OnclickListner listner)
{
title.setonclicklistner(listner);
ingreds.setonclicklistner(listner);
}
public void setText(String text) {
ingreds.setText(text);
}
public void setTitle(String titleText) {
title.setText(titleText);
}
}

Categories

Resources