我对android很新,这是我的第二个应用程序。我正在制作一个标签式活动,其中第一个片段具有创建新任务的表单,第二个片段具有所有已保存任务的列表,第三个片段将显示从第二个列表中选择的任务的注释分段。当我单击第一个片段上的“保存任务”按钮时,应用程序会正确保存任务并将其显示在下一个片段的任务列表中。但是,我不想使用"保存任务"第一个片段中的按钮。我希望能够在用户从第一个活动切换到第二个活动时立即保存任务。
为此,我尝试从活动中的saveTask()
方法调用片段的OnPageChangeListener.onPageScrolled()
方法,但片段中的所有视图都会给出NullPointerException
。如果我在活动performClick()
的“保存任务”按钮上尝试OnPageChangeListener.onPageScrollStateChanged()
,则即使该按钮也会显示NullPointerException
。当我打印到日志以查看是否已初始化“保存任务”按钮时,日志会正确显示按钮ID。关于如何仅使用滑动将任务保存到数据库,我感到很遗憾。请帮忙!
这是我的主要活动:
public class AddTask extends AppCompatActivity {
/**
* The {@link PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {@link FragmentStatePagerAdapter}.
*/
private static SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
private ViewPager mViewPager;
public List<String> fragments = new Vector<String>();
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_task);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
//fill the fragments list with the fragment classes
fragments.add(AddTaskFragment.class.getName());
fragments.add(TasksFragment.class.getName());
fragments.add(CommentsFragment.class.getName());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setOffscreenPageLimit(2);
mViewPager.setCurrentItem(1);
final AddTaskFragment addTaskFrag = (AddTaskFragment) mSectionsPagerAdapter.getItem(0);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
android.support.v7.app.ActionBar actionBar = getSupportActionBar();
switch (position) {
case 0:
actionBar.setTitle("Add New Task");
break;
case 1:
actionBar.setTitle("Existing Tasks");
break;
case 2:
actionBar.setTitle("Comments");
break;
}
}
@Override
public void onPageSelected(int position) {
if (fragments.get(position).equals(TasksFragment.class.getName())) {
}
}
@Override
public void onPageScrollStateChanged(int state) {
if(mViewPager.getCurrentItem()==0) {
if (state == ViewPager.SCROLL_STATE_DRAGGING) {
if (addTaskFrag != null) {
addTaskFrag.saveTaskBtn.performClick();
}
}
}
}
});
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_add_task, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onStart() {
super.onStart();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.connect();
Action viewAction = Action.newAction(
Action.TYPE_VIEW, // TODO: choose an action type.
"AddTask Page", // TODO: Define a title for the content shown.
// TODO: If you have web page content that matches this app activity's content,
// make sure this auto-generated web page URL is correct.
// Otherwise, set the URL to null.
Uri.parse("http://host/path"),
// TODO: Make sure this auto-generated app deep link URI is correct.
Uri.parse("android-app://com.example.ishita.assigntasks/http/host/path")
);
AppIndex.AppIndexApi.start(client, viewAction);
}
@Override
public void onStop() {
super.onStop();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
Action viewAction = Action.newAction(
Action.TYPE_VIEW, // TODO: choose an action type.
"AddTask Page", // TODO: Define a title for the content shown.
// TODO: If you have web page content that matches this app activity's content,
// make sure this auto-generated web page URL is correct.
// Otherwise, set the URL to null.
Uri.parse("http://host/path"),
// TODO: Make sure this auto-generated app deep link URI is correct.
Uri.parse("android-app://com.example.ishita.assigntasks/http/host/path")
);
AppIndex.AppIndexApi.end(client, viewAction);
client.disconnect();
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public List<String> fragmentsA;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
fragmentsA = fragments;
}
@Override
public Fragment getItem(int position) {
//Instantiate the fragment at the position where the pager is.
return Fragment.instantiate(getApplicationContext(), fragmentsA.get(position));
}
@Override
public int getCount() {
// return how many fragments there are in the tabbed activity
return fragmentsA.size();
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Add Task";
case 1:
return "Tasks List";
case 2:
return "Comments";
}
return null;
}
}
}
这是我用于创建新类的Java片段:
/**
* A placeholder fragment containing a simple view.
*/
public class AddTaskFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
final int PICK_CONTACT = 1;
private static final String ARG_SECTION_NUMBER = "section_number";
public String mAssigneeName;
public String mAssigneeContact;
public String mTaskName;
public String mDueDate;
public String mComments = null;
public AddTaskFragment() {
}
EditText dueDate;
EditText assignee;
EditText taskDescription;
EditText comments;
Button saveTaskBtn;
View rootView;
Calendar myCalendar = Calendar.getInstance();
DatePickerDialog.OnDateSetListener date = new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
// TODO Auto-generated method stub
myCalendar.set(Calendar.YEAR, year);
myCalendar.set(Calendar.MONTH, monthOfYear);
myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
updateLabel();
}
};
private void updateLabel() {
String displayFormat = "MMM dd, yyyy"; //setting the format in which the date will be displayed
SimpleDateFormat sdf = new SimpleDateFormat(displayFormat, Locale.US);
dueDate.setText(sdf.format(myCalendar.getTime()));
}
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static AddTaskFragment newInstance(int sectionNumber) {
AddTaskFragment fragment = new AddTaskFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_add_task, container, false);
dueDate = (EditText) rootView.findViewById(R.id.due_date);
taskDescription = (EditText) rootView.findViewById(R.id.description);
comments = (EditText) rootView.findViewById(R.id.comments);
assignee = (EditText) rootView.findViewById(R.id.assignee);
dueDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new DatePickerDialog(getActivity(), date, myCalendar
.get(Calendar.YEAR), myCalendar.get(Calendar.MONTH),
myCalendar.get(Calendar.DAY_OF_MONTH)).show();
}
}
);
assignee.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
startActivityForResult(intent, PICK_CONTACT);
} catch (Exception e) {
e.printStackTrace();
}
}
});
saveTaskBtn = (Button) rootView.findViewById(R.id.save_task);
Log.v("AddTaskFragment", "saveTaskBtn assigned to " + R.id.save_task);
saveTaskBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
saveTask();
}
});
return rootView;
}
public void saveTask(){
try {
mTaskName = taskDescription.getText().toString();
taskDescription.setText("");
mDueDate = dueDate.getText().toString();
dueDate.setText("");
mComments = comments.getText().toString();
comments.setText("");
assignee.setText(R.string.assignee_prompt);
if (mTaskName == null || mDueDate == null || mAssigneeName == null) {
Toast.makeText(getContext(), "Fields cannot be empty. Please fill some values.", Toast.LENGTH_SHORT).show();
} else {
UpdateTask updateDB = new UpdateTask();
updateDB.execute();
Toast.makeText(getContext(), "Task saved.", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void onActivityResult(int reqCode, int resultCode, Intent data) {
super.onActivityResult(reqCode, resultCode, data);
EditText assignee = (EditText) getActivity().findViewById(R.id.assignee);
switch (reqCode) {
case (PICK_CONTACT):
if (resultCode == Activity.RESULT_OK) {
Uri contactData = data.getData();
Cursor cursor = getContext().getContentResolver().query(contactData, new String[]{ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER}, null, null, null);
if (cursor.moveToFirst()) {
mAssigneeName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
mAssigneeContact = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER));
assignee.setText(mAssigneeName);
Toast.makeText(getActivity(), mAssigneeName + " has number " + mAssigneeContact, Toast.LENGTH_LONG).show();
}
cursor.close();
}
break;
}
}
public class UpdateTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
ContentValues taskDetails = new ContentValues();
taskDetails.put(TasksContract.TaskEntry.COL_DESCRIPTION, mTaskName);
taskDetails.put(TasksContract.TaskEntry.COL_ASSIGNEE_KEY, mAssigneeContact);
taskDetails.put(TasksContract.TaskEntry.COL_CREATOR_KEY, "creatorID");
taskDetails.put(TasksContract.TaskEntry.COL_DUE_DATE, mDueDate);
taskDetails.put(TasksContract.TaskEntry.COL_COMMENTS, mComments);
getContext().getContentResolver().insert(TasksContract.TaskEntry.CONTENT_URI, taskDetails);
Cursor cursor = getContext().getContentResolver().query(
TasksContract.ProfileEntry.CONTENT_URI,
new String[]{TasksContract.ProfileEntry._ID},
TasksContract.ProfileEntry.COL_CONTACT + "=?",
new String[]{mAssigneeContact},
null
);
if (!cursor.moveToFirst()) {
ContentValues contactDetails = new ContentValues();
contactDetails.put(TasksContract.ProfileEntry.COL_NAME, mAssigneeName);
contactDetails.put(TasksContract.ProfileEntry.COL_CONTACT, mAssigneeContact);
getContext().getContentResolver().insert(TasksContract.ProfileEntry.CONTENT_URI, contactDetails);
}
cursor.close();
return null;
}
}
}
以下是片段的XML:
<ScrollView 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.ishita.assigntasks.AddTaskFragment">
<EditText
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:hint="@string/task_prompt" />
<EditText
android:id="@+id/assignee"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:ems="10"
android:focusable="false"
android:inputType="textPersonName"
android:text="@string/assignee_prompt" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/due_date"
android:textSize="18sp" />
<EditText
android:id="@+id/due_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:ems="10"
android:focusable="false"
android:inputType="date" />
</LinearLayout>
<EditText
android:id="@+id/comments"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:hint="@string/comments"
android:minHeight="?android:listPreferredItemHeight" />
<Button
android:id="@+id/save_task"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/save_task" />
</LinearLayout>
</ScrollView>
logcat的:
02-18 13:48:05.538 3752-3752/? I/art: Late-enabling -Xcheck:jni
02-18 13:48:05.628 3752-3752/com.example.ishita.assigntasks W/ResourceType: Found multiple library tables, ignoring...
02-18 13:48:05.664 3752-3752/com.example.ishita.assigntasks I/GMPM: App measurement is starting up, version: 8487
02-18 13:48:05.664 3752-3752/com.example.ishita.assigntasks I/GMPM: To enable debug logging run: adb shell setprop log.tag.GMPM VERBOSE
02-18 13:48:05.823 3752-3788/com.example.ishita.assigntasks D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
02-18 13:48:05.840 3752-3752/com.example.ishita.assigntasks D/Atlas: Validating map...
02-18 13:48:06.039 3752-3788/com.example.ishita.assigntasks I/Adreno-EGL: <qeglDrvAPI_eglInitialize:410>: EGL 1.4 QUALCOMM build: AU_LINUX_ANDROID_LA.BF.1.1.1_RB1.05.01.00.042.030_msm8974_LA.BF.1.1.1_RB1__release_AU ()
OpenGL ES Shader Compiler Version: E031.25.03.06
Build Date: 05/17/15 Sun
Local Branch: mybranch10089422
Remote Branch: quic/LA.BF.1.1.1_rb1.22
Local Patches: NONE
Reconstruct Branch: AU_LINUX_ANDROID_LA.BF.1.1.1_RB1.05.01.00.042.030 + 6151be1 + NOTHING
02-18 13:48:06.053 3752-3788/com.example.ishita.assigntasks I/OpenGLRenderer: Initialized EGL, version 1.4
02-18 13:48:06.077 3752-3788/com.example.ishita.assigntasks D/OpenGLRenderer: Enabling debug mode 0
02-18 13:48:06.123 3752-3752/com.example.ishita.assigntasks W/View: requestLayout() improperly called by android.widget.TextView{5fbdde1 V.ED.... ......ID 48,43-403,124} during layout: running second layout pass
02-18 13:48:06.440 3752-3752/com.example.ishita.assigntasks V/case:msgCount:getInt: 0
02-18 13:48:06.440 3752-3752/com.example.ishita.assigntasks V/getViewId: 2131493003
02-18 13:48:06.485 3752-3752/com.example.ishita.assigntasks I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@9dab03c time:19983548
02-18 13:48:10.458 3752-3752/com.example.ishita.assigntasks E/InputEventReceiver: Exception dispatching input event.
02-18 13:48:10.458 3752-3752/com.example.ishita.assigntasks D/AndroidRuntime: Shutting down VM
02-18 13:48:10.532 3752-3752/com.example.ishita.assigntasks E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.ishita.assigntasks, PID: 3752
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.widget.Button.performClick()' on a null object reference
at com.example.ishita.assigntasks.AddTask$1.onPageScrollStateChanged(AddTask.java:100)
at android.support.v4.view.ViewPager.dispatchOnScrollStateChanged(ViewPager.java:1811)
at android.support.v4.view.ViewPager.setScrollState(ViewPager.java:404)
at android.support.v4.view.ViewPager.onInterceptTouchEvent(ViewPager.java:1935)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1961)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2372)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1722)
at android.app.Activity.dispatchTouchEvent(Activity.java:2742)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2333)
at android.view.View.dispatchPointerEvent(View.java:8742)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4136)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4002)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3557)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3610)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3576)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3693)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3584)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3750)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3557)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3610)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3576)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3584)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3557)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5823)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5797)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5768)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5913)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)
at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:5884)
at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:5936)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:548)
答案 0 :(得分:1)
OnPageChangeListener
中页面更改的调用方法(当选择其他页面时)为onPageSelected
。
另外,在getItem
上调用PagerAdapter
会实例化新的片段。要解决此问题,您需要在PagerAdapter中保留片段列表并创建检索它们的方法。
//in PagerAdapter:
private List<Fragment> fragmentList;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
fragmentsA = fragments;
fragmentList = new ArrayList<Fragment>();
for(int i = 0; i < 3; i++){
fragmentList.add(Fragment.instantiate(getApplicationContext(), fragmentsA.get(i)););
}
}
public Fragment getFragment(int position){
return fragmentList.get(position);
}