android - Listview OnItemClickListener 在 MainActivity 上工作但不在类似的 TaskActivity 上工作

标签 android listview android-adapter onitemclicklistener

在 MainActivity 中,我有一个响应长按的 ContextMenu 和一个响应常规点击的常规 OnItemClickListener。

在实际上类似于 MainActivity 的 TaskActivity 上,我也有一个响应长按的 ContextMenu,但是当尝试设置 OnItemClickListener 时, ListView 中的项目不响应(它们确实响应长按).

我错过了什么?我尝试了各种方法,例如将可点击状态更改为 false 等等 - 它们都不起作用。这是有道理的,因为我在 MainActivity XML 中没有它们,但它确实在那里工作。

主要 Activity 代码:

公共(public)类 MainActivity 扩展 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;
}

任务 Activity 代码:

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 - TaskActivity 适配器

    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;
    }
}

最佳答案

在为包含 CheckBoxListView 行尝试了几种推荐的解决方法(如 here )但没有成功之后,我想建议一种不同的方法:

使用另一个透明的 View,它覆盖整行,CheckBox 周围的一小块区域除外。让这个 View 有一个 OnClickListener 触发 TaskInfoFragment 的打开。

理想情况下,我们会使用一个接口(interface),这样 TaskAdapter 就可以将点击的 Task 传递给 TaskActivity,后者又会显示 fragment

几个小时后......(@Guy,你的提示“尝试删除所有与复选框相关的代码和 xml,并且常规点击问题仍然存在”让我一个接一个地交换组件,直到我将它缩小到行xml) 我找到了 TaskActivityListViewOnItemClickListener 不触发的原因。 Task 列表的根 ConstraintLayout 有一个 TaskList 列表的根没有的属性:android:longClickable="真”

删除此属性会使 ListView 正常运行。

关于android - Listview OnItemClickListener 在 MainActivity 上工作但不在类似的 TaskActivity 上工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52431329/

相关文章:

android - 适配器在 Android 中的作用是什么?

Android:折叠线性布局而不是折叠工具栏

android - android.performFiltering() 过滤时出现 sql 异常。

java - 通过http流音频

listview - JavaFX ListView重复删除错误

java - Android 中索引 3 无效,大小为 0

javascript - 如何根据边框元素在winjs ListView 中删除焦点

android - ListView 滚动期间首先显示错误图像,然后显示正确图像

android - 刷新适配器后如何将recyclerView位置项 View 重置为原始状态

android - 空间不足,无法显示 Admob 广告错误