I created an interface so I can communicate between a dialogue and a fragment.
Goal: When the user selects anything from the dialogue it should display it on a text view.
In this interface, I created an interface method, called in the main activity and passed the value the user selected in the dialogue. Along with the user selected value, in my fragment, I created a method that will set the text view to that value. However, whenever I call that method it always returns null.
I did plenty of testing with logs and found that the values being passed through my method is NOT null, everything seems to work the exact way I want it to which is odd. What confuses me even more, is that this method isn't even running, it immediately returns null before executing the code inside which is really strange to me.
Dialog Code:
public String users_time;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String time_options[] = {"10", "20", "30", "40", "50", "60", "70", "80", "90"}; // Since we know how many options there are in the array we use an array instead of an arraylist
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Choose the time");
builder.setSingleChoiceItems(time_options, -1, new DialogInterface.OnClickListener() { // check items = what index is auto selected in the dialog, use -1 bc you dont want that
#Override
public void onClick(DialogInterface dialog, int which) { // which = Index in the array
CharSequence time = time_options[which];
Log.i("this" ,"LOG 1 dialogsTime retusn" + time);
listener.onDialogInput(time);
users_time = time_options[which];
int usersTime = Integer.valueOf(users_time);
listener.grabTime(usersTime);
}
});
builder.setPositiveButton("Set Time", new DialogInterface.OnClickListener() { // positive = Ok or continue
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { // Negative = Cancel or stop
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
return builder.create(); // always return this at the end
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof DiaglogListener) {
listener = (DiaglogListener) context;
}
else {
throw new RuntimeException(context.toString()
+ " must implement DiaglogListener");
}
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
}
Main Activity Interface Method:
#Override
public void onDialogInput(CharSequence dialogsTime) {
Fragment1_timer frag1 = new Fragment1_timer();
Log.i("this" ,"LOG 2 runs successfully");
try {
frag1.setDialogTime(dialogsTime);
} catch (Exception e){
Toast.makeText(this, "Null error :/", Toast.LENGTH_SHORT).show();
}
}
Fragment Method:
public void setDialogTime(CharSequence time){
Log.i("this" ,"LOG 3 ran successfully");
text_view_time.setText(time + ":00");
}
You can't use onAttach method for Fragment to DialogFragment communication.
you will have to use "setTargetFragment" & "getTargetFragment" for that.
you can refer this answer. https://stackoverflow.com/a/32323822/9792247
Related
In my app I have implemented this custom dialog (which has a fairly complex layout) by extending DialogFragment. I expect this dialog to pop up when I click a button in my layout. (Which I have successfully achieved). But the problem is that the dialog shows up in a janky manner.
My custom dialog class:
public class CustomizeDialog extends DialogFragment implements AdapterView.OnItemSelectedListener {
// field declarations go here
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.customize_dialog, null);
builder.setView(view)
.setTitle("Customize")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("Let's go!", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction("fromDialog");
intent.putExtra("ratio",getRatio(paperSizeSpinner.getSelectedItem().toString()));
if(isOrientationSpinnerVisible){
intent.putExtra("isCustom",false);
intent.putExtra("orientation",orientationSpinner.getSelectedItem().toString());
} else {
intent.putExtra("isCustom",true);
}
intentProvider.getIntent(intent);
}
});
widthEditText = view.findViewById(R.id.width_et);
heightEditText = view.findViewById(R.id.height_et);
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
paperSizeSpinner = view.findViewById(R.id.paper_size_spinner);
orientationSpinner = view.findViewById(R.id.orientation_spinner);
// ArrayList for populating paperSize spinner via paperSizeAdapter
ArrayList<String> paperSizes = new ArrayList<>();
paperSizes.add("A0");
paperSizes.add("A1");
paperSizes.add("A2");
paperSizes.add("A3");
paperSizes.add("A4");
paperSizes.add("A5");
paperSizes.add("Custom");
// ArrayList for populating orientation spinner via orientationAdapter
ArrayList<String> orientation = new ArrayList<>();
orientation.add("Portrait");
orientation.add("Landscape");
// arrayAdapters containing arraylists to populate spinners
ArrayAdapter paperSizeAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, paperSizes);
ArrayAdapter orientationAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, orientation);
paperSizeSpinner.setAdapter(paperSizeAdapter);
orientationSpinner.setAdapter(orientationAdapter);
paperSizeSpinner.setSelection(4);
paperSizeSpinner.setOnItemSelectedListener(this);
orientationSpinner.setOnItemSelectedListener(this);
return builder.create();
}
// These are some important complex ui functionalities
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getId() == R.id.paper_size_spinner) {
if (position == 6) {
widthEditText.setEnabled(true);
heightEditText.setEnabled(true);
orientationSpinner.setEnabled(false);
isOrientationSpinnerVisible = false;
} else {
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
orientationSpinner.setEnabled(true);
isOrientationSpinnerVisible = true;
}
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
// interface used to communicate with the parent activity
public interface IntentProvider {
// this method is used to provide the intent to the parent activity
void getIntent(Intent intent);
}
// instantiating the interface object and throwing error if parent activity does not implement this interface
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
intentProvider = (IntentProvider) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement IntentProvider");
}
}
}
MainActivity class:
public class MainActivity extends AppCompatActivity implements CustomizeDialog.IntentProvider {
// field declarations go here
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.image);
// instantiating the dialog
final CustomizeDialog dialog = new CustomizeDialog();
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// showing the dialog on click
dialog.show(getSupportFragmentManager(),"");
}
});
}
// via this method I receive the intent from the dialog
// I know intent might not be the best option for this function but let's let it be here for now
#Override
public void getIntent(Intent intent) {
ratio = intent.getFloatExtra("ratio",3);
isCustom = intent.getBooleanExtra("isCustom",false);
orientation = intent.getStringExtra("orientation");
launchChooser();
}
}
Let me know in the comments if you want the layout code for the dialog.
What I tried:
Implementing threading so that my dialog is ready in a background thread and show it onButtonClick. But this is not allowed in general as any other thread except UI thread aren't supposed to touch UI related events.
Using onCreateView instead of onCreateDialog to inflate the layout directly.
Making the dialog a global variable, initialized it in onCreate and then show the dialog onButtonClick.
Switched to CONSTRAINT LAYOUT
Using an activity as a dialog by setting the dialog theme to the activity in the manifest file.
Launched my app in a device with better hardware than mine.
BUT NOTHING WORKED
What I want:
Why is my dialog janky? and what I need to do to make the dialog pop up faster?
In case anybody wants here's the link to my app repo on github.
AlertDialog and DialogFragment frameworks are slow because they need to some time to do calculations and fragment stuffs. So a solution to this problem is, using the Dialog framework straight away.
Use the Dialog framework's constructor to initialize a Dialog object like this:
Dialog dialog = new Dialog(context, R.style.Theme_AppCompat_Dialog);
// the second parameter is not compulsory and you can use other themes as well
Define the layout and then use dialog.setContentView(R.layout.name_of_layout).
Use dialog.findViewById(R.id.name_of_view) to reference views from the dialog's layout file
And then implement the logic just like anyone would do in an activity class. Find out the best implementation for your use case by reading the official documentation.
I spent all day trying to make this up, but I can't..
This is the problem: I want an yes/no AlertDialog that doesn't disappear on orientation change, so I decided to use DialogFragment.
So I prepared the code and for the first use, everything with it is just perfect, but if I hit the button (that should show the dialog) once more (second, third and further times) the dialog doesn't show up! Though I can see from logs it actually makes instances and I have no errors, it's there, I just can't see it!
If I fold the app, or turn off / on the screen (I believe it's about calling onResume() method) the dialogs shows up, all of them (depending how much time I hit the button), it seems like a some displaying issue or refreshing problem maybe.. I don't know, so I came here hoping to get some help.
About my code:
I have a ListView with custom adapter, and in that adapter I have the code to show the an AlertDialog (DialogFragment) - as part of an ImageButton onClickListener.
The code for DialogFragment that I use:
public static class cMyDialogFragment extends DialogFragment {
public static cMyDialogFragment newInstance(int title) {
cMyDialogFragment frag = new cMyDialogFragment();
Bundle args = new Bundle();
args.putInt("title", title);
frag.setArguments(args);
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int title = getArguments().getInt("title");
this.setCancelable(true);
setRetainInstance(true);
return new AlertDialog.Builder(getActivity())
// .setIcon(R.drawable.alert_dialog_icon)
.setTitle(title)
.setPositiveButton(R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((ActAudiorecords) getActivity()).doPositiveClick();
}
}
)
.setNegativeButton(R.string.no,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((ActAudiorecords) getActivity()).doNegativeClick();
}
}
)
.create();
}
}
The code for calling the dialog to show up (within the custom ListView adapter):
public View getView(final int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (vi == null)
vi = inflater.inflate(R.layout.recordings_row, null);
TextView tvDate = (TextView) vi.findViewById(R.id.tv_Recordings_r_date);
tvDate.setText(ainfo.get(position).getDate());
ImageButton ibtn_play = (ImageButton) vi.findViewById(R.id.ibtnPlay);
final String localPath = dPath + File.separator + ainfo.get(position).getFName();
ImageButton ibtn_remove = (ImageButton) vi.findViewById(R.id.ibtnRecordings_r_remove);
ibtn_remove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
curFName = ainfo.get(position).getFName();
curID = ainfo.get(position).getID();
showDialog();
}
});
ibtn_play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
play(localPath);
}
});
return vi;
}
The additional functions:
void showDialog() {
DialogFragment newFragment = cMyDialogFragment.newInstance(
R.string.do_you_want_to_remove_the_file);
newFragment.show(getFragmentManager(), "dialog");
}
public void doPositiveClick() {
// Do stuff here.
ps_db.delete(const_audiorecords_tname, "id = " + curID, null);
new File(dPath + File.separator + curFName).delete();
Toast.makeText(ActAudiorecords.this, getString(R.string.audiorecord_has_been_removed), Toast.LENGTH_LONG).show();
ActAudiorecords.this.onCreate(null); //Restarting the Activity to refresh the LV
Log.i("FragmentAlertDialog", "Positive click!");
}
public void doNegativeClick() {
// Do stuff here.
Toast.makeText(ActAudiorecords.this, getString(R.string.the_operation_has_been_cancelled), Toast.LENGTH_LONG).show();
Log.i("FragmentAlertDialog", "Negative click!");
}
I have no onResume() in my code.
I tried to use different codes for DialogFragment but it doesn't matter.
It was all due to the line:
ActAudiorecords.this.onCreate(null);
So after calling onCreate() with null as savedInstance it have been removing link to the DialogFragment (as I can understand), it was the line for refreshing the Activity, I solved the problem by splitting the code in onCreate() to which should be called only once (at a start of Activity) and the part that should be called in every refreshing point (such as GUI settings and etc).
I believe I could also save the current Bundle and pass it to onCreate() instead of null and it would work as good as now, but I thought that calling an function is much better for data updating than calling onCreate() over and over, so that's it, thank you all who wanted to help.
I am trying to implement confirm message to exit from my app. I need this, because someone can accidentally click back button more than one time and this will close the app and in case of low memory it will be killed after that because now it is not in foreground.
I have tried different approaches, but some of them required a lot of checks, others doesn't work at all.
I have tried to use onKeyDown event, onBackPressed ...
The problem because I am working not with only with activities, but also with nested fragments (inside activities).
I need to handle the last on back pressed click before exit, so it means that all fragments of current activity have to be popped up from the stack, than activity has to be popped up also and that if this is not last activity do the same for the preceding activity until this is not last activity and all fragments are popped up in it.
How can I implement this ? I have tried to do this using backstack, but unfortunately haven't succeed.
Please suggest what is the best to handle such type of event. I guess that there is an easy way to do this.
Thanks everyone for answers and suggestions.
I have reached the desired result by using fragment count in the stack.
As far as my Main Activity will be the first activity and the last before exit, I can override onBackPressed method inside it.
So solution is simple.
public class MainActivity extends BaseSingleFragmentActivity {
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.title_exit_message)
.setMessage(R.string.message_exit)
.setPositiveButton(R.string.button_text_yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
MainActivity.super.onBackPressed();
}
})
.setNegativeButton(R.string.button_text_no, null)
.show();
} else {
MainActivity.super.onBackPressed();
}
}
}
So this will work only if your activity is last in Activity Stack , so you have to override it your launcher activity, not in some base activity class or other.
A little bit improved solution to my mind.
package com.crosp.solutions.qrcodereader.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import com.crosp.solutions.qrcodereader.R;
import com.crosp.solutions.qrcodereader.constants.FragmentConstants;
/**
* Created by crosp on 7/9/15.
*/
public class ConfirmationDialog extends DialogFragment implements DialogInterface.OnClickListener {
private OnConfirmDialogClickListener mOnConfirmDialogListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mOnConfirmDialogListener = (OnConfirmDialogClickListener) activity;
} catch (ClassCastException ex) {
Log.e(getString(R.string.error_tag), "Activty has to implement " + OnConfirmDialogClickListener.class.getSimpleName() + " interface");
}
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setPositiveButton(R.string.button_text_yes, this)
.setNegativeButton(R.string.button_text_no, this);
Bundle bundle = getArguments();
String message = getString(R.string.message_exit);
String title = getString(R.string.title_exit_message);
int iconId = android.R.drawable.ic_dialog_alert;
if (bundle != null) {
String argumentMessage = bundle.getString(FragmentConstants.Arguments.DIALOG_MESSAGE_ARGUMENT);
String argumentTitle = bundle.getString(FragmentConstants.Arguments.DIALOG_TITLE_ARGUMENT);
int argumentIconId = bundle.getInt(FragmentConstants.Arguments.DIALOG_ICON_ID_ARGUMENT);
message = argumentMessage != null ? argumentMessage : message;
title = argumentTitle != null ? argumentTitle : title;
iconId = argumentIconId != 0 ? argumentIconId : iconId;
}
builder.setIcon(iconId);
builder.setMessage(message);
builder.setTitle(title);
return builder.create();
}
#Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
mOnConfirmDialogListener.onConfirmClick();
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
mOnConfirmDialogListener.onCancelClick();
}
}
public interface OnConfirmDialogClickListener {
void onConfirmClick();
void onCancelClick();
}
}
And in activity
public class MainActivity extends BaseSingleFragmentActivity implements ExitConfirmDialogFactory.OnExitDialogClickListener {
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
Bundle arguments = new Bundle();
if(mExitDialog==null) {
arguments.putInt(FragmentConstants.Arguments.DIALOG_ICON_ID_ARGUMENT, android.R.drawable.ic_dialog_alert);
arguments.putString(FragmentConstants.Arguments.DIALOG_MESSAGE_ARGUMENT, getString(R.string.message_exit));
arguments.putString(FragmentConstants.Arguments.DIALOG_TITLE_ARGUMENT, getString(R.string.title_exit_message));
DialogFragment exitDialog = new ConfirmationDialog();
exitDialog.setArguments(arguments);
mExitDialog = exitDialog;
}
mExitDialog.show(getSupportFragmentManager(),FragmentConstants.Tags.EXIT_DIALOG_TAG);
} else {
super.onBackPressed();
}
}
#Override
public void onConfirmClick() {
super.onBackPressed();
}
#Override
public void onCancelClick() {
}
Basically override onBackPressed() in the Main Activity and avoid calling the parent super.onBackPressed() if the user selects "No" to exiting the app.
Code suggestion:
#Override
public void onBackPressed() {
new AlertDialog.Builder(this)
.setTitle("Exiting app?")
.setPositiveButton("Yes", new OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
// user really do want to exit
MainActivity.super.onBackPressed();
}
}).create().show();
// If negative, show a Fragment or do nothing
}
I am not sure but I think you can use an integer to count your fragments, increase it on adding a new fragment and decrease on every back press. It may be like that:
#Override public void onBackPressed() {
if( fragCount > 0) {
--fragCount;
super.onBackPressed();
return;
}
new AlertDialog.Builder(this) .setTitle("Exiting app?") .setPositiveButton("Yes", new OnClickListener() { public void onClick(DialogInterface arg0, int arg1) { // user really do want to exit
MainActivity.super.onBackPressed(); } }).create().show();
}
Note: Sorry for bad typing I am on phone.
I am trying to implement custom DialogFragment. But when I try to show it I am getting NullPointerException. Also as I have noticed onCreateDialog is never implictly called.
What is wrong with it. I have read official manual, and followed all steps in it DialogFragment
Here is my code for custom Dialog Fragment
public class UserInputDialogFragment extends DialogFragment {
InputDialogListener mListener;
private EditText mTextEdit;
public UserInputDialogFragment() {
super();
}
// Use this instance of the interface to deliver action events
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
View mainView = inflater.inflate(R.layout.dialog_input, null);
builder.setView(mainView);
mTextEdit = (EditText) mainView.findViewById(R.id.user_input);
if (mTextEdit==null) {
Log.e("ERROR","Text edit is null");
}
// Add action buttons
builder.setPositiveButton(R.string.ok_btn, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
mListener.onDialogPositiveClick(UserInputDialogFragment.this,mTextEdit.getText().toString());
}
});
builder.setNegativeButton(R.string.cancel_bnt, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mListener.onDialogNegativeClick(UserInputDialogFragment.this,mTextEdit.getText().toString());
UserInputDialogFragment.this.getDialog().cancel();
}
});
return builder.create();
}
public interface InputDialogListener {
public void onDialogPositiveClick(DialogFragment dialog, String userInput);
public void onDialogNegativeClick(DialogFragment dialog, String userInput);
}
public void showAndAddHint(FragmentManager manager,String tag,String hint) {
this.onCreateDialog(null);
mTextEdit.setHint(hint);
this.show(manager,tag);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Verify that the host activity implements the callback interface
try {
// Instantiate the NoticeDialogListener so we can send events to the host
mListener = (InputDialogListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement InputDialogListener");
}
}
}
And I am trying to show dialog this way.
UserInputDialogFragment userInputDialogFragment = new UserInputDialogFragment();
userInputDialogFragment.showAndAddHint(getFragmentManager(),"Please enter phone number",task.phoneNumber);
And here is NullPointerException mTextEdit is null.
public void showAndAddHint(FragmentManager manager,String tag,String hint) {
this.onCreateDialog(null);
mTextEdit.setHint(hint);
this.show(manager,tag);
}
The showAndAddHint method won't work as written. What you should do instead is:
1 - Set a member variable mHint = hint;
2 - Call show() exactly the way you're doing it now.
3 - Read the member variable mHint in on create dialog and use it to set the edit text hint.
Don't call onCreateDialog explicitly because the show method does that for you when needed.
Im at my wits end here. I have a Class which Implements the OnClickListener cous i need the same action on Buttons accros my Application. This used to work just fine. But since I added some functionality by getting some needed data from the app preferences. startActivity throws a null pointer exception.Here is the class:
//Imports
public class CallClickListener extends Activity implements View.OnClickListener {
protected AppPreferences appPrefs;
String contactPersonName;
String contactPersonTelephone;
String name;
public CallClickListener(Context context){
Log.d("TRACE", "init CallClick");
appPrefs = new AppPreferences(context);
try {
JSONObject object = appPrefs.getConsultantObject();
contactPersonName = object.getString("contactPersonName");
contactPersonTelephone = object.getString("contactPersonTelephone");
name = object.getString("name");
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onClick(View view) {
final View v = view;
AlertDialog.Builder alert = new AlertDialog.Builder(view.getContext());
alert.setTitle("Anrufen");
alert.setMessage("Kontakt für " + name + ", " + contactPersonName + " anrufen");
alert.setPositiveButton("Anrufen", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:"+contactPersonTelephone));
startActivity(callIntent);// this line throws the exception
}
});
alert.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(v.getContext(), "Abbruch", Toast.LENGTH_SHORT).show();
}
});
alert.show();
}
}
The Strings are all there from appPrefs, i also tried with hardcoding a phonenumber just incase. the Alert works fine, but as soon as i hit the positive Button, the app crashes
I add the Listener like this:
bCall.setOnClickListener(new CallClickListener(getApplicationContext()));
I added the necessary Call permissions.
I'm fairly new to Android dev, what am I missing?
Do this.... make the context object that you passed in the constructor into a field variable. and change startActivity to context.startActivity. It will work then.
EDIT: Highlighting the full solution.
bCall.setOnClickListener(new CallClickListener(getApplicationContext()));
should be changed to YourActivityClass.this instead of getApplicationContext.
Start Activity in the same task does not work with a context object that is not an Activity. So you need to either change the context to Activity or you start the activity in a new task. Also without calling startActivity on the context provided to your constructor you were getting the NPE because your CallClickListerner has no context.
Use activity context. Also check if you have initialized bCall. If you have not you will get NullPointerException.
bCall.setOnClickListener(ActivityName.this);
Also check this link to know when to use activity context and when to use application context
When to call activity context OR application context?
Edit:
Make sure you have added permission in manifest file
<uses-permission android:name="android.permission.CALL_PHONE" />
For reference use the below. My Class extends Activity
Button b= (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v1) {
// TODO Auto-generated method stub
final View v = v1;
AlertDialog.Builder alert = new AlertDialog.Builder(v.getContext());
alert.setTitle("Anrufen");
alert.setMessage("Kontakt für " );
alert.setPositiveButton("Anrufen", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:8095992052"));
startActivity(callIntent);// this line throws the exception
}
});
alert.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(v.getContext(), "Abbruch", Toast.LENGTH_SHORT).show();
}
});
alert.show();
}
});