This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
In my application I am getting Null Pointer Exception when click on the up action. The navigation happening properly to parent activity. And it going to the onCreate method of the parent activity. It is expecting a value from intent and it coming as null. But not sure how to set an intent value on up action pressed. Any help appreciated.
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.Bundle.get(java.lang.String)' on a null object reference
activity 1:
public class SignalListActivity extends AppCompatActivity {
public static final String EXTRA_CAT_ID = "sigcatid";
private DatabaseQuery dbQuery;
private Cursor cursor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signal_list);
setTitle("Cat chat");
try {
Toolbar mToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(mToolbar);
if(getSupportActionBar() != null){
getSupportActionBar().setTitle("Signal List");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
dbQuery = new DatabaseQuery(SignalListActivity.this);
final String cat = (String) getIntent().getExtras().get(EXTRA_CAT_ID);
List<Signal> signals = dbQuery.getSignalsNew(cat);
//getting recycler view
RecyclerView signalRecycler =(RecyclerView)findViewById(R.id.signal_recycler);
//GridLayoutManager mGrid = new GridLayoutManager(this, 2);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
signalRecycler.setLayoutManager(layoutManager);
// signalRecycler.setHasFixedSize(true);
SignalAdapter mAdapter = new SignalAdapter(SignalListActivity.this, signals);
signalRecycler.setAdapter(mAdapter);
mAdapter.setListener(new SignalAdapter.Listener() {
#Override
public void onClick(long id) {
Intent intent = new Intent(getApplicationContext(),SignalActivity.class);
intent.putExtra(SignalActivity.EXTRA_SIG_ID, id);
intent.putExtra(EXTRA_CAT_ID, cat);
startActivity(intent);
}
/*public void onClick(int position) {
Intent intent = new Intent(this, SignalActi.class);
intent.putExtra(PizzaDetailActivity.EXTRA_PIZZA_ID, position);
getActivity().startActivity(intent);
}*/
});
} catch(SQLiteException e) {
Toast toast = Toast.makeText(this, "Database unavailable", Toast.LENGTH_SHORT);
toast.show();
}
.....
Activity 2
public class SignalActivity extends AppCompatActivity {
public static final String EXTRA_SIG_ID = "signalId";
private DatabaseQuery dbQuery;
private Context context;
private String cat;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signal);
dbQuery = new DatabaseQuery(SignalActivity.this);
Toolbar mToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(mToolbar);
cat = (String) getIntent().getExtras().get(EXTRA_CAT_ID);
if(getSupportActionBar() != null){
getSupportActionBar().setTitle("Signal Details");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
try {
Long signalId = (Long) getIntent().getExtras().get(EXTRA_SIG_ID);
Signal signal = dbQuery.getSignal(signalId);
TextView name = (TextView)findViewById(R.id.name);
name.setText(signal.getName());
//Populate the drink description
TextView description = (TextView)findViewById(R.id.description);
description.setText(signal.getDescription());
TextView teaser = (TextView)findViewById(R.id.teaser);
teaser.setText(signal.getTeaser());
//Populate the drink image
ImageView photo = (ImageView)findViewById(R.id.photo);
int photoId = getResourseId(this,signal.getImage(), "drawable",getPackageName());
photo.setImageResource(photoId);
photo.setContentDescription(signal.getName());
} catch(SQLiteException e) {
Toast toast = Toast.makeText(this, "Database unavailable", Toast.LENGTH_SHORT);
toast.show();
}
...
when clicking up button from activity 2 it is going to onCreate method of activity 1 and expecting the final String cat = (String) getIntent().getExtras().get(EXTRA_CAT_ID);
If you have 2 activities
Activity A
Activity B
Suppose you now in Activity B, when you press the back button, to navigate back to Activity A, your lifecycle in Activity A would enter onResume(), NOT onCreate() as your Activity A still in you back stack, it doesn't require to recreate the activity once again.
Hence you getting null values, as you are expecting onCreate() callback, which unfortunately won't happen.
To solve this problem we have 3 options:
1) Add a SharedViewModel for both activities, use a MutableLiveData in this ViewModel, add data in Activity B, and observe these data in Activity A.
2) Use Broadcast receiver or callback interface between 2 activities.
3) Start new Intent from Activity B to Activity A and receive the data in onCreate()
Change these two lines:
1)
getIntent().getStringExtra(EXTRA_CAT_ID);
instead of
getIntent().getExtras().get(EXTRA_CAT_ID);
2)
getIntent().getLongExtra(EXTRA_SIG_ID,0);
instead of
getIntent().getExtras().get(EXTRA_SIG_ID);
Because of getIntent().getExtras() is null
Related
I made a TableLayout 3x3 in "Activity A"(Chose a Table Layout, because I thought it suits my needs)
7 of the 9 cells are clickable and open "Activity B" which is a custom number picker I made.
I used an intent to pass an array and other data to activiy B
The idea of my number picker is to set a value in the cell I just clicked in Activiy A(I wanted something like the calendarDatePicker)
In "Activity B" I have a method to update the values from "Activity A" and finish() "Activity B" when an image View is clicked wich works very fine except that it does not set the value for the clicked Text View
How can I set the TextValue from another activity when the TextValue is contained in a Table Layout?
I don't use intent, because honestly I don't know how to handle it when the "Activity B" is closed.
I mean where in "Activity A" should I handle this intent from "Activity B"
Using the debugger I found out that trying to set the text using the TextView Id does not works as it shows a "null" object in the debugger.
Activiy A
package com.example.racu.threebythree;
public class threebythree extends AppCompatActivity {
public static ArrayList<Integer> ColumnA = new ArrayList<Integer>();
public static ArrayList<Integer> ColumnB = new ArrayList<Integer>();
public static ArrayList<Integer> ColumnC = new ArrayList<Integer>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_three_by_three);
for (int i = 1; i < 28; i++) {
if (i > 0 && i < 10)
ColumnA.add(i);
if (i > 10 && i < 19)
ColumnB.add(i);
if (i > 19 && i < 28)
ColumnC.add(i);
}
}
public void openNumberPicker(View v) {
// I used this to "guess" the location of the cell in the table layout as I could not find a way to do it.
String cellName = v.getResources().getResourceName(v.getId());
String cellLetter = cellName.substring(cellName.lastIndexOf("/") + 1);
// Send intent
Intent intent = new Intent(this, NumberPicker.class);
intent.putExtra("Id", (cellLetter.substring(0, 1) + cellLetter.substring(2)).toUpperCase());
switch (cellLetter.substring(0, 1)) {
case ("a"):
intent.putIntegerArrayListExtra("Column", ColumnA);
break;
case ("b"):
intent.putIntegerArrayListExtra("Column", ColumnB);
break;
case ("c"):
intent.putIntegerArrayListExtra("Column", ColumnC);
break;
}
intent.putExtra("Cell ID", v.getId());
startActivity(intent);
}
}
Avtivity B
package com.example.racu.threebythree;
public class NumberPicker extends AppCompatActivity {
GridView numberPicker;
ArrayList<Integer> numbersToDisplay;
TextView viewToDisplay;
ImageView ok, cancel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_number_picker);
numberPicker = (GridView) findViewById(R.id.arrayNumbers);
viewToDisplay = (TextView) findViewById(R.id.number_to_select);
ok = (ImageView) findViewById(R.id.add_number_to_card);
ok.setClickable(false);
Intent intent = getIntent();
String idFromIntent = intent.getStringExtra("Id");
numbersToDisplay = intent.getIntegerArrayListExtra("Letter");
TextView numberPosition = (TextView) findViewById(R.id.numberPosition);
numberPosition.setText(idFromIntent);
final TextView chosenNumber = (TextView) findViewById(R.id.chosenNumber);
ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(this, R.layout.number_for_picker, numbersToDisplay);
numberPicker.setAdapter(adapter);
numberPicker.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
chosenNumber.setText(((TextView) v).getText());
ok.setImageResource(R.drawable.ok_blue);
ok.setClickable(true);
}
});
}
public void updateThreByThree(View v) {
Intent intent = getIntent();
int currentCell = intent.getIntExtra("Cell ID", 0);
String idFromIntent = intent.getStringExtra("Id").substring(0, 1);
TextView chosenNumber = (TextView) findViewById(R.id.chosenNumber);
// Here I try to Set the text to the cell in Activity A, using its R.id, but in the debugger I get a null reference, therefore my app crashes
TextView currentCellToEdit = (TextView) findViewById(currentCell);
currentCellToEdit.setText(chosenNumber.getText());
int temp = Integer.parseInt(chosenNumber.getText().toString());
switch (idFromIntent) {
case "A":
threebythree.ColumnA.remove(Integer.valueOf(temp));
break;
case "B":
threebythree.ColumnB.remove(Integer.valueOf(temp));
break;
case "C":
threebythree.ColumnC.remove(Integer.valueOf(temp));
break;
}
finish();
}
public void cancel(View view) {
finish();
}
}
Thanks to Pavan for the hint I found two more very helpful post here and this one was EXACTLY what I was looking for.
Like that ( make sure you give the TableLayout an id ):
TableLayout tl = (TableLayout)findViewById( R.id.tableLayout );
TextView tv = (TextView)tl.findViewById( R.id.textView );
ActivityB --> Service class --> Populate ListView in ActivityC (as shown below and there is no fragment for it) ---> ActivityD
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0);
setLocale(pref.getString("myLocale", null));
setTitle(R.string.title_activity_choose_number);
setContentView(R.layout.activity_choose_number1);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if(savedInstanceState != null ) {
mobileNumbersList = savedInstanceState.getStringArrayList("mobileNumbers");
}
mobileNumbersList = getIntent().getStringArrayListExtra("mobileNumbers");
mobileNumberAdapter = new ArrayAdapter<String>(this,
R.layout.secnumsinglechoice,
mobileNumbersList);
numberListView = (ListView) findViewById(R.id.listViewNumberList);
numberListView.setAdapter(numberAdapter);
numberListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String numberChosen = numberAdapter.getItem(position);
Intent passNumberIntent = new Intent(getBaseContext(), US.class).
putExtra(Intent.EXTRA_TEXT, numberChosen);
startActivity(passNumberIntent);
}
});
}
Now when back button is pressed in ActivityD to ActivityC, I am getting null pointer error. I know the reason because this time, I am not passing the intent from ActivityD and ListView, adapter, data is all null.
So when I searched for how to save the state, I came across saveInstanceState, onRestoreInstance and onSaveInstance. But I am still not able to fix the issue. ActivityC doesn't have a fragment.
There are two things you should do:
Check getIntent() is null or not. If it's not null, try to get data from it
Put data into savedInstanceState variable on method public void onSaveInstanceState(Bundle savedInstanceState)
I have 2 Fragments that both pass an intent to an Activity (through an event listener). How can the Activity know which of these 2 fragments passed the intent? There's a method called getCallingActivity(), I need the equivalent for fragments.
I Attempted to determine which Fragment Called the Activity with the onAttachFragment() method, But it doesn't work:
public class DetailsActivity extends Activity {
static final String POSITION = "position";
private Movie movie;
private int position;
private static final String TAG = "app";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
}
#Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
Log.v(TAG, "fragment_src");
position = (int) getIntent().getExtras().get(POSITION);
if (fragment instanceof PopularFragment) {
movie = PopularFragment.movieList.get(position);
setData();
} else if (fragment instanceof TopRatedFragment) {
movie = TopRatedFragment.movieList.get(position);
setData();
}
}
public void setData() {
TextView original_title = (TextView) findViewById(R.id.original_title);
original_title.setText(movie.getOriginal_title());
...
}
}
You could send different int values with your intent for both fragment and check in your activity..or you could get your fragment by using
Fragment fragment = getFragmentManager().findFragmentByTag("yourtag");
Why don't you pass some parameters through the Intent itself
For first fragment-
Intent intent=new Intent(getActivity(),DetailsActivity.class);
intent.putExtra("fragName","PopularFragment");
startActivity(intent);
For Second Fragment-
Intent intent=new Intent(getActivity(),DetailsActivity.class);
intent.putExtra("fragName","TopRatedFragment");
startActivity(intent);
In your Activity
String fragName=getIntent().getStringExtra("fragName");
And then just check using if..else.
scenario:
First mainactivity launches and from the menu option user launches second activity using intent and there he adds some text to edittext and get that edittext value using intent to the first activity and add that value to the listview.
FirstActivity:
public class MainActivity extends Activity {
ListView lv;
EditText et;
String AddedTask ;
ArrayList<Model> modelList;
CustomAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = getIntent();
if (intent.hasExtra("NewTask")) {
AddedTask = this.getIntent().getExtras().getString("NewTask");
lv = (ListView) findViewById(R.id.listViewData);
String name = AddedTask;
Model md = new Model(name);
modelList.add(md);
adapter = new CustomAdapter(getApplicationContext(), modelList);
lv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar actions click
switch (item.getItemId()) {
case R.id.action_settings:
return true;
case R.id.action_add_task:
Intent i = new Intent(MainActivity.this, AddTask.class);
startActivity(i);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Second Activity:
public class AddTask extends Activity {
Button addtask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_task);
// get action bar
ActionBar actionBar = getActionBar();
// Enabling Up / Back navigation
actionBar.setDisplayHomeAsUpEnabled(true);
addtask = (Button) findViewById(R.id.btnaddlist);
findViewById(R.id.btnaddlist).setOnClickListener(
new View.OnClickListener() {
public void onClick(View arg0) {
EditText edit = (EditText) findViewById(R.id.tskname);
Intent i = new Intent(AddTask.this,
MainActivity.class);
//Bundle bundle = new Bundle();
String TaskName = edit.getText().toString();
//bundle.putString("NewTask", TaskName);
i.putExtra("NewTask", TaskName);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//i.putExtras(bundle);
startActivity(i);
}
});
}
}
Now my problem is I'm able to add the data to the listview but each time I come back to mainactivity the previous data which was added is lost and updating the old data with my new data.
I have searched for many SO answers and most of them suggest to add adapter.notifyDataSetChanged(); which I have already tried and nothing worked.
I have done by checking the adapter is null or updating the data this way and getting null pointer exception:
if ( adapter== null )
{
adapter = new CustomAdapter(getApplicationContext(), modelList);
lv.setAdapter(adapter);
}
Can anyone say me how do I get this working ?
new View.OnClickListener() {
public void onClick(View arg0) {
EditText edit = (EditText) findViewById(R.id.tskname);
Intent i = new Intent(AddTask.this,
MainActivity.class);
//Bundle bundle = new Bundle();
String TaskName = edit.getText().toString();
//bundle.putString("NewTask", TaskName);
i.putExtra("NewTask", TaskName);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//i.putExtras(bundle);
startActivity(i);
}
});
You are starting a new Activity each time you want to add an item.
Consider using
startActivityForResult()
Link to Android Documentation
Even if startActivityForResult() is IMHO the best way to fix your problem, i'll give you a hint why it doesn't show your "old" data.
You don't finish your first Activity when going to the Second. You could aswell just finish your second activity and your MainActivity would run into
onResume()
therefor check the Android lifecycle
Don't use putextra and intent techniques. Follow below technique.
In main activity create sharedpref as follows:
public static final String SharedPref = "MyPreferences";
In activity 2 insert this code.
SharedPreferences settings=null;//declaration
settings=getSharedPreferences(SharedPref,0);//initialization
String TaskName= edit.getText().toString();
SharedPreferences.Editor editor = settings.edit();
editor.putString("NewTask", TaskName);
editor.commit();
finishfromchild(AddTask.this);
In main activity:
SharedPreferences settings=null;//declaration
In onCreate
//now initialise settings
settings=getSharedPreferences(SharedPref,0);//SharedPref is the foldername
//of your sharedpreferences(you create it first)
//Now create onResume method
public void onResume()
{
super.onResume();
AddedTask=settings.getString("NewTask", "");
lv = (ListView) findViewById(R.id.listViewData);
String name = AddedTask;
Model md = new Model(name);
modelList.add(md);
adapter = new CustomAdapter(getApplicationContext(), modelList);
lv.setAdapter(adapter);
}
Hope this works. I did the same in my previous project.
I am using a ListFragment for displaying a list from a database in my activity. I have included a search function. Unfortunately the "old" ListFragments seem to remain in the background and the ListFragments containing the result of the query are displayed on top of it. How can I avoid, that the old ListFragments are displayed?
My FragmentActivity:
private Button buttonSearch;
private TextView searchString;
public static String search = null;
static IShoppinglist shoppinglistManager;
static IAktionen aktionenManager;
private AktionenListListFragment listFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "ListFragmentActivity created");
super.onCreate(savedInstanceState);
setContentView(R.layout.articlelist);
shoppinglistManager = new Shoppinglist(this);
aktionenManager = new Aktionen(this);
buttonSearch = (Button) findViewById(R.id.search_Button);
buttonSearch.setOnClickListener(searchListAktionen);
//show all entries on start
listFragment = new AktionenListListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_articlelist, listFragment).commit();
}
OnClickListener searchListAktionen = new OnClickListener() {
public void onClick(View v) {
try{
searchString = (TextView) findViewById(R.id.input_search_bezeichnung);
search = searchString.getText().toString().trim();
Log.d(TAG, "search Button clicked "+search);
if(search.trim().length()==0){
search=null;
}
//show all entries on start
listFragment = new AktionenListListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_articlelist, listFragment).commit();
}catch(Exception ex){
ex.printStackTrace();
}
}
};
Thanks in advance,
update:
thank you for your answers. I tried to implement them, but the main problem seems to be nowthat the onCreate and onActivityCreated method in the ListFragment are called twice (as I can see in my log messages).
my new code:
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "ListFragmentActivity created");
super.onCreate(savedInstanceState);
//force commit
getSupportFragmentManager().executePendingTransactions();
if(getSupportFragmentManager().findFragmentByTag(tag) == null) {
setContentView(R.layout.articlelist);
shoppinglistManager = new Shoppinglist(this);
aktionenManager = new Aktionen(this);
buttonSearch = (Button) findViewById(R.id.search_Button);
buttonSearch.setOnClickListener(searchListAktionen);
listFragment = new AktionenListListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_articlelist, listFragment,tag).commit();
}else{
Log.d(TAG, "ListFragment already exists");
}
}
I tried to set a unique tag for my ListFragment but this solution does not work.
I guess that one of the ListFragments is displayed in the background and the other is updated.
So first you need to stop making new ListFragments everytime your list is refreshed and just have a public method in your ListFragment that the Activity can call to restart the loader with the proper parameters. Then:
In your onLoadFinished(),
you should make a new adapter with the list you want to replace it with
myAdapter = new AktionenListCustomCursorAdapter(getActivity(), myCursor);
and call:
this.getListView().setAdapter(myAdapter);
So:
public void onLoadFinished(Loader<Cursor> mAdapter, Cursor myCursor) {
if(myCursor!=null){
//getting the data from the database
Log.d(TAG, "search String "+AktionenListFragmentActivity.search);
if(AktionenListFragmentActivity.search==null){
myCursor = AktionenListFragmentActivity.aktionenManager.fetchAllArticles();
}else{
myCursor = AktionenListFragmentActivity.aktionenManager.fetchItemsByBezeichnung(AktionenListFragmentActivity.search);
}
myAdapter = new AktionenListCustomCursorAdapter(getActivity(), myCursor);
this.getListView().setAdapter(myAdapter);
}
}
Hopefully this solved your question as I understood it. If you have any questions please leave it in the comment below and I will expand my answer. If it worked for you please accept answer. :D