I definied my own method to display Toast and I want to call it from another Activity. When I do that, my app crash. Do you have some Attempt to invoke virtual method.... on a null object reference.
The Toast method:
public void showToastDown(Context context, String message) {
context = getApplicationContext();
inflater = getLayoutInflater();
View v = inflater.inflate(R.layout.toast_down, (ViewGroup) findViewById(R.id.toast_down_root));
TextView tvToastDown = v.findViewById(R.id.tvToastDown);
tvToastDown.setText(message);
Toast toast = new Toast(context);
toast.setGravity(Gravity.BOTTOM|Gravity.FILL_HORIZONTAL, 0,0);
toast.setDuration(Toast.LENGTH_SHORT);
toast.setView(v);
toast.show();
}
and the code from 2nd activity:
switch (item.getItemId()){
case R.id.btnAddActionBar:
MainActivity mainActivity= new MainActivity();
mainActivity.showToastDown(this, "TEXT");
break;
}
return super.onOptionsItemSelected(item);
}
Remove this line from your code, as you are already passing value of context so no need to initialize again with Application Context.
context = getApplicationContext();
EDIT: Change Your Method like this:
public void showToastDown(Context context, String message) {
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
View v = inflater.inflate(R.layout.toast_down, (ViewGroup) ((Activity)context).findViewById(R.id.toast_down_root));
TextView tvToastDown = v.findViewById(R.id.tvToastDown);
tvToastDown.setText(message);
Toast toast = new Toast(context);
toast.setGravity(Gravity.BOTTOM|Gravity.FILL_HORIZONTAL, 0,0);
toast.setDuration(Toast.LENGTH_SHORT);
toast.setView(v);
toast.show();
}
There's a couple of problems with your code:
Never instantiate activities yourself (mainActivity = new MainActivity). This doesn't work, only the Android OS can create activities. I suggest taking some (free) beginner android tutorials online to understand how activities work and what their role is.
The toast function you've written is a utility function that doesn't appear to have anything to do with MainActivity. If you put it as a static function of a different class (whose purpose is only to provide useful utility functions like this) e.g. ActivityTools.java, then you can call it from anywhere and pass it a Context like you are doing.
In your toast function, you're receiving a context as the first parameter but then immediately overwriting it. This doesn't make any sense, there's no reason to overwrite it like this.
Related
I am trying to create a class that it´s supossed to show a toast every time that an object of this class is instaciated.
I want to do this so that I don´t have the same toast code repeated in every activity.
public class Toast extends android.widget.Toast {
String toast_text;
Context toast_context;
public Toast(String toast_text, Context toast_context) {
this.toast_text = toast_text;
this.toast_context = toast_context;
Toast toast = android.widget.Toast.makeText(this.toast_context.this, this.toast_text, Toast.LENGTH_LONG);
ViewGroup view = (ViewGroup) toast.getView();
view.setBackgroundResource(R.drawable.background_global);
TextView messageTextView = (TextView) view.getChildAt(0);
messageTextView.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
messageTextView.setTextSize(35);
Typeface face_font = Typeface.createFromAsset(getAssets(), "res/font/aldrich.ttf");
messageTextView.setTypeface(face_font);
messageTextView.setTextColor(Color.CYAN);
toast.show();
}
}
These are the following erros:
On the constructor: "There is no default constructor available in "android.widget.toast";
On the first error: " ')' expected";
On the second error: "Cannot resolve method "getAssets" ".
Use toast_context that you receive through constructor to create toast and access asset
Toast toast = android.widget.Toast.makeText(toast_context, toast_text, Toast.LENGTH_LONG);
Typeface face_font = Typeface.createFromAsset(toast_context.getAssets(), "res/font/aldrich.ttf");
Beside this, You should use other name than Toast to create custom toast
class MyToast extends android.widget.Toast {
public MyToast(String toast_text, Context toast_context) {
super(toast_context);
...
}
}
I have created my own custom adapter class in my android app and I am calling it from one of my activity. I am adding some elements to the view from the adapter class and I need to access those variables from my activity class.
Now, ideally I would expect it to fill the view and then execute the further code in my activity class, but adapter class is taking some time to populate the view and in the meanwhile further code in my activity class is getting executed where no such elements have been added yet.
How do I handle this situation? I come from a js background. Do we have something like promises in java?
According to the answers I have my changed my code to this:
public class HomeActivity extends Activity {
GridView grid;
String text[] = {"Calendar","Uber","Weather","News","Youtube","Clock","Email","Maps","Twitter","Facebook"};
String list_app_name[] = {"calendar","uber","weather","news","youtube","clock","email","maps","twitter","facebook"};
String id_button[] = {"button_calendar","button_uber","button_weather","button_news","button_youtube","button_clock","button_email","button_maps","button_twitter","button_facebook"};
int image[] = {R.drawable.social_icons1,R.drawable.social_icons2,R.drawable.social_icons3,R.drawable.social_icons4,
R.drawable.social_icons5,R.drawable.social_icons6, R.drawable.social_icons7,R.drawable.social_icons8,
R.drawable.social_icons9,R.drawable.social_icons10};
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_home);
//setting up the adapter for gridView
grid = (GridView)findViewById(R.id.simpleGrid);
ImageAdapter ia = new ImageAdapter(this,image,text,id_button);
grid.setAdapter(ia);
ia.notifyDataSetChanged();
try {
initStateOfApps();
} catch (JSONException e) {
e.printStackTrace();
}
}
public void initStateOfApps() throws JSONException {
Log.d("here","here");
ArrayList<String> list = getEnabledApps();
Log.d("apps",list.toString());
for(int i=0;i<list.size();i++) {
String app_name = list.get(i);
ToggleButton button=null;
if(app_name.equals("calendar")) {
button = (ToggleButton)findViewById(R.id.button_calendar);
button.setChecked(true);
}
}
}
}
So what is happening is that I am creating some toggle buttons that are getting populated in the ImageAdapter class that I wrote.
Once the ImageAdapter is called, I call the notifydatasetchanged() on the adapter in order to update the view.
What I am doing inside the adapter is giving each of the toggle buttons some custom ID I wrote in res/values/ids.xml.
After using setId on each of the toggle buttons, I try using that ID in my activity class but it gives me nullPointerException in the initStateOfApps() where I am trying to change the state of button.
So even after using the notifyDataSetChanged it is still behaving the same.
ImageAdapter.java
public class ImageAdapter extends BaseAdapter {
private Context context;
private final int item_image[];
private final String item_text[];
private final String button_id[];
public ImageAdapter(Context context, int item_image[], String[] item_text,String[] button) {
this.context = context;
this.item_image = item_image;
this.item_text = item_text;
this.button_id = button;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
// get layout from custom_gridview.xml
gridView = inflater.inflate(R.layout.item, null);
// set value into imageview
final ImageView image = (ImageView) gridView.findViewById(R.id.item_image);
image.setImageResource(item_image[position]);
// set value into textview
TextView text = (TextView) gridView.findViewById(R.id.item_text);
text.setText(item_text[position]);
final ToggleButton button_ = (ToggleButton) gridView.findViewById(R.id.item_button);
if(position==0) {
button_.setId(R.id.button_calendar);
image.setId(R.id.image_calendar);
}
button_.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton toggleButton, boolean isChecked)
{
if(context.getResources().getResourceEntryName(toggleButton.getId()).equals("button_calendar")) {
if(isChecked) {
try {
setStateOfApp("calendar","true");
} catch (JSONException e) {
e.printStackTrace();
}
Intent intent = new Intent(context, GoogleApp.class);
((Activity) context).startActivityForResult(intent,10);
} else {
try {
setStateOfApp("calendar","false");
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
} else {
gridView = (View) convertView;
}
return gridView;
}
}
You are trying to access View which is not a part of Activity's content view. So you can't access that view directly.
button = (ToggleButton)findViewById(R.id.button_calendar); // will return null
This ToggleButton will be null because findViewById will fail to find out ToggleButton in current content view because that view is present in your Adapter not in content view.
And you are getting nullpointerException because you are trying to access property on null view.
button.setChecked(true); // This button is null
In java we have <Future>, but I don't think it's what you're looking for.
The adapter (extending BaseAdaper) behaviour lets you create the adapter and, even in a second moment, change underlying data via getAdapter().setData() or whatever method you choose to add.
From this perspective, the adapter is a "stupid" component acting as A View containers, you should retrieve data elsewhere (CursorAdapter is different).
So, in your Activity, fill the adapter with needed data and, when finished, call adapter.notifyDatasetChanged(). This will inform the adapter that its own data has changed and it must refresh views
Yes, ideally, the population of the adapter should be coming from the outside. The adapter should really just take in a list of data and map that data to the views. For example, some method or task in the Activity could produce a list of data (probably asynchronously...since you mentioned it) that you then pass into the adapter and then you can notifyDataSetChanged() if you need to.
I can't see your code, but if for some reason the data is truly required to be populated from inside the adapter, you could use an event bus and subscribe to it in the Activity. I would recommend going with the first option, but here are some links if you choose to use an event bus:
https://github.com/greenrobot/EventBus
http://square.github.io/otto/
As per my understanding with your question
You are not properly managed the adapter data in your activity.
If any of the data or code interlinked with your adapter data or values
Then you can start those code after you retrieve the values or data and update the view in your activity.
Please note that use Viewholders in adapter to avoid slow populating and scrolling in listviews.
Viewholders will smooth your process.
I personally suggest you that
Please go with Recyclerview and RecyclerViewAdapter.
So many Android developers are using it.
If you have background tasks in adapter you can prefer to use RX Java or EventBus
If you provide the code
It's better for us to suggest exact solution
So I've got a Dialog, which contains some editText fields (these are spread over 3 fragments, shown by a viewpager, in case this info matters). For an edit action, I want to create that dialog with some values already put in.
At the moment I'm trying to do it like this:
editButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
GeneralSettingsInitialInputDialog GSIID = new GeneralSettingsInitialInputDialog();
Bundle args = new Bundle();
args.putString("name", TitleTV.getText().toString());
args.putString("ip", IPaddressET.getText().toString());
args.putString("port", PortET.getText().toString());
args.putString("username", UsernameET.getText().toString());
args.putString("pass", PasswordET.getText().toString());
Log.d(tag, args.toString());
GSIID.setArguments(args);
GSIID.show(((Activity) context).getFragmentManager(), "GSIID");
This shows the onClickListener for the edit button (which is contained in a recyclerView. This particular bit comes from my Adapter).
After that, I tried this in the onCreateDialog method for the GSIID dialogFragment:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
ma = (MainActivity) getActivity();
dbHandler = DBHandler.getInstance(getActivity());
view = inflater.inflate(R.layout.fragment_generalsettingsviewpager, null);
mPager = (ViewPager) view.findViewById(R.id.pager);
mPager.setOffscreenPageLimit(3);
mPagerAdapter = new TestAdapter();
mPager.setAdapter(mPagerAdapter);
if (getArguments() != null) {
((EditText) view.findViewById(R.id.IDName)).setText(getArguments().getString("name"));
((EditText) view.findViewById(R.id.IDIPaddress)).setText(getArguments().getString("ip"));
((EditText) view.findViewById(R.id.IDPort)).setText(getArguments().getString("port"));
((EditText) view.findViewById(R.id.IDUsername)).setText(getArguments().getString("username"));
((EditText) view.findViewById(R.id.IDPassword)).setText(getArguments().getString("pass"));
}
// Build Dialog
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(view)
.setTitle("Setup Device")
.setMessage("Please add all required details for your Raspberry Pi here.")
.setPositiveButton("Next", null)
.setNegativeButton("Cancel", null);
return builder.show();
}
This returned a NPE, saying I was trying to use setText on a null, so view.findViewById() is returning null. I thought I'd fix that by moving this code to the onStart() method, to make sure everything is there before I try to set stuff on it, but I'm still getting the same error.
All this time, I'm noticing that the dialog does NOT open before the error occurs, so I'm guessing the findViewById() method is still called too soon, but I don't know how to fix that.
I have tested to make sure my code is not broken, by having the above code run when a button on the GSIID dialog is pressed (so the dialog is opened then). This did indeed work.
So, basically: How can I prevent this findViewById method from being called too early?
Most likely by looking up views in onCreateView() by calling the lookups on the view you're returning from this method.
You need to master the life-cycle of an Activity in android this link and this link can help you to understand the sequence of function calls in each step of the life-cycle.
In most cases you have your views in onCreatView() so it is reasonable to put your findViewById there but in other cases you should make sure the view has been inflated before you call findViewById
Well, my day is saved, thanks to this post.
Basically, you just need a method inside your custom PagerAdapter that returns the view for the index you give it.
CustomAdapter
New: Constructor (I believe that's what it's called)
private View view0 = null;
private View view1 = null;
private View view2 = null;
private View viewError = null;
public TestAdapter(LayoutInflater inflater) {
view0 = inflater.inflate(R.layout.fragment_generalsettingsinputdialog1, null);
view1 = inflater.inflate(R.layout.fragment_generalsettingsinputdialog2, null);
view2 = inflater.inflate(R.layout.fragment_generalsettingsinputdialog3, null);
viewError = inflater.inflate(R.layout.fragment_viewpagererror, null);
}
Changed: instantiateItem()
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View instView = getViewAtPosition(position);
instView.setTag("layoutThingy"+position);
container.addView(instView);
instView.requestFocus();
return instView;
}
New: getViewAtPosition()
public View getViewAtPosition(int position) {
View view = null;
switch(position) {
case 0:
view = view0;
break;
case 1:
view = view1;
break;
case 2:
view = view2;
break;
default:
view = viewError;
}
return view;
}
Other stuff
When initialising PagerAdapter, make sure you pass a LayoutInflater as an argument. For me it was like this: mPagerAdapter = new TestAdapter(getActivity().getLayoutInflater());
Now, I did this in my onStart() method, but I'm guessing you can do this pretty much everywhere.
View page1 = mPagerAdapter.getViewAtPosition(0);
View page2 = mPagerAdapter.getViewAtPosition(1);
View page3 = mPagerAdapter.getViewAtPosition(2);
if (getArguments() != null) {
((EditText) page1.findViewById(R.id.IDName)).setText(getArguments().getString("name"));
((EditText) page2.findViewById(R.id.IDIPaddress)).setText(getArguments().getString("ip"));
((EditText) page2.findViewById(R.id.IDPort)).setText(getArguments().getString("port"));
((EditText) page3.findViewById(R.id.IDUsername)).setText(getArguments().getString("username"));
((EditText) page3.findViewById(R.id.IDPassword)).setText(getArguments().getString("pass"));
}
This properly finds all my EditText's, and should properly find everything I put in my ViewPager. Great! Thanks all for trying to help me, and of course a big thank you to cYrixmorten, with his great post.
I have an app that uses three Activities. I've created in the first one a Thread that checks the connection with the server and when the app cant reach the server it shows a Popup.
The thing is that when I go from the Activity1 to the Activity2 and I lose the connection, I'm getting a WindowManager$BadTokenException.
I've tried with PopupWindow and with AlertDialog but I have the same problem, I can't give them the current Activity.
Alert Dialog:
AlertDialog.Builder builder1 = new AlertDialog.Builder(getApplicationContext());
builder1.setMessage("Se ha hecho el cierre diario, es necesario reiniciar la aplicación.");
builder1.setCancelable(true);
builder1.setPositiveButton("Ok",
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
java.lang.System.exit(0);
}
});
AlertDialog alert11 = builder1.create();
alert11.show();
PopupWindow:
final Activity context = Activity_Start.this;
final boolean Reset = reset;
// Inflate the popup_layout.xml
LinearLayout viewGroup = (LinearLayout) context.findViewById(R.id.popup_mensaje_error);
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View popup_error = layoutInflater.inflate(R.layout.mensaje_error, viewGroup, false);
// Creating the PopupWindow
final PopupWindow popupW_error = new PopupWindow(context);
popupW_error.setContentView(popup_error);
In both cases I have the same error and I'm almost 100% sure that is cause getApplicationContext() is no enough to get what the app needs.
Can someone help me? Thanks!!
Android documents suggests to use getApplicationContext();
but it will not work instead of that use your current activity while instantiating AlertDialog.Builder or AlertDialog or Dialog...
Try
AlertDialog.Builder builder1 = new AlertDialog.Builder(Activity_Start.this);
instead of
AlertDialog.Builder builder1 = new AlertDialog.Builder(getApplicationContext());
And also use
final Context context = Activity_Start.this;
instead of
final Activity context = Activity_Start.this;
The dialog is tied to this particular activity, and not the entire application. Generally use Activity.this when creating objects whose scope is just the activity. Use Application context when you are creating objects whose scope is beyond the current activity.
Hope this helps!
I'm parsing a web service to display in a listView backed by my own subclass of ArrayAdapter. The data is static ArrayList<Wait> in Application.java. You'll see it referenced by App.getWaits().
I use a simple refresh method for when there's new data. I've confirmed that it's being updated but it only renders if I navigate away and then return to the view.
In the past I've been able to refresh the listView by calling notifyDataSetChanged() on the adapter but right now none of these have worked for me. Thanks for taking a look... any ideas!?
//1 This is how I'd normally update the listView dynamically, but not tonight.
adapter.notifyDataSetChanged();
//2 It's the same thing really, so no good.
((WaitAdapter) list.getAdapter()).notifyDataSetChanged();
//3 Saw this as the answer to a similar question, doesn't work.
adapter.getWaits().clear();
adapter.getWaits().addAll(App.getWaits());
adapter.notifyDataSetChanged();
//4 Called in onCreate but tried a 2nd time in refresh() to manually reset adapter, doesn't work.
adapter = new WaitAdapter(getHost().getApplicationContext(), App.getWaits());
list.setAdapter(adapter);
//5 Kinda the same thing, new adapter, reset adapter... also no good.
WaitAdapter adapter = new WaitAdapter(getHost().getApplicationContext(), App.getWaits());
list.setAdapter(adapter);
//6 I read ArrayAdapter keeps its own reference to initial data object but this fails too.
adapter = null;
adapter = new WaitAdapter(getHost().getApplicationContext(), App.getWaits());
list.setAdapter(adapter);
*Update to share my WaitAdapter.java.
public class WaitAdapter extends ArrayAdapter<Wait> {
private LayoutInflater inflater;
private ArrayList<Wait> waits;
public WaitAdapter(Context context, ArrayList<Wait> data) {
super(context, R.layout.list_item_wait, data);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
waits = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item_wait, parent, false);
holder = new ViewHolder();
holder.checkpointName = (TextView) convertView.findViewById(R.id.checkpointName);
holder.delayAmount = (TextView) convertView.findViewById(R.id.delayAmount);
holder.timeReported = (TextView) convertView.findViewById(R.id.timeReported);
holder.dateReported = (TextView) convertView.findViewById(R.id.dateReported);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Wait wait = waits.get(position);
holder.checkpointName.setText(wait.getName());
holder.delayAmount.setText(wait.getDelayInMinutes());
holder.timeReported.setText(wait.getTimeLabel());
holder.dateReported.setText(wait.getDateLabel());
return convertView;
}
#Override
public boolean isEnabled(int position) {
return false;
}
static class ViewHolder {
TextView checkpointName;
TextView delayAmount;
TextView timeReported;
TextView dateReported;
}
}
12/14/14 Update: General implementation background.
At launch the App class starts WaitAsyncTask, which parses remote XML to fill its ArrayList waits. I'll access these waits in a few places so this way I keep them global.
WaitFragment, working with WaitAdapter, displays waits in a ListView and listens for changes to waits. User's can post waits to the web service via an AlertDialog. A successful response executes WaitAsyncTask again, updating the waits object, triggering a WaitFragment refresh().
Console logs and the web service confirm this flow of control and that waits gets updated. If I leave WaitFragment then return, it shows the updated waits. The code posted with comments #1-6 are what I've tried inside of the refresh() to update the ListView.
I use this general approach with other data and fragments in this app and their UIs refresh as intended, but none are listViews. I'm not sure I could post more source without redacting most of it but I'll share my findings once I get it working. I haven't had trouble with ListView before, but it'll be something embarrassing for sure. Thanks to everyone who took a little time :)
Just create a method in Adapter class to update/refresh the listview as follows,
public class WaitAdapter extends ArrayAdapter<Wait> {
private LayoutInflater inflater;
private ArrayList<Wait> waits;
public WaitAdapter(Context context, ArrayList<Wait> data) {
super(context, R.layout.list_item_wait, data);
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
waits = data;
}
/**
* Update content
*/
public void updateListContent(ArrayList<Wait> data)
{
waits = data;
notifyDataSetChanged();
}
}
In your acivity class, just call this adapter method to update the content. Refer the below code
Note:Dont clear the array content of the adapter.
//Dont clear the arraylist of adapter
adapter.updateListContent(App.getWaits());
This may help you.