I have a recycler view in my activity. I implement an Interface in this activity that has to show keyboard when the user, touching a specific item in recycler view and send item position item that user touched into Activity.
This is my Interface:
public interface ReplyAction {
void onEvent(Context context , int courseId);
}
This is my interface method that i called in acivity:
#Override
public void onEvent(final Context mContext, int courseId) {
replyTo = courseId;
etMessage = (EditText) ((Activity) mContext).findViewById(R.id.etMessage);
etMessage.setFocusable(true);
//Show Keyboard to user
InputMethodManager imm = (InputMethodManager) getSystemService(mContext.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
but I will get this error:
FATAL EXCEPTION: main
Process: codenevisha.com.apps.learningmanagementsystem, PID: 7098
java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.Activity.getSystemService(Activity.java:5774)
at codenevisha.com.apps.learningmanagementsystem.activity.ActivityCourseChat.onEvent(ActivityCourseChat.java:547)
at codenevisha.com.apps.learningmanagementsystem.adapter.chatAdapter$1.onClick(chatAdapter.java:240)
This is Where I call OnEvent Method that is in my recycler view adapter:
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
String question;
String answer;
switch (holder.getItemViewType()) {
case 1: //For item message text left
question = chatArray.get(position).getCourseForumModel().getCourseForumQuestion();
answer = chatArray.get(position).getCourseForumModel().getCourseForumAnswer();
ViewHolderLeftText vLText = (ViewHolderLeftText) holder;
vLText.txtQuestion.setText(question);
if (!answer.equals("")) {
if (chatArray.get(position).getCourseForumModel().getCourseForumAUser().equals(G.userId)) {
//This Answer is prepared by this user
vLText.answerLayout.setBackgroundColor(mContext.getResources().getColor(R.color.my_message_background_color));
}
vLText.txtAnswer.setText(answer);
//Handling reply message to this message
vLText.imgReplay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ActivityCourseChat a = new ActivityCourseChat();
a.onEvent(mContext , chatArray.get(position).getCourseForumModel().getCourseForumId());
}
});
}
break;
case 2: //For item message image left
ViewHolderLeftImage vLImage = (ViewHolderLeftImage) holder;
//Handling reply message to this message
vLImage.imgReply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ActivityCourseChat a = new ActivityCourseChat();
a.onEvent(mContext ,chatArray.get(position).getCourseForumModel().getCourseForumId());
}
});
break;
}
ActivityCourseChat a = new ActivityCourseChat();
NEVER create an instance of an activity yourself. Delete both occurrences of this line. Then, get your ActivityCourseChat instance some other way. For example, if this RecyclerView.Adapter is being used by ActivityCourseChat, pass in the ActivityCourseChat instance via a constructor parameter.
Related
I have an Recycler.Adapter and my onBindViewHolder is like this:
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final String url = urls.get(position);
final width_height wh = whs.get(position);
holder.imageView.setClickable(true);
Picasso.with(context)
.load(url).resize(wh.width, wh.height).centerCrop()
.into(holder.imageView);
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialogFragment.show(fragmentManager, "");
dialogFragment.setImage(url);
dialogFragment.setRating(0);
}
});
holder.textView.setText(position + "");
holder.textView.setClickable(true);
holder.textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialogFragment.show(fragmentManager, "");
dialogFragment.setImage(url);
dialogFragment.setRating(0);
}
});
}
The dialogFragment is already instantiated in the contructor of Adapter. However, its onCreateView has not been called yet when the holder is clicked. And the setImage and setRating need to modify its imageView and RatingBar, which are null unless the onCreateView of the fragment is called. Is there a way to resolve this?
That's because DialogFragment.show commits asynchronously. In your case you'd want it to use DialogFragment.showNow instead so it commits synchronously.
#Override
public void onClick(View v) {
dialogFragment.showNow(fragmentManager, "");
dialogFragment.setImage(url);
dialogFragment.setRating(0);
}
Otherwise I'd suggest to create new DialogFragment every time the button is clicked, and pass image url and rating as arguments before it is shown.
A more correct way would be to have the setImage method and setRating method check for null. If null, they should save the value to variable, and onCreate should use those values to set.
For example (not tested);
void setImage(src) {
if (mImage == null)
mImageSource = src;
else
mImage.setImage(src);
}
void onCreateView(...) {
...
if (mImageSource != null)
mImage.setImage(mImageSource);
mImageSource = null;
}
This way you can correctly use the asynchronous dialog calls.
In the MainActivity I have both a ContextMenu that responds to Long clicks and a regular OnItemClickListener that responds to regular clicks.
On the TaskActivity which is practically similar to the MainActivity, I also have a ContextMenu that responds to Long clicks, however when trying to set an OnItemClickListener, the items in the list view don't respond (they do respond to long clicks).
What am I missing? I tried various methods like changing clickable status to false and so on - none of them work. And that makes sense because I don't have them on the MainActivity XML's but it does work there.
MainActivity code:
public class MainActivity extends AppCompatActivity {
final Context context = this;
public static final int SIGN_IN = 1;
public static String currentTaskListId;
public static String currentUserId;
private TaskListAdapter mTaskListAdapter;
//TextView that is displayed when the list is empty//
private TextView mEmptyStateTextView;
//The loading indicator //
private View loadingIndicator;
// Firebase instance variables
private FirebaseAuth mFirebaseAuth;
private FirebaseAuth.AuthStateListener mAuthStateListener;
private FirebaseDatabase mFirebaseDatabase;
private DatabaseReference mTaskListDatabaseReference;
private ChildEventListener mChildEventListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the content of the activity to use the activity_main.xml layout file - the task lists
setContentView(R.layout.activity_main);
// Initialize Firebase components
mFirebaseAuth = FirebaseAuth.getInstance();
mFirebaseDatabase = FirebaseDatabase.getInstance();
//Initialize firebase authentication
mAuthStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// user is signed in
currentUserId=user.getUid();
onSignedInInitialize(user.getUid());
} else {
// user is signed out
onSignedOutCleanup();
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setIsSmartLockEnabled(false)
.setAvailableProviders(Arrays.asList(
new AuthUI.IdpConfig.EmailBuilder().build(),
new AuthUI.IdpConfig.GoogleBuilder().build()))
.setTosAndPrivacyPolicyUrls("https://superapp.example.com/terms-of-service.html",
"https://superapp.example.com/privacy-policy.html")
.build(),
SIGN_IN);
}
}
};
//Initialize task list Array, ListView and Adapter.
final ArrayList<TaskList> taskLists = new ArrayList<TaskList>();
// Create an {#link TaskListAdapter}, whose data source is a list of {#link TaskList}s.
mTaskListAdapter = new TaskListAdapter(this, taskLists);
// Locate the {#link ListView} object in the view hierarchy of the {#link Activity}.
ListView listView = (ListView) findViewById(R.id.task_list_view);
//Set the empty view
mEmptyStateTextView = (TextView) findViewById(R.id.empty_view);
listView.setEmptyView(mEmptyStateTextView);
//Initialize the loading indicator
loadingIndicator = findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.INVISIBLE);
// Make the {#link ListView} use the {#link TaskListAdapter} defined above, so that the
// {#link ListView} will display list items for each {#link TaskList} in the list.
listView.setAdapter(mTaskListAdapter);
//Set and create the FAB and it's action listener
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Get add_list.xml view
LayoutInflater li = LayoutInflater.from(context);
View addTaskListView = li.inflate(R.layout.add_list, null);
//Create the prompt to enable the user to create a new task list
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
context);
// Set add_list.xml as the layout for alertdialog builder
alertDialogBuilder.setView(addTaskListView);
//Set the user input box
final EditText userInput = (EditText) addTaskListView
.findViewById(R.id.edit_list_name);
// Set dialog message
alertDialogBuilder
.setCancelable(false)
.setPositiveButton("Create",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
// Get list title from user and create a new task list
//Also fetch the FireBase ID and connect it to the new task list.
String mTaskListId = mTaskListDatabaseReference.push().getKey();
TaskList taskList = new TaskList(userInput.getText().toString(),mTaskListId);
mTaskListDatabaseReference.child(mTaskListId).setValue(taskList);
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
dialog.cancel();
}
});
// Create the dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// Show the dialog
alertDialog.show();
}
});
// Set an item click listener on the ListView, which creates an intent to open
//the relevant task list and show the tasks inside.
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
// Find the current task list that was clicked on
TaskList currentTaskList = mTaskListAdapter.getItem(position);
//get the current task list's ID
currentTaskListId=currentTaskList.getId();
// Create a new intent to view the tasks in the chosen list
Intent taskIntent = new Intent(MainActivity.this, TaskActivity.class);
// Send the intent to launch a new activity
startActivity(taskIntent);
}
});
listView.setLongClickable(true);
registerForContextMenu(listView);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SIGN_IN) {
if (resultCode == RESULT_OK) {
// Sign-in succeeded, set up the UI
Toast.makeText(this, "Signed in!", Toast.LENGTH_SHORT).show();
} else if (resultCode == RESULT_CANCELED) {
// Sign in was canceled by the user, finish the activity
Toast.makeText(this, "Sign in canceled", Toast.LENGTH_SHORT).show();
finish();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mini_menu,menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.sign_out:
AuthUI.getInstance().signOut(this);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
protected void onResume() {
super.onResume();
mFirebaseAuth.addAuthStateListener(mAuthStateListener);
}
#Override
protected void onPause() {
super.onPause();
if (mAuthStateListener != null) {
mFirebaseAuth.removeAuthStateListener(mAuthStateListener);
}
mTaskListAdapter.clear();
detachDatabaseReadListener();
}
private void onSignedInInitialize(final String userId) {
//Get reference for the task list for the logged in user and attach the database listener
mTaskListDatabaseReference=mFirebaseDatabase.getReference().child("users").child(userId);
loadingIndicator.setVisibility(View.VISIBLE);
attachDatabaseReadListener();
mEmptyStateTextView.setText("No task lists, add a new one!");
loadingIndicator.setVisibility(View.GONE);
}
private void onSignedOutCleanup() {
mTaskListAdapter.clear();
detachDatabaseReadListener();
}
private void attachDatabaseReadListener() {
if (mChildEventListener == null) {
mChildEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
TaskList taskList = dataSnapshot.getValue(TaskList.class);
mTaskListAdapter.add(taskList);
}
public void onChildChanged(DataSnapshot dataSnapshot, String s) {}
public void onChildRemoved(DataSnapshot dataSnapshot) {}
public void onChildMoved(DataSnapshot dataSnapshot, String s) {}
public void onCancelled(DatabaseError databaseError) {}
};
}
mTaskListDatabaseReference.addChildEventListener(mChildEventListener);
}
private void detachDatabaseReadListener() {
if (mChildEventListener != null) {
mTaskListDatabaseReference.removeEventListener(mChildEventListener);
mChildEventListener = null;
}
}
public static String getCurrentTaskListId() {
return currentTaskListId;
}
public static String getCurrentUserId() {
return currentUserId;
}
/**
* MENU
*/
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo){
if (v.getId() == R.id.task_list_view){
AdapterView.AdapterContextMenuInfo info =(AdapterView.AdapterContextMenuInfo)menuInfo;
menu.add(0,0,0,"Delete");
}
}
#Override
public boolean onContextItemSelected(MenuItem menuItem){
AdapterView.AdapterContextMenuInfo info=(AdapterView.AdapterContextMenuInfo)menuItem.getMenuInfo();
TaskList taskListClicked=mTaskListAdapter.getItem(info.position);
Log.d("check","" +taskListClicked.getTitle());
switch (menuItem.getItemId()) {
case 0:
mTaskListDatabaseReference.child(taskListClicked.getId()).removeValue();
mTaskListAdapter.remove(taskListClicked);
Toast.makeText(this, "Task List deleted!", Toast.LENGTH_LONG).show();
break;
default:
break;
}
return true;
}
}
TaskActivity code:
public class TaskActivity extends AppCompatActivity {
final Context context = this;
private TaskAdapter mTaskAdapter;
private int taskCount;
// TextView that is displayed when the list is empty //
private TextView mEmptyStateTextView;
//The loading indicator //
private View loadingIndicator;
//Edit text and button for creating new tasks quickly
private EditText mTaskEditText;
private Button mTaskCreateButton;
// Firebase instance variables
private FirebaseDatabase mFirebaseDatabase;
private DatabaseReference mTaskDatabaseReference;
private DatabaseReference mTaskNumDatabaseReference;
private ChildEventListener mChildEventListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the content of the activity to use the activity_main.xml layout file - the task lists
setContentView(R.layout.task_activity);
//Set up to allow Up navigation to parent activity
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Initialize Firebase components
mFirebaseDatabase = FirebaseDatabase.getInstance();
// Initialize references to views
mTaskEditText = (EditText) findViewById(R.id.task_edit_text);
mTaskCreateButton = (Button) findViewById(R.id.create_task_button);
// Enable Send button when there's text to send
mTaskEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().trim().length() > 0) {
mTaskCreateButton.setEnabled(true);
} else {
mTaskCreateButton.setEnabled(false);
}
}
#Override
public void afterTextChanged(Editable editable) {
}
});
// Create button creates a new task and clears the EditText
mTaskCreateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Get task title from user and create a new task
//Also fetch the FireBase ID and connect it to the new task.
//And finally get the task's creation date
String creationDate ="Created: " + new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
String taskId = mTaskDatabaseReference.push().getKey();
Task task = new Task(mTaskEditText.getText().toString(),false,taskId,creationDate);
mTaskDatabaseReference.child(taskId).setValue(task);
//add that task to the list's task count
mTaskNumDatabaseReference.child("taskNum").setValue(taskCount+1);
// Clear input box
mTaskEditText.setText("");
}
});
//Initialize task Array, ListView and Adapter.
final ArrayList<Task> tasks = new ArrayList<Task>();
// Create an {#link TaskAdapter}, whose data source is a list of {#link Task}s.
mTaskAdapter = new TaskAdapter(this, tasks);
// Locate the {#link ListView} object in the view hierarchy of the {#link Activity}.
ListView listView = (ListView) findViewById(R.id.task_list_view);
//Set the empty view
mEmptyStateTextView = (TextView) findViewById(R.id.empty_view);
listView.setEmptyView(mEmptyStateTextView);
//Initialize the loading indicator
loadingIndicator = findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.INVISIBLE);
// Make the {#link ListView} use the {#link TaskAdapter} defined above, so that the
// {#link ListView} will display list items for each {#link Task} in the list.
listView.setAdapter(mTaskAdapter);
//Set a regular click - opening the TaskInfoFragment
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
// Find the current task list that was clicked on
Log.d("clicked here bro","clicikcckckc");
Task currentTask = mTaskAdapter.getItem(position);
//Open the TaskInfoFragment for this task
TaskInfoFragment taskInfo = new TaskInfoFragment();
taskInfo.setCurrentTask(currentTask);
android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.frag_container, taskInfo);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
});
//Set context menu for ListView
listView.setLongClickable(true);
registerForContextMenu(listView);
//Get reference for the task list for the logged in user and attach the database listener
mTaskDatabaseReference=mFirebaseDatabase.getReference().child("users")
.child(MainActivity.getCurrentUserId())
.child(MainActivity.getCurrentTaskListId()).child("tasks");
mTaskNumDatabaseReference=mFirebaseDatabase.getReference().child("users")
.child(MainActivity.getCurrentUserId())
.child(MainActivity.getCurrentTaskListId());
//add listener to get the current task count in this specific task list
mTaskNumDatabaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
TaskList taskList = dataSnapshot.getValue(TaskList.class);
taskCount=taskList.getTaskNum();
Log.d("post count: ", "" + taskCount);
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
}
});
}
#Override
protected void onResume() {
super.onResume();
loadingIndicator.setVisibility(View.VISIBLE);
attachDatabaseReadListener();
mEmptyStateTextView.setText("No tasks, add a new one!");
loadingIndicator.setVisibility(View.GONE);
}
#Override
protected void onPause() {
super.onPause();
mTaskAdapter.clear();
detachDatabaseReadListener();
}
private void attachDatabaseReadListener() {
if (mChildEventListener == null) {
mChildEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Task task = dataSnapshot.getValue(Task.class);
mTaskAdapter.add(task);
}
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
//Task task = dataSnapshot.getValue(Task.class);
//mTaskAdapter.add(task);
}
public void onChildRemoved(DataSnapshot dataSnapshot) {
mTaskNumDatabaseReference.child("taskNum").setValue(taskCount-1);
}
public void onChildMoved(DataSnapshot dataSnapshot, String s) {}
public void onCancelled(DatabaseError databaseError) {}
};
}
mTaskDatabaseReference.addChildEventListener(mChildEventListener);
}
private void detachDatabaseReadListener() {
if (mChildEventListener != null) {
mTaskDatabaseReference.removeEventListener(mChildEventListener);
mChildEventListener = null;
}
}
/**
* MENU
*/
#Override
public void onCreateContextMenu(ContextMenu menu,View v, ContextMenu.ContextMenuInfo menuInfo){
if (v.getId() == R.id.task_list_view){
AdapterView.AdapterContextMenuInfo info =(AdapterView.AdapterContextMenuInfo)menuInfo;
menu.add(0,0,0,"Delete");
menu.add(0,1,1,"info");
}
}
#Override
public boolean onContextItemSelected(MenuItem menuItem){
AdapterView.AdapterContextMenuInfo info=(AdapterView.AdapterContextMenuInfo)menuItem.getMenuInfo();
Task taskClicked=mTaskAdapter.getItem(info.position);
Log.d("check","" +taskClicked.getTitle());
switch (menuItem.getItemId()) {
case 0:
mTaskDatabaseReference.child(taskClicked.getId()).removeValue();
mTaskAdapter.remove(taskClicked);
Toast.makeText(this, "Task deleted!", Toast.LENGTH_LONG).show();
break;
case 1:
//Open the TaskInfoFragment for this task
TaskInfoFragment taskInfo = new TaskInfoFragment();
taskInfo.setCurrentTask(taskClicked);
android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.frag_container, taskInfo);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
break;
default:
break;
}
return true;
}
//set up the back button - to navigate to the parent activity
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
//Check if the call came from the TaskInfoFragment or the activity
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.frag_container);
if(currentFragment!=null && currentFragment.isVisible()){
this.onBackPressed();
}
else{
NavUtils.navigateUpFromSameTask(this);
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
TaskAdapter - the TaskActivity Adapter
package com.example.guyerez.todotiger;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import java.util.ArrayList;
import java.util.Locale;
/**
* {#link TaskAdapter} is an {#link ArrayAdapter} that can provide the layout for each task item
* based on a data source, which is a list of {#link Task} objects.
*/
public class TaskAdapter extends ArrayAdapter<Task> {
//Define FireBase instance variables
private DatabaseReference mTaskDatabaseReference;
private FirebaseDatabase mFirebaseDatabase;
/**
* Create a new {#link TaskAdapter} object.
*
* #param context is the current context (i.e. Activity) that the adapter is being created in.
* #param tasks is the list of {#link Task}s to be displayed.
*/
public TaskAdapter(Context context, ArrayList<Task> tasks) {
super(context, 0, tasks);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Check if an existing view is being reused, otherwise inflate the view
View listItemView = convertView;
if (listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.task_item, parent, false);
}
// Get the {#link Task} object located at this position in the list
final Task currentTask = getItem(position);
// Locate the TextView in the task_item.xml layout with the ID task_title.
final TextView titleTextView = (TextView) listItemView.findViewById(R.id.task_title);
// Get the task's title from the currentTask object and set it in the text view
titleTextView.setText(currentTask.getTitle());
//If the task is completed - title Strikethrough
titleTextView.setBackgroundResource(strikeCompleted(currentTask.getCompleted()));
//Initialize the check box and check it if the task was completed.
CheckBox checkBox = (CheckBox) listItemView.findViewById(R.id.check_box);
checkBox.setOnCheckedChangeListener(null);
checkBox.setChecked(currentTask.getCompleted());
//Initialize the creation date TextView in the task_item.xml layout with the ID creation_date
TextView creationDateTextView = (TextView) listItemView.findViewById(R.id.creation_date);
//Get the task's creation date from the currentTask object and set it in the text view
creationDateTextView.setText(currentTask.getCreationDate());
// Initialize Firebase DB
mFirebaseDatabase = FirebaseDatabase.getInstance();
//Get the task DB reference to edit task completion status
// Find the CheckBox in the task_item.xml layout with the ID check_box.
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
mTaskDatabaseReference=mFirebaseDatabase.getReference()
.child("users").child(MainActivity.getCurrentUserId())
.child(MainActivity.getCurrentTaskListId()).child("tasks").child(currentTask.getId());
if (isChecked) {
titleTextView.setBackgroundResource(R.drawable.strike_through);
mTaskDatabaseReference.child("completed").setValue(true);
} else {
titleTextView.setBackgroundResource(0);
mTaskDatabaseReference.child("completed").setValue(false);
}
}
}
);
// Return the whole list item layout (containing 1 text view and 1 checkbox) so that it can be shown in the ListView.
return listItemView;
}
private int strikeCompleted(boolean completed){
if (completed){
return R.drawable.strike_through;
}
else{
return 0;
}
}
}
After trying the several recommended workarounds (like here) for ListView rows containing a CheckBox without any success, I'd like to suggest a different approach:
Use another, transparent View which covers the whole row except for a small area around the CheckBox. Let this View have an OnClickListener which triggers the opening of the TaskInfoFragment.
Ideally one would use an interface so the TaskAdapter could pass the clicked Task to the TaskActivity which in turn would show the Fragment.
Several hours later... (#Guy, your hint that you "tried deleting all checkbox related code and xml, and the regular click problem persisted" made me exchange one component after another until I had it narrowed down to the row xml) I found the reason why the ListView's OnItemClickListener in TaskActivity does not fire. The root ConstraintLayout of the Task list has an attribute which the root of the TaskList list does not have: android:longClickable="true"
Removing this attribute makes the ListView behave normally.
I have an AppCompatActivity that, at some point, display a DialogFragment. In this dialog, there are items for which I ask confirmation before deleting them. That confirmation is asked through another Yes/No DialogFragment. When the user clicks Yes in that second dialog, I want the first dialog to refresh its ListView (just need to update the adapter and call its notifyDataSetChanged method). The problem is that I don't know when to update the listview.
Because that delete functionality is called from various sources, I implement a listener Interface at the activity level and call an "onDeleteRequest" event from that interface whenever I need an item to be deleted, and that's the activity who opens up the confirmation dialog and perform the actual delete.
Since I don't care much about refreshing the ListView in unnecessary situations, I tried to update the list in the onResume event, but the event is not called when I come back to the first dialog after the confirmation one is dismissed.
So my question is: how can I know when a dialog B displayed on top of a dialog A has been dismissed so I can refresh dialog A accordingly?
EDIT : A bit of code to support my question:
My activity class:
public class MonthActivity
extends AppCompatActivity
implements OnEditCalendarsDialogListener
{
...
//That's where dialog A is shown
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
...
if (id == R.id.action_select_calendar) {
final CalendarSelection currentSelection = mCalendarSelectionAdapter.getCurrentCalendarSelection();
if (currentSelection != null) {
EditCalendarsDialogFragment dialogFragment = EditCalendarsDialogFragment.newInstance(currentSelection);
dialogFragment.show(getSupportFragmentManager());
}
return true;
}
return super.onOptionsItemSelected(item);
}
...
//OnEditCalendarsDialogListener interface implementation
//That's where Dialog B is shown over Dialog A
#Override
public void onEditCalendarsDialogDelete(long calendarID) {
final Repository repository = Repository.getInstance(this);
final Calendar calendar = repository.fetchOneByID(Calendar.class, calendarID);
if (calendar != null) {
YesNoDialog yesNoDialog = YesNoDialog.newInstance(this, R.string.yes_no_dialog_confirmation, R.string.yes_no_dialog_calendar_delete);
setCurrentOnDecisionClickListener(new OnPositiveClickListener() {
#Override
public boolean onPositiveClick(DialogInterface dialog) {
//Delete calendar
repository.delete(calendar);
//That's where I'd like to notify Dialog A that it needs to be refreshed
return true;
}
});
yesNoDialog.show(getSupportFragmentManager());
}
}
}
My dialog class
public class EditCalendarsDialogFragment
extends DialogFragment
{
private OnEditCalendarsDialogListener mDialogListener;
public static EditCalendarsDialogFragment newInstance(CalendarSelection calendarSelection) {
EditCalendarsDialogFragment dialog = new EditCalendarsDialogFragment();
Bundle arguments = new Bundle();
if (calendarSelection != null) {
arguments.putLong(KEY_ID, calendarSelection.getID());
}
else {
arguments.putLong(KEY_ID, 0L);
}
dialog.setArguments(arguments);
return dialog;
}
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mDialogListener = (OnEditCalendarsDialogListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnCalendarSelectionDialogListener");
}
}
...
private View getLayoutView() {
View rootView = getActivity().getLayoutInflater().inflate(R.layout.calendar_list, null, false);
if (rootView != null) {
mCalendars = (ListView) rootView.findViewById(R.id.calendars);
if (mCalendars != null) {
//Create adaptor
mCalendarAdapter = new ArrayAdapter<Calendar>(
getContext(),
android.R.layout.simple_list_item_2,
android.R.id.text1,
new ArrayList<Calendar>()
) {
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View view = super.getView(position, convertView, parent);
final Calendar calendar = getItem(position);
if (calendar != null && calendar.hasID()) {
...
view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mDialogListener != null) {
//That's where I request delete from calling activity
mDialogListener.onEditCalendarsDialogDelete(calendar.getID());
}
return true;
}
});
}
return view;
}
};
mCalendars.setAdapter(mCalendarAdapter);
refreshCalendarList();
}
}
return rootView;
}
}
Use EventBus.
Register your dialog A to listen to events. When you dismiss dialog B post an event and pass the listitem's adapter position or whatever data you want to use to identify which item is to be deleted. Inside your dialog A write a function to receive this event inside which you delete the item.
OK, so I finally used the "over-abusive-callback" method.
I created the following interface:
public interface OnDeletedListener {
void onDeleted();
}
Updated the OnEditCalendarsDialogListener interface so that the callback has a callback to this interface too:
public interface OnEditCalendarsDialogListener {
void onEditCalendarsDialogDelete(long calendarID, OnDeletedListener onDeletedListener);
}
Implemented the OnDeletedListener interface in "Dialog A" class:
public class EditCalendarsDialogFragment
extends DialogFragment
implements OnDeletedListener
{
...
//OnDeletedListener interface implementation
#Override
public void onDeleted() {
//That's where I'm called back after item is deleted
refreshCalendarList();
}
...
private View getLayoutView() {
...
view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mDialogListener != null) {
//That's where I request delete from calling activity, asking to call me back once deleted
mDialogListener.onEditCalendarsDialogDelete(calendar.getID(), EditCalendarsDialogFragment.this);
}
return true;
}
});
...
}
}
And finally, call the callback when delete is accepted and performed:
public class MonthActivity
extends AppCompatActivity
implements OnEditCalendarsDialogListener
{
//OnEditCalendarsDialogListener interface implementation
//That's where Dialog B is shown over Dialog A
#Override
public void onEditCalendarsDialogDelete(long calendarID, final OnDeletedListener onDeletedListener) {
final Repository repository = Repository.getInstance(this);
final Calendar calendar = repository.fetchOneByID(Calendar.class, calendarID);
if (calendar != null) {
YesNoDialog yesNoDialog = YesNoDialog.newInstance(this, R.string.yes_no_dialog_confirmation, R.string.yes_no_dialog_calendar_delete);
setCurrentOnDecisionClickListener(new OnPositiveClickListener() {
#Override
public boolean onPositiveClick(DialogInterface dialog) {
//Delete calendar
repository.delete(calendar);
//That's where I notify Dialog A that it needs to be refreshed
if (onDeletedListener != null) {
onDeletedListener.onDeleted();
}
return true;
}
});
yesNoDialog.show(getSupportFragmentManager());
}
}
}
Works smoothly!
Here there is minor issue Like I had Recyclerview in dialog fragment.ie name of bank in recyclerview When we select one bank in recyclerview and after dialogfragment dismiss that name should be appear on Button ie when we selected Union Bank from dialog fragment it should appear on button.Issue is when we click on button then its text changes rather then on time of dismiss listener
here is Dialog dismissal code:
mRecyclerView.addOnItemTouchListener(new RecyclerTouchListener(getContext(), mRecyclerView, new ClickListener() {
#Override
public void onClick(View view, final int position) {
Employee e = bank.get(position);
Toast.makeText(getContext(), e.getBank_id() + "" + e.getBank_name(), Toast.LENGTH_SHORT).show();
getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialogInterface) {
Employee e = bank.get(position);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor edit = sp.edit();
edit.putString("bankname", e.getBank_name());
edit.commit();
}
});
c.onItemSelect(e.getBank_name());
onDismiss(getDialog());
}
Here is onclick event where dialog opens and where the value should be printed:
select_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentManager fm=getFragmentManager();
DialogRecyclerview dr = new DialogRecyclerview(AccountManagement_banks.this,callback);
dr.setRetainInstance(true);
dr.show(getSupportFragmentManager(), "Dialog");
SharedPreferences st = PreferenceManager.getDefaultSharedPreferences(AccountManagement_banks.this);
String mode=st.getString("bankname","");
select_button.setText(mode);
Toast.makeText(getApplication(),mode,Toast.LENGTH_SHORT).show();
}
});
Same in:
#Override
public void onItemSelect(String text) {
select_button.setText(text);
}
Here I had created new Interface:
public interface CallBack {
void onItemSelect(String text);}
just create a callback and implement it on your main class (where you want to display the name) and pass the callback instance to adapter. Now dialog fragment, now when you are selecting any item just call callback function which is overridden in main calss and inside this function just change the text of your button.
public interface CallBack {
void onItemSelect(String text);
}
implement this in your main class like
public class MainActivity extends Activity implements CallBack {
.
.
.
public void onItemSelect(String text){
button.setText(text);
}
.
.
}
when you are opening your dialogfragment from your main activity just pass MainActivity.this as an argument in the dialog constructor. And in your Dialog class constructor write your code like this
private Callback callback;
public YourDialog(Context context, Callback callback){
this.callback = callback;
}
and when you selecting list item just call
callback.onItemSelect(e.getBank_name());
Hope it will help you out.
Each item on my RecyclerView has a button that has three states: OPEN, LOADING, and CLOSED.
Initially all the buttons are in the OPEN state. When a button is clicked, the state is changed to LOADING and a network call is performed in the background. After the network call succeeds, the button state should be changed to CLOSED.
So in my adapter I used the following:
holder.button.setOnClickListener(v -> {
holder.state = LOADING;
notifyItemChanged(holder.getAdapterPosition()); /* 1 */
callNetwork(..., () -> {
/* this is the callback that runs on the main thread */
holder.state = CLOSED;
notifyItemChanged(holder.getAdapterPosition()); /* 2 */
});
});
The LOADING state is always visualized correctly at /* 1 */ because getAdapterPosition() gives me the correct position.
However, the CLOSED state of the button is never visualized, because getAdapterPosition at /* 2 */ always returns -1.
I might understand getAdapterPosition() wrongly in this case.
How do I refresh the appearance of an item on a callback?
From the docs:
Note that if you've called notifyDataSetChanged(), until the next
layout pass, the return value of this method will be NO_POSITION
NO_POSITION is a constant whose value is -1. This might explain why you are getting a return value of -1 here.
In any case, why don't you find the position of the model in the underlying dataset and then call notifyItemChanged(int position)? You could save the model as a field in the holder.
For example:
public class MyHolder extends RecyclerView.ViewHolder {
private Model mMyModel;
public MyHolder(Model myModel) {
mMyModel = myModel;
}
public Model getMyModel() {
return mMyModel;
}
}
holder.button.setOnClickListener(v -> {
holder.state = LOADING;
notifyItemChanged(holder.getAdapterPosition());
callNetwork(..., () -> {
/* this is the callback that runs on the main thread */
holder.state = CLOSED;
int position = myList.indexOf(holder.getMyModel());
notifyItemChanged(position);
});
});
Alternatively you can just ignore if the position is -1, like this:
holder.button.setOnClickListener(v -> {
holder.state = LOADING;
int preNetworkCallPosition = holder.getAdapterPosition();
if (preNetworkCallPosition != RecyclerView.NO_POSITION) {
notifyItemChanged(preNetworkCallPosition);
}
callNetwork(..., () -> {
/* this is the callback that runs on the main thread */
holder.state = CLOSED;
int postNetworkCallPosition = holder.getAdapterPosition();
if (postNetworkCallPosition != RecyclerView.NO_POSITION) {
notifyItemChanged(postNetworkCallPosition);
}
});
});
getAdapterPosition(); It will always return -1 when recyclerview makes layout calculations. You are calling this methods inside ViewHolder.. It means RecyclerView is doing calculations.
If you need position inside click actions of view, call it in the public void onClick(final View v) method for example:
"#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final Students user = mUsers.get(position);
holder.Name.setText(user.getFullname());
holder.Index.setText(user.getIndex_number());
if (user.getThumbnail().equals("default")) {
holder.profile_image.setImageResource(R.drawable.profile_pic);
} else {
Picasso.get().load(user.getThumbnail())
.placeholder(R.drawable.profile_pic)
.into(holder.profile_image);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
**list_user_id = mUsers.get(position).getId();**
Intent Sub = new Intent(mContext, UserProfileActivity.class);
Sub.putExtra("user_id1", list_user_id);
mContext.startActivity(Sub);
BUT NOT
getAdapterPosition(); It will always return -1 when recyclerview makes layout calculations. You are calling this methods inside ViewHolder.. It means RecyclerView is doing calculations.
If you need position inside click actions of view, call it in the public void onClick(final View v) method for example:
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final Students user = mUsers.get(position);
holder.Name.setText(user.getFullname());
holder.Index.setText(user.getIndex_number());
**list_user_id = mUsers.get(position).getId();**
if (user.getThumbnail().equals("default")) {
holder.profile_image.setImageResource(R.drawable.profile_pic);
} else {
Picasso.get().load(user.getThumbnail())
.placeholder(R.drawable.profile_pic)
.into(holder.profile_image);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
Intent Sub = new Intent(mContext, UserProfileActivity.class);
Sub.putExtra("user_id1", list_user_id);
mContext.startActivity(Sub);