My app shows many custom dialog like Yes/No or Accept/Cancel decissions and, while I was coding, I realized that there are so much code repeated, following the same schema.
I want to build a general class but I don't know how to do it or, more exactly, the correct way that I have to do it(interfaces, abstract classes, inheritance, static classes, ...)
This is my current class:
public class DialogTwoOptions extends Dialog {
TextView title_tv;
// Button yes_btn, no_btn;
public DialogTwoOptions(Context context)
{
super(context);
setContentView(R.layout.dialogo_sino); // a simple layout with a TextView and Two Buttons
title_tv = (TextView) findViewById(R.id.dialogo_titulo_sino);
// yes_btn = (Button) findViewById(R.id.dialogo_aceptar);
// no_btn = (Button) findViewById(R.id.dialogo_cancelar);
View v = getWindow().getDecorView();
v.setBackgroundResource(android.R.color.transparent);
}
public void quitDialog(View v) {
if (isShowing()) dismiss();
}
public void setTitle(String title) {
title_tv.setText(title);
}
}
And this is what I am doing when I need to use this class:
final DialogTwoOptions dialog = new DialogTwoOptions(this);
Button yes = (Button) dialog.findViewById(R.id.dialog_yes_btn);
Button no = (Button) dialog.findViewById(R.id.dialog_no_btn);
yes.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v) {
dialog.dismiss();
// Do something
}
});
no.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v) {
dialog.dismiss();
// Do something
}
});
dialog.show();
I am sure that it is improvable, but how could you do this?
Thanks
First create an Base DialogFragment to keep hold of the instance of the Activity. So when the Dialog is attached to the Activity , you will know the instance of the Activity which created it.
public abstract class BaseDialogFragment<T> extends DialogFragment {
private T mActivityInstance;
public final T getActivityInstance() {
return mActivityInstance;
}
#Override
public void onAttach(Activity activity) {
mActivityInstance = (T) activity;
super.onAttach(activity);
}
#Override
public void onDetach() {
super.onDetach();
mActivityInstance = null;
}
}
Then, create a GeneralDialogFragment which extends the BaseDialogFragment
public class GeneralDialogFragment extends BaseDialogFragment<GeneralDialogFragment.OnDialogFragmentClickListener> {
// interface to handle the dialog click back to the Activity
public interface OnDialogFragmentClickListener {
public void onOkClicked(GeneralDialogFragment dialog);
public void onCancelClicked(GeneralDialogFragment dialog);
}
// Create an instance of the Dialog with the input
public static GeneralDialogFragment newInstance(String title, String message) {
GeneralDialogFragment frag = new GeneralDialogFragment();
Bundle args = new Bundle();
args.putString("title", title);
args.putString("msg", message);
frag.setArguments(args);
return frag;
}
// Create a Dialog using default AlertDialog builder , if not inflate custom view in onCreateView
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(getArguments().getString("title"))
.setMessage(getArguments().getString("message"))
.setCancelable(false)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Positive button clicked
getActivityInstance().onOkClicked(GeneralDialogFragment.this);
}
}
)
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// negative button clicked
getActivityInstance().onCancelClicked(GeneralDialogFragment.this);
}
}
)
.create();
}
}
If you need to use your own custom layout for dialog,then inflate a layout in onCreateView and remove onCreateDialog . But Add the click listeners in onCreateView like i explained in onCreateDialog
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_dialog, container, false);
return view;
}
Then , In your Activity need to implement an interface to handle the action in dialog
public class TryMeActivity extends
FragmentActivity implements GeneralDialogFragment.OnDialogFragmentClickListener {
#Override
public void onOkClicked(GeneralDialogFragment dialog) {
// do your stuff
}
#Override
public void onCancelClicked(GeneralDialogFragment dialog) {
// do your stuff
}
}
Finally, Show the Dialog from your Activity when required, like this
GeneralDialogFragment generalDialogFragment =
GeneralDialogFragment.newInstance("title", "message");
generalDialogFragment.show(getSupportFragmentManager(),"dialog");
Hope this helps. I am sure this approach is one of the optimized way, but there could be also different approaches .
I faced a problem like you. And all in stackoverflow does not meet what I want. So I create my own Dialog Class and it can use like AlertDialog.Builder class.
In my dialogxml.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/drconner">
<LinearLayout
android:id="#+id/under"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/malertTitle"
android:layout_width="match_parent"
android:layout_height="50dp"
android:padding="5dp"
android:textSize="25sp"
android:textColor="#ffffff"
android:drawablePadding="2dp"
android:background="#color/colorPrimaryDark"
/>
<TextView
android:id="#+id/aleartMessage"
android:layout_width="match_parent"
android:layout_height="75dp"
android:padding="5dp"
android:textSize="18sp"
android:textColor="#color/colorAccent"/>
</LinearLayout>
<LinearLayout
android:layout_below="#+id/under"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp"
android:orientation="horizontal">
<Button
android:id="#+id/aleartYes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<Button
android:id="#+id/aleartNo"
android:layout_marginLeft="30dp"
android:layout_marginStart="30dp"
android:layout_marginRight="3dp"
android:layout_marginEnd="3dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
For Dialog Shape I create just simple shape xml - drconner.xml
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="5dp"/>
<stroke android:color="#color/colorPrimaryDark" android:width="2dp"/>
</shape>
For custom Alert I create Alear.java as follow
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;
/**
* Created by sanyatihan on 27-Dec-16.
*/
public class Alert extends Dialog {
private String message;
private String title;
private String btYesText;
private String btNoText;
private int icon=0;
private View.OnClickListener btYesListener=null;
private View.OnClickListener btNoListener=null;
public Alert(Context context) {
super(context);
}
public Alert(Context context, int themeResId) {
super(context, themeResId);
}
protected Alert(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.dialogxml);
TextView tv = (TextView) findViewById(R.id.malertTitle);
tv.setCompoundDrawablesWithIntrinsicBounds(icon,0,0,0);
tv.setText(getTitle());
TextView tvmessage = (TextView) findViewById(R.id.aleartMessage);
tvmessage.setText(getMessage());
Button btYes = (Button) findViewById(R.id.aleartYes);
Button btNo = (Button) findViewById(R.id.aleartNo);
btYes.setText(btYesText);
btNo.setText(btNoText);
btYes.setOnClickListener(btYesListener);
btNo.setOnClickListener(btNoListener);
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void setIcon(int icon) {
this.icon = icon;
}
public int getIcon() {
return icon;
}
public void setPositveButton(String yes, View.OnClickListener onClickListener) {
dismiss();
this.btYesText = yes;
this.btYesListener = onClickListener;
}
public void setNegativeButton(String no, View.OnClickListener onClickListener) {
dismiss();
this.btNoText = no;
this.btNoListener = onClickListener;
}
}
To use this Alert class, just simple as the use of AlertDialog.Builder class
for example :
final Alert mAlert = new Alert(this);
mAlert.setTitle("This is Error Warning");
mAlert.setIcon(android.R.drawable.ic_dialog_alert);
mAlert.setMessage("Do you want to delete?");
mAlert.setPositveButton("Yes", new View.OnClickListener() {
#Override
public void onClick(View view) {
mAlert.dismiss();
//Do want you want
}
});
mAlert.setNegativeButton("No", new View.OnClickListener() {
#Override
public void onClick(View view) {
mAlert.dismiss();
//Do want you want
}
});
mAlert.show();
The main thing is you should call dismiss() function in your onClick. I hope this may help to you. And let me know if this is what you want or not. You can change the layout as you want in dialogxml.xml.
I have been using this for some time.
Calling the alert dialog inside an activity, where alertDialog is a static function in a class called Misc:
Misc.alertDlg(this, "Confirm", "Delete the file?", "Yes", null, "Cancel",
(DialogInterface dialog, int which) -> {
if(which == Misc.BTN_POS)
deleteYourFile()
});
}
And the alert dialog function (a static function in a class called Misc:
static public void alertDlg(Context context, String title, String msg, String btnPos, String btnNeutral, String btnNeg, DialogInterface.OnClickListener ocListener) {
Builder db = new AlertDialog.Builder(context);
db.setTitle(title);
db.setMessage(msg);
if (btnPos != null) db.setPositiveButton(btnPos, ocListener);
if (btnNeutral != null) db.setNeutralButton(btnNeutral, ocListener);
if (btnNeg != null) db.setNegativeButton(btnNeg, ocListener);
db.setIcon(android.R.drawable.ic_dialog_alert);
db.show();
}
But I have just recently converted it to kotlin.
Calling the alert dialog (in Kotlin):
Misc.alertDlg(this, "Confirm", "Delete the file?", "Yes", null, "Cancel"){
which-> if(which == Misc.BTN_POS) deleteYourFile()
}
And the alert dialog function (a function in an object called Misc):
fun alertDlg(context: Context, title: String, msg: String, btnNeg: String?, btnNeutral: String?, btnPos: String?,
onClickCallback: (which: Int) -> Unit) {
val ocListener = DialogInterface.OnClickListener() {dialog, which ->
onClickCallback(which)
}
val db = AlertDialog.Builder(context)
db.setTitle(title)
db.setMessage(msg)
if (btnPos != null) db.setPositiveButton(btnPos, ocListener)
if (btnNeutral != null) db.setNeutralButton(btnNeutral, ocListener)
if (btnNeg != null) db.setNegativeButton(btnNeg, ocListener)
db.setIcon(android.R.drawable.ic_dialog_alert)
db.show()
}
I have also been using a similar method to show a text input dialog.
You can use AlertDialog and AlertDialog.Builder.
new AlertDialog.Builder(context)
.setTitle("some_title")
.setMessge("some_message")
.setNegativeButton("No", null)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(int which) {
// do some action
}
})
.show();
try below code:
calling way
new CustomDialog().makeDialog(Activity.this,"pass value from diffrent-2 ");
class CustomDialog
public class CustomDialog
{
public void makeDialog(Context con, String value)
{
final DialogTwoOptions dialog = new DialogTwoOptions(con);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.ur_xml);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
// set the custom dialog components - text, image
// and button
dialog.setCanceledOnTouchOutside(false);
Button yes = (Button) dialog.findViewById(R.id.dialog_yes_btn);
Button no = (Button) dialog.findViewById(R.id.dialog_no_btn);
yes.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
dialog.dismiss();
// Do something
if (value.equals("1"))
{
}
else if (value.equals("1"))
{
}
// do more condition
}
});
no.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
dialog.dismiss();
// Do something
if (value.equals("1"))
{
}
else if (value.equals("1"))
{
}
// do more condition
}
});
dialog.show();
}
}
package com.example.jojo.gridview;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.Window;
import android.widget.ImageView;
import android.widget.TextView;
public class DialogClass extends Dialog {
Bitmap b;
String n;
public DialogClass(Context context,Bitmap img,String name) {
super(context);
b=img;
n=name;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.dialog_style);
ImageView image= (ImageView) findViewById(R.id.imageView2);
TextView text= (TextView) findViewById(R.id.textView2);
image.setImageBitmap(b);
text.setText(n);
}
}
Related
I am building a quiz app that has two types of questionnaires. I have a DialogAlert that allows the user to choose which questionnaire (two options: either "history" or "chemistry") they want to complete and have the results display in a fragment.
My goal is to be able to display the textview ("history" or "chemistry") that the questionnaire they selected in the result fragment.
I have a Dialog class:
public class DialogAlert extends DialogFragment {
private Context context;
String selection;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String[] items = {"History", "Chemistry"};
AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
builder.setTitle("Select a topic to complete")
.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
selection = items[which];
}
})
// Set the action buttons
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
switch (selection)
{
case("History"):
Intent intent_hist = new Intent(getActivity(), historyquestions.class);
startActivity(intent_hist);
break;
case("Chemistry"):
Intent intent_chem = new Intent(getActivity(), chemistryquestions.class);
startActivity(intent_chem);
break;
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
Toast.makeText(getActivity(), "No topic was selected", Toast.LENGTH_SHORT)
.show();
dialog.cancel();
}
});
return builder.create();
}
My Result fragment in which I have a placeholder textview that I want to display what the user had selected (either history or chemistry) based on the positive/ negative button above:
public class homeFragment extends Fragment{
TextView topic
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View layoutView = inflater.inflate(R.layout.fragment_home, container, false);
topic = (TextView) layoutView.findViewById(R.id.topic);
return layoutView;
}
}
How should I approach this? The challenge is that the result is shown in one of the fragments and I am unsure how would I "pass" what the user had selected in the Dialog to the Result fragment. Can someone please help?
Thank you in advance!
*Edit with the home fragment Id
<FrameLayout 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"
tools:context=".ui.home.homeFragment">
<FrameLayout
android:id="#+id/home_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<LinearLayout
android:id="#+id/layout1"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginStart="10dp"
android:layout_marginTop="270dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:background="#drawable/layout_bg"
android:orientation="vertical"
android:weightSum="300">
<TextView
android:id="#+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_weight="10"
android:fontFamily="#font/inter_regular"
android:text="Selection of topic"
android:textColor="#000000"
android:textSize="22sp" />
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/topic"
android:layout_width="340dp"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:fontFamily="#font/inter_regular"
android:text="Topic"
android:textColor="#000000"
android:textSize="20sp" />
</TableRow>
</LinearLayout>
</FrameLayout>
Edit 2023-02-13
HomeViewModel class:
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class HomeViewModel extends ViewModel {
private final MutableLiveData<String> mText;
public HomeViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is a home fragment");
}
// getText method
public LiveData<String> getText() {
return mText;
}
// function to update the mText value
public void setText(String updateText) {
mText.setValue(updateText);
}
}
homeFragment class:
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.annotation.Nullable;
public class homeFragment extends Fragment{
private HomeViewModel homeViewModel;
public View onCreateView(#NonNull LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {
View layoutView = inflater.inflate(R.layout.fragment_home, container, false);
homeViewModel =
ViewModelProviders.of(requireActivity()).get(HomeViewModel.class);
final TextView topic = (TextView)layoutView.findViewById(R.id.topic);
homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
topic.setText(s);
}
});
return layoutView;
}
Dialog class:
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProviders;
import com.example.quizzApp.MainActivity;
import com.example.quizzApp.ui.home.HomeViewModel;
public class DialogAlert extends DialogFragment {
private Context context;
String selection;
private HomeViewModel model;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(requireActivity()).get(HomeViewModel.class);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String[] items = {"History", "Chemistry"};
AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
// Set the dialog title
builder.setTitle("Select a topic to complete")
// Specify the list array, the items to be selected by default (null for none),
// and the listener through which to receive callbacks when items are selected
.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
selection = items[which];
}
})
// Set the action buttons
// User clicked OK, so save the selectedItems results somewhere
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
switch (selection)
{
case("History"):
model.setText("History");
Intent intent_hist = new Intent(getActivity(), MainActivity.class);
startActivity(intent_hist);
break;
case("Chemistry"):
model.setText("Chemistry");
Intent intent_chem = new Intent(getActivity(), MainActivity.class);
startActivity(intent_chem);
break;
}
}
})
// or return them to the component that opened the dialog
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
Toast.makeText(getActivity(), "No topic was selected", Toast.LENGTH_SHORT)
.show();
dialog.cancel();
}
});
return builder.create();
}
Scenario
You have created an App with Bottom Navigation Activity template. There should be 3 tabs Home, Dashboard, Notifications. And somehow you have opened a DialogFragment and that allows you to choose between History or Chemistry as the topic. And upon selecting either one and press OK, your Home fragment should display the topic selected.
Possible solution
If you are using Bottom Navigation Activity template, there should be a HomeViewModel class. You can make use of this HomeViewModel class, share it among different Fragments, and update the view accordingly.
HomeFragment class:
public class HomeFragment extends Fragment {
private HomeViewModel homeViewModel;
private Button btnDialog;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
// Please notice the below line, getting ViewModel using the below method can ensure
// the model can be shared across different Fragments
homeViewModel =
ViewModelProviders.of(requireActivity()).get(HomeViewModel.class);
// new ViewModelProvider(this).get(HomeViewModel.class);
View root = inflater.inflate(R.layout.fragment_home, container, false);
final TextView textView = root.findViewById(R.id.text_home);
// You have registered the ViewModel to change your HomeFragment TextView. So if the value
// of mText has been updated, the TextView in HomeFragment will also be updated
// accordingly.
homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
textView.setText(s);
}
});
// This btnDialog is just my testing button, it is a button to open your mentioned
// DialogFragment. So you can ignore this button and the openDialog(View) function.
btnDialog = root.findViewById(R.id.btnDialog);
btnDialog.setOnClickListener(this::openDialog);
return root;
}
// As mentioned above, this function can be ignored
public void openDialog(View v) {
DialogAlert frag = new DialogAlert();
frag.show(getChildFragmentManager(), "DialogAlert");
}
}
HomeViewModel class:
public class HomeViewModel extends ViewModel {
private MutableLiveData<String> mText;
public HomeViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is home fragment");
}
public LiveData<String> getText() {
return mText;
}
// You need to add a function so that you can update mText value
public void setText(String updateText) {
mText.setValue(updateText);
}
}
DialogAlert class:
public class DialogAlert extends DialogFragment {
private Context context;
String selection;
// Define a variable to hold the ViewModel class
private HomeViewModel model;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Obtain the HomeViewModel so that we can update the value of mText and sync to view in
// HomeFragment
model = ViewModelProviders.of(requireActivity()).get(HomeViewModel.class);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String[] items = {"History", "Chemistry"};
AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
builder.setTitle("Select a topic to complete")
.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
selection = items[which];
}
})
// Set the action buttons
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
switch (selection) {
case ("History"):
// Magic line, it will trigger the onChanged() in HomeFragment
model.setText("History");
dialog.dismiss();
break;
case ("Chemistry"):
// Magic line, it will trigger the onChanged() in HomeFragment
model.setText("Chemistry");
dialog.dismiss();
break;
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
Toast.makeText(getActivity(), "No topic was selected", Toast.LENGTH_SHORT)
.show();
dialog.cancel();
}
});
return builder.create();
}
}
With the above code, after you have selected the option in DialogFragment, your HomeFragment TextView should be updated at once.
Misconception
Regarding on the following code:
switch (selection)
{
case("History"):
Intent intent_hist = new Intent(getActivity(), historyquestions.class);
startActivity(intent_hist);
break;
case("Chemistry"):
Intent intent_chem = new Intent(getActivity(), chemistryquestions.class);
startActivity(intent_chem);
break;
}
The above code will start an Activity to either historyquestions Activity or chemistryquestions Activity (if you have properly created these Activity), instead of proceeding to your result homeFragment Fragment.
Additional Note
It is a good practice to follow Java naming conventions when you name classes. For example:
homeFragment should be named as HomeFragment
historyquestions should be named as HistoryQuestions
I want to create a custom dialog with a recycler view on it. If I choose the recycler view cell and press ok button in dialog, then the textview will change. I created recycler view adapter, custom dialog, but I don't know how to connect dialog and adapter and what to put in onClick function..help me please..
custom_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/writing_dialog"
android:layout_width="match_parent"
android:layout_height="400dp">
<TextView
android:id="#+id/textView8"
android:layout_width="0dp"
android:layout_height="50dp"
android:fontFamily="#font/nexon"
android:text="choose!"
android:textAlignment="center"
android:gravity="center"
android:textColor="#341867"
android:textSize="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/writing_dialog_ok"
android:layout_width="65dp"
android:layout_height="39dp"
android:layout_marginEnd="20dp"
android:background="#00FFFFFF"
android:fontFamily="#font/nexon"
android:text="ok"
android:textColor="#341867"
android:textSize="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/guideline6" />
<Button
android:id="#+id/writing_dialog_cancel"
android:layout_width="65dp"
android:layout_height="39dp"
android:layout_marginEnd="30dp"
android:background="#00FFFFFF"
android:text="cancel"
android:textColor="#341867"
android:textSize="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/writing_dialog_ok"
app:layout_constraintTop_toTopOf="#+id/guideline6" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="355dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/writing_dialog_recy"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="20dp"
app:layout_constraintBottom_toTopOf="#+id/guideline6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView8" />
</androidx.constraintlayout.widget.ConstraintLayout>
recyclerview cell
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/dialog_container"
android:layout_width="match_parent"
android:layout_height="45dp">
<RadioButton
android:id="#+id/dialog_radio"
android:layout_width="0dp"
android:layout_height="45dp"
android:fontFamily="#font/nexon"
android:text="시리즈 1"
android:textSize="18dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
recycler view adapter
public class WritingNovelAdapter extends RecyclerView.Adapter<WritingNovelAdapter.Holder>{
private Context context;
private ArrayList<WritingNovel_data> dataList;
public WritingNovelAdapter(Context context, ArrayList<WritingNovel_data> dataList){
this.context = context;
this.dataList = dataList;
}
public static class Holder extends RecyclerView.ViewHolder{
protected ConstraintLayout dialog_container;
protected RadioButton dialog_radio;
public Holder(View view){
super(view);
this.dialog_container = view.findViewById(R.id.dialog_container);
this.dialog_radio = view.findViewById(R.id.dialog_radio);
}
}
#Override
public WritingNovelAdapter.Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.writing_dialog_cell, parent, false);
Holder holder = new WritingNovelAdapter.Holder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull WritingNovelAdapter.Holder holder, final int position) {
String title = dataList.get(position).title;
if(title.length() > 16){
title = title.substring(0, 15) + "…";
}
holder.dialog_radio.setText(title);
holder.dialog_container.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
//????????????????????????????
}
});
}
#Override
public int getItemCount() {
if(dataList == null){
return 0;
}
else{
return dataList.size();
}
}
}
custom dialog class
class CustomDialog {
private Context context;
public CustomDialog(Context context)
{
this.context = context;
}
public void callDialog()
{
final Dialog dialog = new Dialog(context);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.writing_novel_series_dialog);
dialog.show();
final RecyclerView writing_dialog_recy = dialog.findViewById(R.id.writing_dialog_recy);
final Button writing_dialog_ok = dialog.findViewById(R.id.writing_dialog_ok);
final Button writing_dialog_cancel = dialog.findViewById(R.id.writing_dialog_cancel);
writing_dialog_ok.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
writing_dialog_cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
}
====EDIT-1====
I call my dialog in here!
public class writing_novel extends AppCompatActivity {
private static final int GALLERY_REQUEST = 979;
private RichEditor mEditor;
private ColorPicker colorPicker;
androidx.appcompat.app.AlertDialog.Builder textSizeDialogBuilder;
private NumberPicker textPicker;
androidx.appcompat.app.AlertDialog.Builder youtubeDialogBuilder;
private EditText etYoutubeUrl;
private Button writing_novel_btn_series;
private ImageButton writing_novel_novel_ibtn_next;
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:{
finish();
return true;
}
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_writing_novel);
Toolbar toolbar = findViewById(R.id.writing_novel_main_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
writing_novel_novel_ibtn_next = findViewById(R.id.writing_novel_novel_ibtn_next);
writing_novel_novel_ibtn_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(writing_novel.this);
builder.setTitle("정말 다음으로 넘어가시겠습니까?").setMessage("다음으로 넘어가기전, 한번 더 검토해주세요.");
builder.setPositiveButton("넘어가기", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int id)
{
Toast.makeText(getApplicationContext(), "OK Click", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(writing_novel.this, decide_novel_title.class);
startActivity(intent);
}
});
builder.setNegativeButton("취소", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int id)
{
Toast.makeText(getApplicationContext(), "Cancel Click", Toast.LENGTH_SHORT).show();
dialog.dismiss();
}
});
builder.setCancelable(false);
builder.create().show();
}
});
writing_novel_btn_series = findViewById(R.id.writing_novel_btn_series);
writing_novel_btn_series.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Bundle args = new Bundle();
args.putString("id", "");
DialogFragment dialogFragment = new DialogFragment();
dialogFragment.setArguments(args);
dialogFragment.show(getFragmentManager(), "id");
CustomDialog dialog = new CustomDialog(writing_novel.this);
dialog.show(getSupportFragmentManager(), "CustomDialog");
}
});
If I understand correctly, you are trying to figure out how to display the RecyclerView list of items, and when an item is clicked, show its data in a TextView below. Please correct me if I am wrong.
For the first step, you are close. All you need to do is instantiate a new layout manager and an instance of your adapter class, and pass them to your RecyclerView.
Add this to your CustomDialog class:
public void callDialog() {
...
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(context);
writing_dialog_recy.setLayoutManager(layoutManager);
// I'm assumming you are passing a list of data here
WritingNovelAdapter adapter = new WritingNovelAdapter(context, dataList);
writing_dialog_recy.setAdapter(adapter);
...
As for showing the text in the textView, you have a few different ways to implement this. Its hard to say without seeing the rest of the related code, but I would recommend implementing a callback interface and calling the method from your ViewHolder, like so:
Define the interface in your Adapter class
public interface CallbackInterface {
void showText(String text);
}
Implement a callback interface in your CustomDialog class and implement the setText method, which is where you will set the text in the TextView. This will require that you have an instance of the TextView that you want to show that text in, meaning you must call this somewhere: TextView textView = findViewById(R.id.textView8);
class CustomDialog implements CallbackInterface {
...
public void showText(String text) {
textView.setText(text);
}
}
Pass an instance of your CustomDialog to the adapter (make sure to redefine adapter constructor to accept an instance of CustomDialog
public void callDialog() {
...
// I'm assumming you are passing a list of data here
WritingNovelAdapter adapter = new WritingNovelAdapter(context, dataList, this);
writing_dialog_recy.setAdapter(adapter);
...
}
Call the callback method from the adapter class when the recyclerview cell is clicked
public class WritingNovelAdapter extends RecyclerView.Adapter<WritingNovelAdapter.Holder> {
private Context context;
private ArrayList<WritingNovel_data> dataList;
private CallbackInterface callbackInterface;
public WritingNovelAdapter(Context context, ArrayList<WritingNovel_data>
dataList, CallbackInterface callbackInterface){
this.context = context;
this.dataList = dataList;
this.callbackInterface = callbackInterface;
}
...
holder.dialog_container.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
callbackInterface.showText(title);
}
});
}
Edit #1
Your comment stated that your dialog is not showing up. Unless you left some code out of your CustomDialog class, this is because all your CustomDialog class is, is a Java class. You need to extend a superclass such as AlertDialog or DialogFragment. I'll do my best to summarize how to do this, but you should take a look at the android docs -> https://developer.android.com/guide/topics/ui/dialogs
Here is an example of a DialogFragment you could try creating:
public class CustomDialog extends DialogFragment implements CallbackInterface {
private Context context;
private TextView textView;
private RecyclerView writing_dialog_recy;
public CustomDialog(Context context) {
this.context = context;
}
/* This is the method which builds and essentially shows the dialog */
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
LayoutInflater inflater = getActivity().getLayoutInflater();
// Inflate your view that contains the recyclerview
View view = inflater.inflate(R.layout.custom_dialog);
// Your text view where you want to show the text after an item is clicked
textView = view.findViewById(R.id.textView8);
// Your recyclerview in your custom_dialog.xml
writing_dialog_recy = view.findViewById(R.id.writing_dialog_recy);
// Create the layout manager
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(context);
writing_dialog_recy.setLayoutManager(layoutManager);
// Create and set the adapter
WritingNovelAdapter adapter = new WritingNovelAdapter(context, dataList, this);
writing_dialog_recy.setAdapter(adapter);
builder.setView(view);
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// do whatever you want when user clicks the positive button
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
return builder.create(); // return the dialog builder
}
public void showText(String text) {
textView.setText(text);
}
}
Then in whatever activity you are creating this dialog from, you show the DialogFragment and pass it the activity's FragmentManager and a tag
CustomDialog dialog = new CustomDialog(this);
dialog.show(getSupportFragmentManager(), "CustomDialog");
I am trying to create a Dialog Box from an Non activity Class.
This is my Code
public static void ShowDialogBox(final Context con, final Listener list) {
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(con);
dlgAlert.setMessage("TEXT");
dlgAlert.setTitle("TEXT");
dlgAlert.setPositiveButton("TEXT"),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
dlgAlert.setCancelable(false);
dlgAlert.create().show(); // THIS LINE GIVES ME AN ERROR
}
This is the error which I am getting
android.view.WindowManager$BadTokenException: at
android.view.ViewRootImpl.setView (ViewRootImpl.java:574) at
android.view.WindowManagerGlobal.addView
(WindowManagerGlobal.java:282) at
android.view.WindowManagerImpl.addView (WindowManagerImpl.java:85)
at android.app.Dialog.show (Dialog.java:298) at
PACKAGE NAME AND CLASS
PACKAGE NAME AND CLASS at
PACKAGE NAME AND CLASS
PACKAGE NAME AND CLASS at
PACKAGE NAME AND CLASS.onBackPressed
(Class.java:95) at android.app.Activity.onKeyUp
(Activity.java:2465) at android.view.KeyEvent.dispatch
(KeyEvent.java:2646) at android.app.Activity.dispatchKeyEvent
(Activity.java:2716) at
android.support.v7.internal.view.WindowCallbackWrapper.dispatchKeyEvent
(WindowCallbackWrapper.java:50) at
android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent
(AppCompatDelegateImplBase.java:224) at
com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent
(PhoneWindow.java:2280) at
android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent
(ViewRootImpl.java:4038) at
android.view.ViewRootImpl$ViewPostImeInputStage.onProcess
(ViewRootImpl.java:4000) at
android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.onDeliverToNext
(ViewRootImpl.java:3615) at
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
at android.view.ViewRootImpl$AsyncInputStage.forward
(ViewRootImpl.java:3698) at
android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589)
at android.view.ViewRootImpl$AsyncInputStage.apply
(ViewRootImpl.java:3755) at
android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.onDeliverToNext
(ViewRootImpl.java:3615) at
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589)
at android.view.ViewRootImpl$InputStage.deliver
(ViewRootImpl.java:3562) at
android.view.ViewRootImpl$InputStage.onDeliverToNext
(ViewRootImpl.java:3615) at
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
at android.view.ViewRootImpl$AsyncInputStage.forward
(ViewRootImpl.java:3731) at
android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent
(ViewRootImpl.java:3892) at
android.view.inputmethod.InputMethodManager$PendingEvent.run
(InputMethodManager.java:2208) at
android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback
(InputMethodManager.java:1849) at
android.view.inputmethod.InputMethodManager.finishedInputEvent
(InputMethodManager.java:1840) at
android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished
(InputMethodManager.java:2185) at
android.view.InputEventSender.dispatchInputEventFinished
(InputEventSender.java:141) at
android.os.MessageQueue.nativePollOnce (Native Method) at
android.os.MessageQueue.next (MessageQueue.java:143) at
android.os.Looper.loop (Looper.java:122) at
android.app.ActivityThread.main (ActivityThread.java:5254) at
java.lang.reflect.Method.invoke (Native Method) at
java.lang.reflect.Method.invoke (Method.java:372) at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
(ZygoteInit.java:902) at com.android.internal.os.ZygoteInit.main
(ZygoteInit.java:697)
Here is the scenario of the user
Activity A -->Opens Activity B-->User presses Back button in Activity B--> On Back button pressed a listener is sent to Activity A --> And then the Dialog Box shown is called.
The issue you are having with the attempt to build your AlertDialog in a separate class is you are passing the AlertDialog the Context of your Activity. You get the error because the AlertDialog requires the WindowManager from the Activity which has the layout--not the Context. This is because Activit extends Context... not the other way around.
In order to make your code work you need to provide the AlertDialog.Builder access to the Activity. So change your code to something like this:
public class TestDialog {
private static final String TAG = TestDialog.class.getSimpleName();
Activity mActivity;
public TestDialog(Activity activity){
mActivity = activity;
}
public void showDialog(){
AlertDialog.Builder b = new AlertDialog.Builder(mActivity);
b.setTitle("Title");
b.setMessage("message");
b.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Log.e(TAG, "showDialog : onClick");
}
});
b.create().show();
}
}
Now you can call the AlertDialog from an Activity lets say in this case MainActivity like this:
TestDialog testDialog = new TestDialog(MainActivity.this);
testDialog.showDialog();
I have not tried this from a Fragment, so I do not know whether this works from a Fragment or whether you will continue to have issues with certain devices. For those reasons, I (and Google!) still strongly suggest that you use the DialogFragment instead, because is has been especially designed for this scenario. Take a look at the Google Docs.:
https://developer.android.com/guide/topics/ui/dialogs
I generally prefer using DialogFragment instead of what you attempted in order to cut down on repetition. Here is an example of a DialogFragment with a custom layout which I have called R.layout.fragment_alert_dialog:
public class AlertDialogFragment extends DialogFragment {
private static final String ARG_TITLE = "title";
private static final String ARG_MESSAGE = "message";
private String title;
private String message;
boolean endSuccess = false;
private AlertFinishedDialogListener mListener;
public AlertDialogFragment() {
}
public static AlertDialogFragment newInstance(String title, String message) {
AlertDialogFragment fragment = new AlertDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
args.putString(ARG_MESSAGE, message);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
title = getArguments().getString(ARG_TITLE);
message = getArguments().getString(ARG_MESSAGE);
}
}
#Override
public Dialog onCreateDialog(Bundle saveIntsanceState){
final Context context = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View rootView = inflater.inflate(R.layout.fragment_alert_dialog, null, false);
final TextView titleView = (TextView)rootView.findViewById(R.id.tvTitle);
final TextView messView = (TextView)rootView.findViewById(R.id.tvMessage);
titleView.setText(title);
messView.setText(message);
builder.setView(rootView)
// .setTitle(title)
.setPositiveButton(R.string.ok_button_dialog_title, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
endSuccess = true;
if(mListener == null) mListener = (AlertFinishedDialogListener) context;
mListener.onAlertFinishedDialog();
}
});
return builder.create();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
if(mListener == null) mListener = (AlertFinishedDialogListener) context;
}
catch (Exception ex){
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface AlertFinishedDialogListener {
void onAlertFinishedDialog();
}
}
It incorporates a Listener just in case you need to be notified when the DialogFragment is completed.
First you need to implement the callback:
implements AlertDialogFragment.AlertFinishedDialogListener{
In order to call the AlertDialogFragment you do this from your Activity (also Fragment if necessary).
private void startAlertDialogFragment(String title, String mess){
AlertDialogFragment alert = AlertDialogFragment.newInstance(title, mess);
alert.show(getFragmentManager(), "alertDialogFragment132");
}
#Override
public void onAlertFinishedDialog() {
Log.e(TAG, "onAlertFinishedDialog");
}
Problem
You can show dialogs from activity context only. except TYPE_SYSTEM_ALERT or TYPE_APPLICATION_OVERLAY, which is not recommended if your app does not show emergency notifications to user.
Solution
If you have activity context available then you can show dialog from any class like service, broadcast receiver, or even any class you imagine.
Here is my workaround that can show dialog from any class like i said.
Here is a snippet what i do to show dialog from any class. (Could it
be more simpler!)
import android.app.Dialog;
import android.content.DialogInterface;
public class SampleClass {
void anyMethod() {
Dialog dialog = ApplicationContext.getInstance().showDialog("title", "yourMessage", "Cancel", "Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO: handle button 1 clicked
}
}, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO: handle button 2 clicked
}
});
}
}
Now you will implement to make this work.
1. make application class which you will register in android manifest application tag
<application
android:name=".ApplicationContext"
...
>
...
</application>
2. In this application class you will hold live activity object. that will further useful for showing dialog.
ApplicationContext.java
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Application;
import android.content.DialogInterface;
public class ApplicationContext extends Application {
private static ApplicationContext mInstance;
private Activity liveActivity;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
#Override
public void onTerminate() {
super.onTerminate();
mInstance = null;
}
public static synchronized ApplicationContext getInstance() {
return mInstance;
}
public Activity getLiveActivity() {
return liveActivity;
}
public void setLiveActivity(Activity liveActivity) {
this.liveActivity = liveActivity;
}
/*
* Show Dialog with Title, Message, Button1, Button2 with Button1 and Button2 Listener
*/
public AlertDialog showDialog(String title, String msg,
String btn1, String btn2,
DialogInterface.OnClickListener listener1,
DialogInterface.OnClickListener listener2) {
if (liveActivity == null) return null;
AlertDialog.Builder builder = new AlertDialog.Builder(liveActivity)
.setTitle(title)
.setMessage(msg)
.setCancelable(false)
.setPositiveButton(btn1, listener1);
if (btn2 != null)
builder.setNegativeButton(btn2, listener2);
AlertDialog alert = builder.create();
alert.show();
return alert;
}
}
Just one more step
3. You will extend all your activity by this base activity class (You can edit your base activity if you already have one.)
import android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
#Override
protected void onResume() {
super.onResume();
ApplicationContext.getInstance().setLiveActivity(this);
}
#Override
protected void onPause() {
super.onPause();
ApplicationContext.getInstance().setLiveActivity(null);
}
}
Here you go !!!
I'm trying to use the .setText within a java class to try to change the value of a TextView on the activity_main XML file, so far i'm getting the NullpointerExeption error and I've read that its due an error when declaring my variable. How can i achieve this? Do i need to declare it first at the mainActivity.java?
On my activity_main.xml i have a button -> it opens a custom listView -> if you press the 2 item on the list view -> it opens a custom alert dialog -> the custom alert dialog it contains 2 buttons -> if you press the second button -> it has to set the text of a TextView that is on activity_main.xml
Any help is appreciated!
MainActivity.java
final TextView KMLabel = (TextView)findViewById(R.id.KMlabel);
activity.main.xml
<TextView
android:id="#+id/KMlabel"
android:layout_alignBottom="#+id/TVKm"
android:layout_toRightOf="#+id/TVKm"
android:textSize="22sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#e6c009"
android:text="KM/H"
android:textStyle="italic"/>
custom.java
public class custom extends BaseAdapter{
Context context;
String Item[];
String SubItem[];
int flags[];
LayoutInflater inflter;
public custom(Context applicationContext, String[] Item, String[] SubItem , int[] flags) {
this.context = context;
this.Item = Item;
this.SubItem = SubItem;
this.flags = flags;
inflter = (LayoutInflater.from(applicationContext));
}
#Override
public int getCount() {
return Item.length;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = inflter.inflate(R.layout.activity_items, null);
//TextView Prueba = (TextView)view.findViewById(R.id.KMlabel);
TextView item = (TextView) view.findViewById(R.id.item);
TextView subitem = (TextView) view.findViewById(R.id.subitem);
ImageView image = (ImageView) view.findViewById(R.id.image);
item.setText(Item[i]);
subitem.setText(SubItem[i]);
image.setImageResource(flags[i]);
return view;
}
viewdialog.java
public class ViewDialog {
public void showDialog(Activity activity, String msg){
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(false);
dialog.setContentView(R.layout.custom_dialog);
//I'm declaring it like this
final TextView KMLabel = (TextView)activity.findViewById(R.id.KMlabel);
Button dialogButton = (Button) dialog.findViewById(R.id.btn_dialog);
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
Button KmPerHr = (Button)dialog.findViewById(R.id.KmPerH);
KmPerHr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//and calling it this way:
KMLabel.setText("MLL/H");
}
});
dialog.show();
}
}
LOGCAT:
FATAL EXCEPTION: main
Process: com.example.dell.getspeed, PID: 3925
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.example.dell.getspeed.ViewDialog$2.onClick(ViewDialog.java:38)
at android.view.View.performClick(View.java:5721)
at android.widget.TextView.performClick(TextView.java:10936)
at android.view.View$PerformClick.run(View.java:22620)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7406)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
You have to move your code
Button KmPerHr = (Button)dialog.findViewById(R.id.KmPerH);
KmPerHr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//and calling it this way:
KMLabel.setText("MLL/H");
}
});
final TextView KMLabel = (TextView)dialog.findViewById(R.id.KMlabel);
Button dialogButton = (Button) dialog.findViewById(R.id.btn_dialog);
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
below the dialog.show() code because code findViewById only work after you pop up dialog.
Create a Global class which extends to application class, then create a texview in Global
Textview t = null;
Then create two static methods to set and get this textview
Public static void setT(TextView p){
t = p;
}
And get it from
Public static TextView getT(){
return t;
}
Set TextView in your activity ,then access this textview from wherever you want until your activity is alive.
Try the code below:
MainActivity class:-------
public class MainActivity extends AppCompatActivity {
private TextView KMlabel;
private Button b;
private ViewDialog vd;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo2);
vd = new ViewDialog();
KMlabel = (TextView) findViewById(R.id.KMlabel);
b = (Button) findViewById(R.id.b);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
vd.showDialog(MainActivity.this , KMlabel , "Your Message" , "Your Text");
}
});
}
}
ViewDialog class:------
public class ViewDialog {
public void showDialog(Context context, final TextView v , String msg , final String text) {
createYesNoInfoDialog(context, msg, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
}, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
v.setText(text);
}
}).show();
}
private AlertDialog createYesNoInfoDialog(Context finalContext, String message,
DialogInterface.OnClickListener onNoListener, DialogInterface.OnClickListener onYesListener) {
AlertDialog a = new AlertDialog.Builder(finalContext).setTitle(
message)
.setNegativeButton("No", onNoListener)
.setPositiveButton("Yes", onYesListener).create();
return a;
}
}
demo2.xml:-----
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="xcxc"
android:id="#+id/KMlabel"/>
<Button
android:layout_width="match_parent"
android:text="Create Dialog"
android:layout_height="wrap_content"
android:id="#+id/b"/>
</LinearLayout>
R.id.KMlabel is on activity_main.xml so you have to initialize the TextView from MainActivity reference.
final TextView KMLabel = (TextView)activity.findViewById(R.id.KMlabel);
Edit:
You can use callback pattern for this:
ViewDialog:
public class ViewDialog {
// interface for callback
public interface OnSelectListener {
public void onOkSelect();
}
OnSelectListener mOnSelectListener;
public void showDialog(Activity activity, String msg, OnSelectListener mListener){
mOnSelectListener = mListener;
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(false);
dialog.setContentView(R.layout.custom_dialog);
//I'm declaring it like this
final TextView KMLabel = (TextView)activity.findViewById(R.id.KMlabel);
Button dialogButton = (Button) dialog.findViewById(R.id.btn_dialog);
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
Button KmPerHr = (Button)dialog.findViewById(R.id.KmPerH);
KmPerHr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//pass to the implementation if not null
if( mOnSelectListener != null){
mOnSelectListener.onOkSelect();
}
}
});
dialog.show();
}
}
In MainActivity:
// initialize interface
ViewDialog.OnSelectListener mOnSelectListener = new ViewDialog.OnSelectListener(){
public void onOkSelect(){
KMLabel.setText("MLL/H");
}
};
ViewDialog viewDialog = new ViewDialog();
viewDialog.showDialog(this, "Message", mOnSelectListener);
This happens since you are trying to call the TextView within the custom alert dialog. TextView only belongs to the MainActivity. You can call or change that only within the MainActivity class. So please try this below.
MainActivity.class
public class MainActivity extends AppCompatActivity {
private TextView KMlabel;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
KMlabel = (TextView) findViewById(R.id.KMlabel);
}
public void setTextKM(String string){
KMlabel.setText(string);
}
}
ViewDialog class
public class ViewDialog {
public void showDialog(Activity activity, String msg){
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(false);
dialog.setContentView(R.layout.custom_dialog);
Button dialogButton = (Button) dialog.findViewById(R.id.btn_dialog);
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
Button KmPerHr = (Button)dialog.findViewById(R.id.KmPerH);
KmPerHr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MainActivity mainActivity = new MainActivity();
mainActivity.setTextKM("MLL/H");
}
});
dialog.show();
}
}
I've looked at a lot of similar questions and can't seem to get anything to work. I have a main class with a function like this that edits shows a dialog box then edits a List when a button is pressed.
public class EditPlayers extends SherlockFragmentActivity {
listPlayerNames.setAdapter(new EditPlayerAdapter(ctx,
R.layout.score_row_edit_player, listScoreEdit));
public void deletePlayer(final int position) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(
EditPlayers.this);
// Setting Dialog Title
alertDialog.setTitle("Delete Player");
// Setting Dialog Message
alertDialog.setMessage("Are you sure?");
// Setting Delete Button
alertDialog.setPositiveButton("Delete",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
listScoreEdit.remove(position);
updateListView();
}
});
// Setting Cancel Button
alertDialog.setNeutralButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
}
How do I access that function from the getView() in the adapter? Here's the XML for the row
<TextView
android:id="#+id/nameEdit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:layout_weight="70"
android:text="Name"
android:textColor="#666666"
android:textSize="22sp"
android:textStyle="bold" >
</TextView>
<Button
android:id="#+id/deletePlayer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="30"
android:text="Delete"
android:focusable="false" />
Here's the getView()
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
convertView = (LinearLayout) inflater.inflate(resource, null);
Score score = getItem(position);
TextView txtName = (TextView) convertView.findViewById(R.id.nameEdit);
txtName.setText(score.getName());
Button b = (Button)convertView.findViewById(R.id.deletePlayer);
b.setTag(position);
b.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//call function here
}
});
return convertView;
}
I'm totally lost at this point so any help would be appreciated. Thanks!
I would recommend providing an interface back to your activity that lets it know when that button is pressed. I would not recommend calling an activity's method from an ArrayAdapter. It is too tightly coupled.
Try something like this:
Your Activity
public class EditPlayers extends SherlockFragmentActivity implements EditPlayerAdapterCallback {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EditPlayerAdapter adapter = new EditPlayerAdapter(this,
R.layout.score_row_edit_player, listScoreEdit);
adapter.setCallback(this);
listPlayerNames.setAdapter(adapter);
}
private void deletePlayer(final int position) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(
EditPlayers.this);
// Setting Dialog Title
alertDialog.setTitle("Delete Player");
// Setting Dialog Message
alertDialog.setMessage("Are you sure?");
// Setting Delete Button
alertDialog.setPositiveButton("Delete",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
listScoreEdit.remove(position);
updateListView();
}
});
// Setting Cancel Button
alertDialog.setNeutralButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
#Override
public void deletePressed(int position) {
deletePlayer(position);
}
}
Adapter:
public class EditPlayerAdapter extends ArrayAdapter {
private EditPlayerAdapterCallback callback;
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
convertView = (LinearLayout) inflater.inflate(resource, null);
Score score = getItem(position);
TextView txtName = (TextView) convertView.findViewById(R.id.nameEdit);
txtName.setText(score.getName());
Button b = (Button)convertView.findViewById(R.id.deletePlayer);
b.setTag(position);
b.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(callback != null) {
callback.deletePressed(position);
}
}
});
return convertView;
}
public void setCallback(EditPlayerAdapterCallback callback){
this.callback = callback;
}
public interface EditPlayerAdapterCallback {
public void deletePressed(int position);
}
}
Your EditPlayerAdapter gets a Context passed to it. Activity extends Context
If the Context passed is your EditPlayers and you store a class-scoped reference to that Context in your Adapter, you can then do:
((EditPlayers) yourContextVar).function();
Better yet, make an interface of some sort. It will help clarify and organise your code and it applies the same principle.